【问题标题】:C- Segmentation Fault in strlen() for a word list problemC- strlen() 中针对单词列表问题的分段错误
【发布时间】:2019-11-01 01:40:33
【问题描述】:

我尝试创建一个可扩展的最多 20 个字母的单词列表。在添加到列表之前,我使用 'char word[20]' 作为每个新单词的主机。对于长度为 20- 的单词的输入,该程序运行良好。如果我添加一个长度为 20+ 的单词,我的程序应该忽略并继续。

但是在下一次,我在那些 if-else 语句的 strlen(word) 的某个地方得到了 Segmentation Fault。

奇怪的是有时我的程序可以克服这个故障,但在大多数情况下,它会崩溃。

一些尝试: - 如果我使用 'char word[1000]' ,它在任何时候都可以正常工作(到目前为止)。我猜到 strlen() 的参数指针在“继续”之后错误指向某个错误,所以我用 &word[0] 跟踪它并写了 strlen(&word[0]) 并使用 'char word[20]'。这并不能解决问题,并且在发生 Segmentation Fault 时 &word[0] 保持不变。

char *wordList[] = {""};
char word[10];
char * p, c;
int i = -1;
int size = 10;
int strlength = -1;

while(strlength != 0){
    //get word by using loop of getchar() and detect \0
    printf("Enter word :");
    scanf("%s",word);
    printf("Taken word: %s at %p\n",word,&word[0]);

    //detect word length to avoid 4-letter words and words with length 20+
    if (strlen(word) == 0){
        printf("Break due to length 0\n");
        break;
    }else if(strlen(word) > 20){
        printf("Ignore due to length 20+\n");
        continue;
    }
    printf("End checking length");

    //add word to wordList by extending memory for one new word and assign each char to memory
    i++;
    wordList[i] = malloc(sizeof(char)*strlen(word)-1);
    strcpy(wordList[i],word);
    printf("[");
    for(int j = 0; j <= i; j++){
        printf(" %s,",wordList[j]);
    }
    printf("]\n");

【问题讨论】:

  • word中第一个字符&amp;word[0]的地址就是word
  • wordList 只有一个元素。 wordList[i] 具有未定义的行为,只要 i &gt; 0
  • @AviBerger 今晚你和我的想法很相似。 :)
  • 您应该使用%9s 来确保scanf() 的接收量不会超过word 的容量。
  • @DanielFarrell 只是尝试一下。哈哈 。看起来很奇怪吧?大声笑

标签: c segmentation-fault strlen


【解决方案1】:

请记住,在 C 中,字符串只是内存中连续的字符集,以已知地址(char*char[],如果您愿意)开始,以空字节结尾 \0 C 字符串可以天生不知道它们的大小; 程序员有责任确保您不会尝试访问超出分配给您的字符串的内存。当你这样做时,你会得到一个段错误。

scanf("%s",&word[0]);

您告诉scanf 从标准输入读取一个字符串并将其存储在word 中(&amp;word[0] 只是word)。但是您不会告诉scanf 最多读取多少个字符,因此您不会阻止scanf 访问world[20],这是10 个字符串中的一个字符(C 当然是基于0 的偏移量,所以world 中的第一个有效字符是world[0],最后一个是world[19]。)。输入超过 19 个字符(为终止 \0 多留一个),您将超出您的内存分配并且任何事情都可能发生(如果您的程序在该内存地址有有效数据,您将覆盖它。如果数据在那里恰好是一个指针,下次尝试取消引用时,您将覆盖地址和段错误。如果您的程序的内存在那里结束,您将直接发生段错误。

所以你要做的就是告诉scanf 最多读取多少字节。最简单的方法是使用 scanf 的可选“字段宽度说明符”:

scanf("%9s",word)

这告诉scanf 读取一个字符串并将其存储在word 中,但最多只能存储9 个字符(第10 个是终止\0 字符)。

如果我添加一个长度超过 20 的单词,我的程序应该忽略并继续

你的逻辑有一个缺陷 - 你不知道这个词是否有 10 个字符长,直到你从输入中读取 所有字符 并从 @ 中读取 然后 个字符987654340@ 到 '\0' 的第一次出现。在您检查strlen 和可选的continue 之前,您已经通过将第11 个字符写入scanf 内的word[10] 犯了一个错误。请记住,它不能仅从word 知道在该地址分配了多少字节。

单词列表代码也必须修复。

char *wordList[] = {""};`
...
//add word to wordList by extending memory for one new word and assign each char to memory

嗯,wordList[] 正好是一个char* 长,而那个字符串是"",你定义的空字符串是未指定长度[] 的静态定义列表的唯一内容,其大小在编译时确定是时候成为 1。相反,您应该像为 word 所做的那样定义静态列表。

char* wordList[20];

您还需要知道当前列表大小,与下一个列表元素的偏移量相同。你已经在处理这个了;从-1 开始并在操作之前递增有点不合常规,但它确实有效。

现在你实际上 wordList[i] 分配,直到i &gt;= 20

unsigned int wordListLen = 0;
...
if(wordListLen >= 20){
   // list full!
   break;
} else {
   unsigned int wlen = strnlen(word,10)+1;
   wordList[wordListLen] = malloc( wlen * sizeof(char) );
   strncpy(wordList[wordListLen], word, 10);
   wordListLen++;
   ...print...
}

在分配word 的副本时,不要忘记'\0' 的位置!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 2016-03-25
    • 1970-01-01
    • 2023-04-04
    相关资源
    最近更新 更多