strtok() 与 realloc() 奇怪的行为

Ale*_*lex 0 c strtok realloc

我有以下用 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
    }
    ...

Run Code Online (Sandbox Code Playgroud)

问题是 strtok() 表现出奇怪的行为,它返回一个词,该词不存在于短语字符串中,但属于答案字符串的一部分。

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

void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1000);
Run Code Online (Sandbox Code Playgroud)

到:

void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1);
Run Code Online (Sandbox Code Playgroud)

strok() 按预期工作。

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

dbu*_*ush 5

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);
Run Code Online (Sandbox Code Playgroud)

还有一个问题:第一次realloc调用内存是完全未初始化的。随后调用strcat它取决于answer包含一个空终止字符串。事实并非如此,这也会调用未定义的行为。

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

char *answer = malloc(1);
if (!answer) return -1;
answer[0] = 0;
Run Code Online (Sandbox Code Playgroud)