这是我的程序的一部分,将一行文件解析为数组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
任何帮助?
答案 0 :(得分:1)
问题在于
char *num_args[100];
声明一个指针数组,但它们未初始化。你的for
循环了
解析行不一定在数组中设置所有100个空格,所以有些
将会保持未初始化状态,最有可能是!= NULL
。
这就是为什么free
失败的原因,因为在你的自由循环中的某些时候你正在尝试
为尚未初始化的free(num_args[j])
执行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)
<强> Fotenotes 强>
1 正如chux在评论中指出的那样,我的语句初始化了指向NULL
的所有指针。是
并非完全正确,因为只有第一个元素被初始化为NULL
,所有其他元素
元素用0位模式初始化。可能有架构
其中NULL
未由0位模式和元素的其余部分表示
不会指向NULL
。但在大多数体系结构中,NULL
是0位模式和
效果是所有元素都指向NULL
。看到
https://ideone.com/RYAyHm作为与GCC汇编的一个例子。
2 我正在使用chux第二条评论所使用的措辞,解释非常好。
答案 1 :(得分:1)
您的代码中存在多个问题:
主循环使用虚假测试来结束文件:你应该写while (fgets(str, 1024, f) != NULL) {
释放已分配指针的循环应停在id
:超出此索引,所有指针都未初始化,因此将它们传递给free
具有未定义的行为。另请注意,将空指针传递给free
是完全安全的。如果以这种方式修改循环,则无需初始化此数组:
for (j = 0; j < id; j++) {
free(num_args[j]);
}
将单词存储到数组中的方式效率低且风险大:您分配16个字节的内存并使用sscanf()
和%s
转换说明符来复制单词由strtok
解析。
num_args[id]
将最大数量的字符存储到sscanf(line, "%15s", num_args[id]);
。\r
,\n
,\t
...您只需将该字词存储为{{1} }。num_args[id] = strdup(line);
:strtok
line = strtok(str, " \t\r\n\v\f")
也是有问题的:您不测试storage_people
字节是否足够用于生成的字符串,包括终止空字节。您应该使用实用程序函数将2个字符串与重新分配连接到适当的大小。