【问题标题】:Segmentation fault on sprintf in CC中sprintf的分段错误
【发布时间】:2014-10-27 17:13:41
【问题描述】:

此函数位于套接字服务器中。当客户端发送查询时,服务器接受查询并从链表中查找匹配项。该函数在前几个查询中运行良好,然后发生分段错误。问题发生在 sprintf 调用中(“Before sprintf.\n”之后的那个)。我真的不明白为什么它只工作了几次。我做错了什么?

char* searchNode(char* query) {
    int i, isFound, count = 0;
    node* temp = head;
    char* searchResult = calloc(1, sizeof(* searchResult));
    char* finalResult = calloc(1, sizeof(* finalResult));;

    printf("Before search node.\n");

    while(temp->next) {
        isFound = TRUE;
        temp = temp->next;
        for(i = 0; i < strlen(query); i++) { /* compare each char in both strings */
            if(tolower(query[i]) != tolower(temp->foodName[i])) {
                isFound = FALSE;
                break;
            }
        }
        if(isFound == TRUE) { /* if a match is found, write it into the temp string */
        printf("Match found.\n");
            searchResult = realloc(searchResult, strlen(searchResult) + 1 + strlen(nodeToString(temp)) + 1);
        printf("Before sprintf.\n");
            sprintf(searchResult, "%s%s", searchResult, nodeToString(temp));
            count++; /* count the number of results found */
        }
    }

    printf("Before finalise string.\n");

    if(count > 0) { /* if at least a result is found, add combine all results with a head line*/
        sprintf(finalResult, "%d food item(s) found.\n\n", count);
        strcat(finalResult, searchResult);
        free(searchResult);
        return finalResult;
    }

    /* if no match is found, return this message */
    return "No food item found.\nPlease check your spelling and try again.\n";
}

【问题讨论】:

  • 您正在尝试将字符串打印到自身中。如果您想将一个字符串附加到另一个字符串,请考虑使用strcatstrncat
  • 这一行:node* temp = head;似乎引用了一个未定义的变量“头”。
  • 这种行:char* searchResult = calloc(1, sizeof(* searchResult));不太可能工作,因为(在开始时)searchResult 没有特别指向任何东西,所以如果有任何有用的话,请求取消引用的大小很可能返回 4
  • (当前)int 变量 isFound 被设置为 TRUE 或 FALSE。但是,它没有被初始化为任何一个值,应该在单独的行上定义为 bool isFound = FALSE;
  • 这一行:sprintf(finalResult, "%d food item(s) found.\n\n", count);将导致未定义的行为,因为它没有指向足够长的区域以包含放置在其中的文本。

标签: c arrays string sockets printf


【解决方案1】:

当将 searchResult 作为参数传递时,我不知道 sprintf 会做什么。我系统上的手册页表明它是未定义的:

C99 和 POSIX.1-2001 指定如果调用结果未定义 到 sprintf()、snprintf()、vsprintf() 或 vsnprintf() 会导致复制 发生在重叠的对象之间(例如,如果目标 字符串数组和提供的输入参数之一指的是相同的 缓冲区)。

您可能应该在那里使用 strcat。

【讨论】:

    【解决方案2】:

    只需阅读失败的行

     sprintf(searchResult, "%s%s", searchResult, nodeToString(temp));
    

    它说将 searchResult 和其他内容打印到 searchResult 中。它不可能工作

    searchResult 不是 Tardis

    【讨论】:

      【解决方案3】:

      您忘记测试calloc 是否成功。而且您使用不正确:您需要为其中的以 0 结尾的字符串分配足够的字节。

      请注意,char* searchResult = calloc(1, sizeof(* searchResult)); 大错特错:它等同于/* wrong code*/ char* searchResult= calloc(1,1);,您不能这样做(您需要分配足够宽的字符串);你有一些undefined behavior,但运气不好,它没有崩溃(SO 包含 很多关于 UB 的答案,参见例如this one)。

      您应该使用snprintf(3)(可能使用strdup(3))并且您应该考虑snprintf + 1 的结果作为终止零字节。如果您的系统提供asprintf(3),您可能需要使用它。

      请编译所有警告和调试信息gcc -Wall -Wextra -g。使用valgrindgdb 调试器。

      【讨论】:

      • 令人惊讶的是(从坏的意义上说)人们对标准库函数的安全版本一无所知,并且更喜欢其中的危险变体......
      • 我会说 OP 只是忘记(?)重新分配 finalResult 最终指向的内容。
      • 感谢您的回答。但是为什么它会在最初的几个电话中起作用并最终崩溃呢?这真的让我很困扰。如果它不正确,它根本不应该工作。但为什么?我已经坚持了好几天了。我还是不明白。
      • @KolyaH:你错了:UB 是不对的,但不幸的是,它有时可能看起来可能有效。遗憾的是,UB 并不总是崩溃! (参考我的一些回答提到 UB)
      【解决方案4】:

      正在调整 searchResult 指向的内容,但 finalResult 仅指向 1 char,尽管最终将所有搜索结果复制到其中,这很可能是更多1 char,写入无效内存并引发未定义行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多