strtok 和 free

3
这样做有哪些问题:
void *educator_func(void *param) {
char *lineE = (char *) malloc (1024);
size_t lenE = 1024;
ssize_t readE;

FILE * fpE;

fpE = fopen(file, "r");

if (fpE == NULL) {
    printf("ERROR: couldnt open file\n");
    exit(0);
}

while ((readE = getline(&lineE, &lenE, fpE)) != -1) {
    char *pch2E = (char *) malloc (50);

    pch2E = strtok(lineE, " ");

    free(pch2E);
}

free(lineE);
fclose(fpE);

return NULL;
}

如果我删除这行代码'pch2E = strtok(lineE, " ");',它就可以正常工作...
为什么我不能在那里使用strtok()?我也尝试过用strtok_r(),但是没有成功,它会给我返回一个无效的释放地址(0x422af10地址在大小为1,024的块内被释放了0个字节)。
2个回答

2

你的代码并没有按照你想象的那样执行... 调用 pch2E = strtok(lineE, " "); 会将 pch2E 的值替换为 strtok 的返回值,该返回值可能是 lineE 或者是新分配的替代品。

你可以按照以下方式修复它...

int firstPass = 1;
while ((readE = getline(&lineE, &lenE, fpE)) != -1) 
{
    char* pch2E = strtok( firstPass ? lineE : NULL, " ");
    firstPass = 0;
}

free(lineE);

我想补充一下,越看你的代码,它就越显得根本性有缺陷。你需要在代码中添加一个内部循环来处理标记,而外部循环则是加载行...

while ((readE = getline(&lineE, &lenE, fpE)) != -1) 
{
    char* pch2E;
    int firstPass = 1;

    while( (pch2E = strtok( firstPass ? lineE : NULL, " ")) != NULL )
    {
        firstPass = 0;
        // do something with the pch2E return value
    }
}

free(lineE);

应该使用lenE,而不是&lenE,我们需要缓冲区的大小,而不是保存该数字的变量的地址。 - LtWorf
错误。getline 的原型期望一个指向长度变量的指针,该变量将从 getline 中作为输出填充。 - K Scott Piel
没关系...只是想确保那里没有混淆 微笑 - K Scott Piel

1

strtok返回指向标记的指针,该标记包含在您传递的字符串中,因此您不能释放它,因为它不(总是)指向您使用malloc分配的内容。

如果您想要一个将标记复制到缓冲区中的函数,那么这样做是行不通的。在C语言中,应该这样实现:

tokenize(char* string, char* delimiter, char* token);

您需要传递一个有效的指向token的指针,以便函数可以复制其中的数据。在C语言中,为了复制指针中的数据,函数需要访问该指针,因此无法在返回值上执行此操作。

另一种策略(但更糟糕)是编写一个在内部分配内存并返回需要由调用者释放的内存区域指针的函数。

对于您的问题,需要多次调用strtok来返回所有标记,直到它返回null,因此应该是:

while ((readE = getline(&lineE, &lenE, fpE)) != -1) {
    char *pch2E;

    pch2E = strtok(lineE, " "); //1st token

    while ((pch2E = strtok(NULL, " ")) != NULL) {
        //Do something with the token
    }
}

你使用getline函数时传递的长度参数是错误的。请查看getline函数的man手册——函数原型如下:ssize_t getline(char **lineptr, size_t *n, FILE *stream); - K Scott Piel
1
此外,请注意,当您重新解析一行时,strtok 希望您将 NULL 作为第一个参数传递给它。每次传入 lineE 都会重新从字符串顶部开始解析 -- strtok 是一个全局有状态的函数(因此有替代的 strtok_r)。 - K Scott Piel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接