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

使用C结构体时strcat触发Segmentation Fault的问题排查

问题:无<stdio.h>依赖实现读取文件前10个单词时的段错误问题

本人是C语言和Unix新手,正尝试实现一个不依赖<stdio.h>库、仅通过系统调用打印文件前10个单词的函数。目前采用逐字符读取方式,希望将非空格字符拼接至结构体变量中,但调用strcat()时触发Segmentation Fault(段错误),询问是否需要以其他方式分配字符串/结构体。

相关代码如下:

struct word{
    char *content;
    int length;
};

void openRead(){
    char curChar;
    //open file
    int infile = open("sample.txt", O_RDONLY);
    // set count
    int count = 10;
    //create array of words
    struct word words[count];
    struct word firstWord;
    firstWord.length = 0;
    firstWord.content = "test\0";
    words[0] = firstWord;
    
    int totalLen = lseek(infile, 0, SEEK_END);
    lseek(infile, 0, SEEK_SET);
    int i = 0;
    int curCount = 1;
    //-1 due to terminating character
    while (curCount < count && i < totalLen-1){
        // read next character
        int p= lseek(infile, i, SEEK_SET);
        read(infile, &curChar, 1);
        int spaceCheck = isspace(curChar);
        
        // if regular character add to word
        if(spaceCheck == 0){
            struct word curWord = words[curCount];
            curWord.length = curWord.length + 1;
            
            // conver character to string for string concatenation
            char cToStr[2];
            cToStr[1] = '\0';
            cToStr[0] = curChar;

            strcat(curWord.content, cToStr); // segmentation fault
            words[curCount] = curWord;
        } else { // create new word
            struct word newWord;
            newWord.length = 1;
            newWord.content = &curChar;
            words[curCount] =  newWord;
        }
        i++;
    }
    close(infile);
}

int main()
{
    openRead();
}

问题分析与解决

段错误的核心原因是非法内存访问,你的代码存在以下几个关键问题:

  • 字符串常量不可修改:firstWord.content = "test\0"; 中的"test"是只读字符串常量,存储在程序的只读数据段,strcat尝试修改它会直接触发段错误。
  • 结构体数组未初始化:struct word words[count]; 中除words[0]外的元素都未初始化,words[curCount]的content是野指针,访问必然出错。
  • 栈变量指针无效:newWord.content = &curChar; 中curChar是栈上的局部变量,循环迭代会覆盖它,函数结束后地址直接失效,无法存储单词内容。
  • 冗余的lseek调用:read会自动推进文件指针,每次循环用lseek定位到i的位置会导致重复读取字符。

修正思路

  1. 用malloc/realloc给每个单词的content动态分配可修改的内存。
  2. 初始化结构体数组的所有元素,避免野指针。
  3. 去掉冗余的lseek,直接通过read逐字符推进文件指针。
  4. 处理连续空格的情况,避免生成空单词。

修正后的代码示例

#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

struct word{
    char *content;
    int length;
};

void openRead(){
    char curChar;
    int infile = open("sample.txt", O_RDONLY);
    if (infile == -1) {
        return;
    }

    const int max_words = 10;
    struct word words[max_words];
    // 初始化所有单词结构体
    for (int i = 0; i < max_words; i++) {
        words[i].content = NULL;
        words[i].length = 0;
    }

    int cur_word_idx = 0;
    // 逐字符读取,读到文件结束即停止
    while (cur_word_idx < max_words && read(infile, &curChar, 1) == 1) {
        if (!isspace(curChar)) {
            struct word *cur_word = &words[cur_word_idx];
            // 重新分配内存:原长度+1(当前字符)+1(终止符)
            char *new_content = realloc(cur_word->content, cur_word->length + 2);
            if (!new_content) {
                // 内存分配失败,清理已分配的内存
                for (int i = 0; i <= cur_word_idx; i++) {
                    free(words[i].content);
                }
                close(infile);
                return;
            }
            cur_word->content = new_content;
            cur_word->content[cur_word->length] = curChar;
            cur_word->length++;
            cur_word->content[cur_word->length] = '\0'; // 确保字符串终止
        } else {
            // 遇到空格且当前单词有内容时,切换到下一个单词
            if (cur_word_idx < max_words - 1 && words[cur_word_idx].length > 0) {
                cur_word_idx++;
            }
            // 连续空格直接跳过,不生成空单词
        }
    }

    // 用系统调用write打印结果,不依赖<stdio.h>
    for (int i = 0; i < max_words && words[i].content; i++) {
        write(STDOUT_FILENO, words[i].content, words[i].length);
        write(STDOUT_FILENO, "\n", 1);
        free(words[i].content); // 释放动态分配的内存
    }

    close(infile);
}

int main()
{
    openRead();
    return 0;
}

关键说明

  • 用realloc动态调整内存大小,确保每个单词有足够空间存储字符。
  • 初始化结构体数组所有元素,彻底避免野指针问题。
  • 去掉冗余的lseek,通过read的返回值判断是否读到文件末尾。
  • 处理连续空格,不会生成空单词。
  • 使用write系统调用完成打印,完全不依赖<stdio.h>。
  • 添加了基础错误处理,避免程序因文件打开失败、内存分配失败崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 18:42:40