【问题标题】:strtok() with realloc() weird behaviourstrtok() 与 realloc() 奇怪的行为
【发布时间】:2020-01-18 20:40:42
【问题描述】:

我有以下用 C 编写的程序:

    ...
    char *answer = NULL;
    char *pch = strtok(phrase, " "); // phrase is a string with possibly many words
    while (pch) {
        char *tmp = translate_word(pch); // returns a string based on pch
        void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1000); // allocate space to answer
        if (!ptr) // If realloc fails
             return -1;
        strcat(answer, tmp); // append tmp to answer
        pch = strtok(NULL, " "); // find next word
    }
    ...

问题在于 strtok() 表现出奇怪的行为,它返回一个在 phrase 字符串中不存在但属于 answer 字符串的单词。

另一方面,当我更改以下行时:

void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1000);

到:

void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1);

strok() 按预期工作。

在这种情况下,realloc() 如何影响 strtok()?他们甚至不使用相同的变量。期待您的见解。

【问题讨论】:

  • sizeof(answer)sizeof(tmp) - 这不是你想的那样。此外,realloc 不会根据strcat 工作的需要终止answer
  • realloc frees answer 重新分配后,所以你应该使用strcat(ptr, tmp)
  • 关于:realloc()sizeof(tmp):tmp 调用中的表达式是一个指针,因此取决于您的底层硬件和某些编译器选项,该值将是 4 或 8 个字节,不是tmp 指向的字符数组的长度
  • 关于:void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1000); // allocate space to answer if (!ptr) // If realloc fails return -1; 1)当realloc()失败时,ptr原来指向的数据丢失,导致内存泄漏。始终从realloc() 的返回值中分配一个临时指针,检查临时指针是否不为 NULL,然后分配给原始指针。 (续)
  • (cont) 另外,不要在发生错误时立即退出,而是首先调用perror( "realloc failed" );,它会输出到stderr,您的错误消息和系统认为发生错误的文本原因。

标签: c realloc strtok


【解决方案1】:

realloc 函数可以移动之前分配的内存。调用后,返回分配内存的指针,传递给它的指针值,如果不同,则不再有效。因此,当您调用 strcat(answer, tmp); 时,您可能正在写入调用 undefined behavior 的已释放内存,在这种情况下,它表现为您看到的奇怪输出。

检查realloc的返回值后,将该值赋回answer

另外,sizeof(answer)sizeof(tmp) 给你指针的大小,而不是它所指向的大小。相反,您想使用strlen 来获取字符串的长度然后包含。在我们处理它的同时,让我们只添加 1 而不是 1000,因为这就是您真正需要的。

    void *ptr = realloc(answer, strlen(answer) + strlen(tmp) + 1);
    if (!ptr)
         return -1;
    answer = ptr;
    strcat(answer, tmp);

还有一个问题:第一次调用realloc 时,内存完全未初始化。随后在其上调用 strcat 取决于 answer 包含一个以空字符结尾的字符串。并非如此,这也会调用未定义的行为。

这可以通过malloc-ing 一个字节开始并将其设置为 0 来解决,这样你就可以从一个空字符串开始。

char *answer = malloc(1);
if (!answer) return -1;
answer[0] = 0;

【讨论】:

    【解决方案2】:

    sizeof(answer) & sizeof(tmp) 为您提供指针的大小。

    你需要使用 strlen 来代替

    【讨论】:

    • 这只是部分答案,并没有解决可能的主要问题,忘记在realloc之后更新指针。
    • @HAL9000 但它以它开头。
    【解决方案3】:

    另外...

    char *answer = NULL;
    

    ...任一:

    ... strlen(answer) ...
    strcat(answer, tmp);
    

    这些应该失败,有分段违规,但可能不取决于操作系统。取消引用 NULL 绝不是一个好主意。

    简而言之,您需要知道您已经为answer 分配了一些东西,或者检查答案是否为NULL。

    【讨论】:

      猜你喜欢
      • 2016-07-30
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 2018-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多