【问题标题】:Trying to load text file into an array, getting a seg fault. Any ideas why?尝试将文本文件加载到数组中,出现段错误。任何想法为什么?
【发布时间】:2012-10-11 06:42:51
【问题描述】:

这个函数的任务相当简单。给定一个 char* 数组、一个指向文件的指针和一个最大字长,它会读取文件并将每个字一个接一个地复制到 char* 数组中。由于文件中每行一个单词,因此使用\n 作为单词之间的分隔符是有意义的。所以考虑到这一点,代码应该很容易解释:

void loadDictionary(char* strDictionary[], FILE* filePointer, int nMaxLetters)
{
    int nNameCount= 0, nCursor = 0;
    char* strCurrent;
    char cCurrent;

    //allocate space for a word
    strCurrent = malloc(nMaxLetters * sizeof(char));

    while ((cCurrent = fgetc(filePointer)) != EOF) {

        if(cCurrent != '\n')
        {
            strCurrent[nCursor] = cCurrent;
            nCursor++;

        } else { //then we've reached the end of the line (word)

            //add null termination to string
            strCurrent[nCursor] = '\0'; //SEG FAULT

            //copy string to dictionary
            memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);

            //increment count
            nNameCount++;

            //reset the cursor
            nCursor = 0;
        }
    }
}

此代码在我调用strCurrent[nCursor] = '\0'; 的行处生成分段错误。我不知道为什么,因为从表面上看,这个操作似乎应该与另一个块中的操作没有什么不同,我称之为strCurrent[nCursor] = cCurrent;。 strCurrent 应该分配了足够多的空间来存储所有必要的字符。所以,我有些不知所措。帮我解决这个问题,伙计们。

注意:我认为使用fgets 而不是fgetc 来完成这项任务可能会更轻松。我很可能会转向那个;但是,由于我遇到了一个我不理解的错误,所以我不想在我理解它之前将其搁置。

编辑:

有人指出memcpy操作可能出现错误,可能是strDictionary分配不当所致。这是分配strDictionary 的main 块。也许我犯了一个错误:

int main(int argc, char* argv[])
{
    char** strDictionary;
    FILE* filePointer;
    int nResults = 0, nLines = 0, nNumLines, nMaxChars, i;

    filePointer = fopen("dictionary.txt", "r");

    //obtain the number of lines and the maximum word size of the dictionary
    countLines(filePointer, &nNumLines, &nMaxChars);

    //allocate memory for strDictionary
    strDictionary = malloc(nNumLines * nMaxChars * sizeof(char));
    printf("%d words in dictionary. Longest word is %d letters\n",
            nNumLines, nMaxChars);
    //Output here correctly prints: 1000 and 21

    //reset the file pointer (not sure if this is a necessary step, but oh well)
    filePointer = fopen("dictionary.txt", "r");

    //load dictionary into memory
    loadDictionary(strDictionary, filePointer, nMaxChars);
    for (i=0; i<10; i++)
        printf("%dth element of dictionary: %s\n", i, strDictionary[i]);

    return 0;
}

编辑 2:

好的,我决定使用fgets() 而不是fgetc() 来大大简化我的功能。我还为strDictionary 做了我认为正确的malloc() 操作。但是,我仍然遇到段错误。这是更新的代码:

void loadDictionary(char* strDictionary[], FILE* filePointer, int nMaxLetters)
{
    printf("Call to loadDictionary. nMaxLetters = %d\n", nMaxLetters);
    int nWordCount= 0, nCursor = 0;
    char* strCurrent;
    char cCurrent;

    strCurrent = malloc(nMaxLetters); //allocate space for a word


    while (fgets(strCurrent, nMaxLetters, filePointer) != NULL)
    {
        memcpy(strDictionary[nWordCount], strCurrent, strlen(strCurrent)+1);
        nWordCount++;
    }
}

