我有以下功能读入图表。当我运行Valgrind时,我收到以下错误:
char * line = malloc(1024 * 1024)
我使用pr_graph * pr_graph_load(
char const * const ifname)
{
FILE * fin = fopen(ifname, "r");
pr_graph * graph = malloc(sizeof(*graph));
char * line = malloc(1024 * 1024);
size_t len = 0;
/* Read in graph one vertex at a time. */
for(pr_int v=0; v < graph->nvtxs; ++v) {
ssize_t read = getline(&line, &len, fin);
if(read == -1) {
free(line);
fprintf(stderr, "ERROR: premature EOF at line %lu\n", v+1);
pr_graph_free(graph);
return NULL;
}
/* Store the beginning of the adjacency list. */
graph->xadj[v] = edge_ptr;
/* Check for sinks -- these make pagerank more difficult. */
if(read == 1) {
fprintf(stderr, "WARNING: vertex '%lu' is a sink vertex.\n", v+1);
continue;
}
/* Foreach edge in line. */
char * ptr = strtok(line, " ");
while(ptr != NULL) {
char *end = NULL;
pr_int const e_id = strtoull(ptr, &end, 10);
/* end of line */
if (ptr == end) {
break;
}
assert(e_id > 0 && e_id <= graph->nvtxs);
graph->nbrs[edge_ptr++] = e_id - 1; /* 1 indexed */
ptr = strtok(NULL, " ");
}
}
assert(edge_ptr == graph->nedges);
graph->xadj[graph->nvtxs] = graph->nedges;
free(line);
fclose(fin);
return graph;
分配1048576个字节,但最后,我释放了行指针。我在这里做错了什么?
{{1}}
答案 0 :(得分:4)
您滥用POSIX getline()
功能。你有:
char * line = malloc(1024 * 1024);
size_t len = 0;
/* Read in graph one vertex at a time. */
for(pr_int v=0; v < graph->nvtxs; ++v)
{
ssize_t read = getline(&line, &len, fin);
您告诉getline()
分配了零字节,因此它在line
中分配了更多空间 - 在此之前没有free()
行的义务。
ssize_t getline(char **restrict lineptr, size_t *restrict n, FILE *restrict stream);
应用程序应确保
*lineptr
是可以传递给free()
函数的有效参数。如果*n
非零,则应用程序应确保*lineptr
指向大小至少为*n
字节的对象,或者为空指针。
您的代码符合'*lineptr
是一个有效的参数,可以传递给free()
'标准;但是您将*n
设置为零,因此第二个条件不相关。由于*n
表示“尚未分配内存”,因此会忽略*lineptr
中的值。
你应该使用其中一种:
char * line = 0;
size_t len = 0;
/* Read in graph one vertex at a time. */
for(pr_int v=0; v < graph->nvtxs; ++v)
{
ssize_t read = getline(&line, &len, fin);
或:
size_t len = 1024 * 1024;
char * line = malloc(size);
/* Read in graph one vertex at a time. */
for(pr_int v=0; v < graph->nvtxs; ++v)
{
ssize_t read = getline(&line, &len, fin);
要么工作。我可能会使用空缓冲区 - 我不会经常预先分配1 MiB的空间,除非我知道它将被全部使用。
请注意,使用空指针和零长度,getline()
通常会分配空间,即使文件为空并且它立即返回-1
。你应该采取措施来解放它。由于line
为空,即使getline()
未分配空格,line
也可以安全地传递给free()
。
如果您正在正确编译(使用-g
选项编译和链接),Valgrind将告诉您哪个行分配了泄漏的内存。如果你没有得到这些信息,你就会误用Valgrind(或者,至少使用它不足 - 如果你让它,它可以告诉你更多)。
答案 1 :(得分:0)
我认为您应该尝试禁用此行
ssize_t read = getline(&line, &len, fin);
这是猜测,但我认为line
正在修改getline
...
因此,如果您运行没有它的代码,那么您将看到valgrind
,如果这就是问题所在。
如果这是答案,那么你可以为line
设置较少的内存并用
char line [100000];
那么你认为你不会有同样的记忆问题......