You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言文本编辑器运行触发Segmentation Fault错误原因排查

C语言文本编辑器执行触发Segmentation Fault的成因分析

问题现象

编译无报错,但执行时无论是创建新文件还是打开现有.txt文件,终端均报错:

./a.out
Enter the filename: hello
Enter the start line number: 1
Enter the end line number: 9
Segmentation fault (core dumped)

触发错误的代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LINE_LENGTH 1024

void edit_lines(char* buffer, int start_line, int end_line) {
    char* start = buffer;

    // Move the start pointer to the start_line position
    for (int i = 0; i < start_line - 1; i++) {
        start = strchr(start, '\n');
        if (start == NULL) {
            printf("Error: Invalid line number\n");
            return;
        }
        start++;
    }

    char* end = start;

    // Move the end pointer to the end_line position
    for (int i = start_line; i < end_line; i++) {
        end = strchr(end, '\n');
        if (end == NULL) {
            printf("Error: Invalid line number\n");
            return;
        }
        end++;
    }

    char* line_end = strchr(end, '\n');
    if (line_end) {
        *line_end = '\0'; 

        char saved[MAX_LINE_LENGTH] = {0};
        strncpy(saved, line_end + 1, sizeof(saved) - 1); 
        saved[sizeof(saved) - 1] = '\0'; 

        char new_lines[MAX_LINE_LENGTH];
        printf("Enter the new lines (press Enter twice to finish):\n");
        fgets(new_lines, sizeof(new_lines), stdin);
        char* nl_pos = strchr(new_lines, '\n');
        while (nl_pos) {
            *nl_pos = '\0';
            strcat(start, new_lines);
            strcat(start, "\n");
            fgets(new_lines, sizeof(new_lines), stdin);
            nl_pos = strchr(new_lines, '\n');
        }
        strcat(start, saved);
    } else {
        printf("Error: Invalid line number\n");
    }
}

int main(int argc, char** argv) {
    char* buffer = NULL;
    FILE* f;
    char filename[1024] = {0};

    if (argc < 2) {
        // Create a new file
        printf("Enter the filename: ");
        fgets(filename, sizeof(filename), stdin);
        filename[strcspn(filename, "\n")] = '\0'; 

        f = fopen(filename, "w");
        if (!f) {
            printf("Error creating file %s\n", filename);
            return 1;
        }
    } else {
        // Open an existing file
        f = fopen(argv[1], "r");
        if (!f) {
            printf("Error opening file %s\n", argv[1]);
            return 1;
        }

        // Get the size of the file
        if (fseek(f, 0, SEEK_END) != 0) {
            printf("Error seeking end of file %s\n", argv[1]);
            fclose(f);
            return 1;
        }
        long file_size = ftell(f);
        rewind(f);

        // Allocate memory for the buffer
        buffer = (char*)malloc(file_size + 1);
        if (buffer == NULL) {
            printf("Error allocating memory\n");
            fclose(f);
            return 1;
        }

        // Read the file contents into the buffer
        if (fread(buffer, 1, file_size, f) != file_size) {
            printf("Error reading file %s\n", argv[1]);
            free(buffer);
            fclose(f);
            return 1;
        }
        buffer[file_size] = '\0'; 

        fclose(f);
    }

    int start_line = 0, end_line = 0;
    printf("Enter the start line number: ");
    scanf("%d", &start_line);
    printf("Enter the end line number: ");
    scanf("%d", &end_line);

    edit_lines(buffer, start_line, end_line);

    f = fopen(argc < 2 ? filename : argv[1], "w");
    if (!f) {
        printf("Error opening file %s for writing\n", argc < 2 ? filename : argv[1]);
        free(buffer);
        return 1;
    }

    if (fwrite(buffer, strlen(buffer), 1, f) != 1) {
        printf("Error writing to file %s\n", argc < 2 ? filename : argv[1]);
        free(buffer);
        fclose(f);
        return 1;
    }

    free(buffer);
    fclose(f);
    return 0;
}

错误成因分析

  • 新文件场景下buffer为空指针:当通过交互创建新文件时(argc<2分支),代码仅创建文件,但buffer始终保持NULL状态。调用edit_lines(buffer, ...)时,函数直接对NULL指针执行strchr操作,直接触发段错误。
  • 内存越界写入:即使是打开已有文件的场景,malloc分配的内存仅为原文件尺寸+1。后续用strcat往buffer追加新内容时,未检查内存是否足够,新内容超出分配的内存范围会破坏堆结构,最终触发段错误。
  • 输入缓冲区残留换行符:scanf读取行号后,输入缓冲区会残留换行符,后续fgets会直接读到空行,引发逻辑异常,间接增加出错概率。
  • 无效行号处理不彻底:当用户输入的end_line超过文件实际行数时,strchr返回NULL,函数打印错误后返回,但主函数后续依然会对buffer执行写入操作,若此时buffer状态异常(比如新文件场景下还是NULL),就会触发段错误。

内容的提问来源于stack exchange,提问作者Karma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:24:53