int main(int argc, char* argv[])
{
    char** strDictionary;
    FILE* filePointer;
    int nResults = 0, nLines = 0, nNumLines, nMaxChars, i;
    filePointer = fopen("dictionary.txt", "r");

    //count the lines in the file (works fine)
    countLines(filePointer, &nNumLines, &nMaxChars);

    //allocate space for the dictionary
    strDictionary = malloc(nNumLines * sizeof(char*));
    for (i = 0; i<nLines; i++)
        strDictionary[i] = malloc(nMaxChars * sizeof(char));
    printf("%d words in dictionary. Longest word is %d letters\n",
            nNumLines, nMaxChars);

    //load dictionary into array
    filePointer = fopen("dictionary.txt", "r");
    loadDictionary(strDictionary, filePointer, nMaxChars);
    for (i=0; i<10; i++)
        printf("%dth element of dictionary: %s\n", i, strDictionary[i]);

    return 0;
}

【问题讨论】:

  • 您可能想在 'nCursor' 出现段错误时检查它的值。 ps 没有必要做 sizeof(char) 它是在 C 中定义的唯一大小
  • 你知道它是否在它读入的第一个单词上吗?最大行有多长,nMaxLetters 有多大?
  • 可能您的代码在包含 nMaxLetters 的行上出现了段错误,而您没有考虑到还包括终止空字符。
  • 我怀疑这可能是它出现段错误的memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1); 行。您是否为strDictionary 的所有元素分配了足够的空间?
  • 我怀疑malloc(nMaxLetters * sizeof(char)); 您没有为空字节终止符分配 +1。

标签: c arrays segmentation-fault


【解决方案1】:

这里:

char cCurrent;
...
while ((cCurrent = fgetc(filePointer)) != EOF) {

您正在将fgetc() 类型为int 的值截断为char。这可能会导致 while 条件无法正确识别 EOF。 cCurrent 必须是 int。

这里:

//allocate space for a word
strCurrent = malloc(nMaxLetters * sizeof(char));

nMaxLetters 必须考虑一个额外的字符来表示字符串 NUL 终止符。算不算?

顺便说一句,sizeof(char) 始终为 1。

现在,这个参数声明:

char* strDictionary[]

等价于:

char** strDictionary

或者,IOW,一个指向char的指针。这是因为在 C 中,数组永远不会作为参数传递,只有指向它们的第一个元素的指针才是,尽管括号中的欺骗性语法暗示某些东西是数组。

这一行:

memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);

将把nNameCount'th 指针指向char 并写入它指向的字符数据。

但是调用函数分配的字符串缓冲区(长度为nMaxLetters)是否至少与文件中的行数一样多?在将这个数组传递给loadDictionary()之前,它是否用指向这些缓冲区的指针填充了一些指向char的指针数组? IOW,这段代码期望调用者做这样的事情:

#define nMaxEntries 1000

char* dictionary[nMaxEntries];
int i;
FILE* f;

...

for (i = 0; i < nMaxEntries; i++)
  dictionary[i] = malloc(nMaxLetters);

loadDictionary(dictionary, f, nMaxLetters);

必须在上述代码中检查内存分配失败。另外,我强烈建议将nMaxEntries 传递给loadDictionary() 或在loadDictionary() 中使用它,这样如果文件的行数多于nMaxEntries,就不会超出指针数组。 nNameCount 不应超过 nMaxEntries。

更新更新的问题...

这里:

char** strDictionary;
...
strDictionary = malloc(nNumLines * nMaxChars * sizeof(char));

您没有像loadDictionary() 根据上述分析所期望的那样创建指向char 的指针数组,而是创建了char 的二维数组。因此,段错误很可能不会发生在这一行:

 strCurrent[nCursor] = '\0'; //SEG FAULT

但在下一个,在您放大并查看代码的反汇编之前,这在调试器中可能并不明显:

 //copy string to dictionary
 memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);

更新 2:

我不明白你为什么现在为nNumLines 指针分配空间:

strDictionary = malloc(nNumLines * sizeof(char*));

但是在那些 nNumLines 指针中,您初始化了 nLines 指针(如果我正确阅读了您的最新代码,nLines 永远不会变成 0 以外的任何值):

for (i = 0; i<nLines; i++)
    strDictionary[i] = malloc(nMaxChars * sizeof(char));

有什么诀窍?错字?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-05
    • 2022-01-23
    • 1970-01-01
    • 2014-07-28
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    相关资源
    最近更新 更多