无法在我的 strtok 程序中正确分配和释放内存
Unable to malloc and free memory properly in my strtok program
所以这是我将一行文件解析为数组 num_args 的程序的一部分,我将其用于进一步的实现:
while(fgets(str, 1024, f) > 0) {
int id;
int final_arg_num;
int my_index;
char *num_args[100];
for (id = 0, line = strtok(str, " "); id < 100; id++) {
if (line == NULL) {
break;
}
num_args[id] = malloc(16*sizeof(char));
sscanf(line, "%s", num_args[id]);
line = strtok(NULL, " ");
}
final_arg_num = id;
char *storage_people = (char *)malloc(sizeof(char)*need);
if (strcmp(num_args[0],"Movie:") != 0) {
strcpy(storage_people,num_args[0]);
} else {
strcpy(storage_people,"");
}
for (my_index = 1; my_index < final_arg_num; my_index++) {
if (strcmp(num_args[0],"Movie:") || (!strcmp(num_args[0],"Movie:") && my_index > 1))
strcat(storage_people, " " );
strcat(storage_people, num_args[my_index]);
}
if (strcmp(num_args[0],"Movie:") == 0) {
// do something
} else {
// do something
}
/**for (j = 0; j < 100; j++) {
if (num_args[j] != NULL) {
free(num_args[j]);
}
}**/
free(storage_people);
}
fclose(f);
如果我不释放 num_args,我会发生内存泄漏;如果我取消注释我程序的 free(num_args[j])
部分,我会得到这样的 valgrind 错误:
==3062== Conditional jump or move depends on uninitialised value(s)
==3062== at 0x401D3B: main (original.c:410)
==3062==
==3062== Conditional jump or move depends on uninitialised value(s)
==3062== at 0x4C2BDA2: free (in .*)
==3062== by 0x401D54: main (original.c:411)
==3062==
==3062== Invalid free() / delete / delete[] / realloc()
==3062== at 0x4C2BDEC: free (in .*)
==3062== by 0x401D54: main (original.c:411)
==3062== Address 0x8 is not stack'd, malloc'd or (recently) free'd
有什么帮助吗?
问题是
char *num_args[100];
声明了一个指针数组,但未初始化。你的 for
循环
解析行不一定设置数组中的所有 100 个空格,所以一些
将保持未初始化状态,很可能 != NULL
.
这就是 free
失败的原因,因为在您 free-loop 的某个时刻您正在尝试
为尚未初始化的 num_args[j]
执行 free(num_args[j])
并且
不是 NULL
,因此它崩溃了。
您必须初始化数组,或者像这样 memset
char *num_args[100];
memset(num_args, 0, sizeof num_args);
或使用初始化列表
char *num_args[100] = { NULL };
将所有指针初始化为 null 指针1,2.
你应该像这样fgets
检查
while(fgets (str , 1024 , f))
或者像这样
while(fgets (str , 1024 , f) != NULL)
注释
1正如 在评论中指出的,我的语句 将所有指针初始化为 NULL
. 是
不完全正确,因为只有第一个元素被初始化为 NULL
,所有其他
元素用 0 位模式初始化。可能有架构
其中 NULL
不是由 0 位模式表示的,元素的其余部分
不会指向 NULL
。但在大多数体系结构中,NULL
是 0 位模式并且
结果将是所有元素都指向 NULL
。看
https://ideone.com/RYAyHm 作为使用 GCC 编译的示例。
2我用的是第二条评论的措辞,解释的很好
您的代码中存在多个问题:
主循环对文件末尾使用虚假测试:您应该改写 while (fgets(str, 1024, f) != NULL) {
释放已分配指针的循环应停止在 id
:超出此索引,所有指针都未初始化,因此将它们传递给 free
具有未定义的行为。另请注意,将空指针传递给 free
是完全安全的。如果您这样修改循环,则无需初始化此数组:
for (j = 0; j < id; j++) {
free(num_args[j]);
}
将单词存储到数组中的方式既低效又危险:您分配 16 个字节的内存并使用 sscanf()
和 %s
转换说明符来复制word 由 strtok
解析。
- 您应该将要存储到
num_args[id]
中的最大字符数传递给 sscanf(line, "%15s", num_args[id]);
。
- 注意,除非源字符串中有其他白色space字符,如
\r
、\n
、\t
...你可以只存储num_args[id] = strdup(line);
. 字词
- 如果这些字符应被视为源字符串中的分隔符,请将它们传递给
strtok
:line = strtok(str, " \t\r\n\v\f")
- 将单词复制和连接到
storage_people
中也是有问题的:您没有测试 need
字节是否足够 space 作为结果字符串,包括终止空字节。您应该使用效用函数连接 2 个字符串并重新分配到适当的大小。
所以这是我将一行文件解析为数组 num_args 的程序的一部分,我将其用于进一步的实现:
while(fgets(str, 1024, f) > 0) {
int id;
int final_arg_num;
int my_index;
char *num_args[100];
for (id = 0, line = strtok(str, " "); id < 100; id++) {
if (line == NULL) {
break;
}
num_args[id] = malloc(16*sizeof(char));
sscanf(line, "%s", num_args[id]);
line = strtok(NULL, " ");
}
final_arg_num = id;
char *storage_people = (char *)malloc(sizeof(char)*need);
if (strcmp(num_args[0],"Movie:") != 0) {
strcpy(storage_people,num_args[0]);
} else {
strcpy(storage_people,"");
}
for (my_index = 1; my_index < final_arg_num; my_index++) {
if (strcmp(num_args[0],"Movie:") || (!strcmp(num_args[0],"Movie:") && my_index > 1))
strcat(storage_people, " " );
strcat(storage_people, num_args[my_index]);
}
if (strcmp(num_args[0],"Movie:") == 0) {
// do something
} else {
// do something
}
/**for (j = 0; j < 100; j++) {
if (num_args[j] != NULL) {
free(num_args[j]);
}
}**/
free(storage_people);
}
fclose(f);
如果我不释放 num_args,我会发生内存泄漏;如果我取消注释我程序的 free(num_args[j])
部分,我会得到这样的 valgrind 错误:
==3062== Conditional jump or move depends on uninitialised value(s)
==3062== at 0x401D3B: main (original.c:410)
==3062==
==3062== Conditional jump or move depends on uninitialised value(s)
==3062== at 0x4C2BDA2: free (in .*)
==3062== by 0x401D54: main (original.c:411)
==3062==
==3062== Invalid free() / delete / delete[] / realloc()
==3062== at 0x4C2BDEC: free (in .*)
==3062== by 0x401D54: main (original.c:411)
==3062== Address 0x8 is not stack'd, malloc'd or (recently) free'd
有什么帮助吗?
问题是
char *num_args[100];
声明了一个指针数组,但未初始化。你的 for
循环
解析行不一定设置数组中的所有 100 个空格,所以一些
将保持未初始化状态,很可能 != NULL
.
这就是 free
失败的原因,因为在您 free-loop 的某个时刻您正在尝试
为尚未初始化的 num_args[j]
执行 free(num_args[j])
并且
不是 NULL
,因此它崩溃了。
您必须初始化数组,或者像这样 memset
char *num_args[100];
memset(num_args, 0, sizeof num_args);
或使用初始化列表
char *num_args[100] = { NULL };
将所有指针初始化为 null 指针1,2.
你应该像这样fgets
检查
while(fgets (str , 1024 , f))
或者像这样
while(fgets (str , 1024 , f) != NULL)
注释
1正如 NULL
. 是
不完全正确,因为只有第一个元素被初始化为 NULL
,所有其他
元素用 0 位模式初始化。可能有架构
其中 NULL
不是由 0 位模式表示的,元素的其余部分
不会指向 NULL
。但在大多数体系结构中,NULL
是 0 位模式并且
结果将是所有元素都指向 NULL
。看
https://ideone.com/RYAyHm 作为使用 GCC 编译的示例。
2我用的是
您的代码中存在多个问题:
主循环对文件末尾使用虚假测试:您应该改写
while (fgets(str, 1024, f) != NULL) {
释放已分配指针的循环应停止在
id
:超出此索引,所有指针都未初始化,因此将它们传递给free
具有未定义的行为。另请注意,将空指针传递给free
是完全安全的。如果您这样修改循环,则无需初始化此数组:for (j = 0; j < id; j++) { free(num_args[j]); }
将单词存储到数组中的方式既低效又危险:您分配 16 个字节的内存并使用
sscanf()
和%s
转换说明符来复制word 由strtok
解析。- 您应该将要存储到
num_args[id]
中的最大字符数传递给sscanf(line, "%15s", num_args[id]);
。 - 注意,除非源字符串中有其他白色space字符,如
\r
、\n
、\t
...你可以只存储num_args[id] = strdup(line);
. 字词
- 如果这些字符应被视为源字符串中的分隔符,请将它们传递给
strtok
:line = strtok(str, " \t\r\n\v\f")
- 您应该将要存储到
- 将单词复制和连接到
storage_people
中也是有问题的:您没有测试need
字节是否足够 space 作为结果字符串,包括终止空字节。您应该使用效用函数连接 2 个字符串并重新分配到适当的大小。