C语言中的自由字符指针

Free char pointer in C language

我有以下读取图表的函数。当我在 运行 Valgrind 时出现以下错误:

definitely lost: 1,048,576 bytes in 1 blocks

我正在使用 char * line = malloc(1024 * 1024) 分配 1048576 个字节,但最后,我释放了行指针。我在这里做错了什么?

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;

我认为你应该尝试禁用这条线

ssize_t read = getline(&line, &len, fin);

这是一个猜测,但我认为 line 正在被 getline...

修改

所以如果你 运行 没有它的代码那么你会看到 valgrind 如果那是问题所在。

如果那是答案,那么您可以为 line 分配更小的内存,并用

定义它
char line [100000];

那么你就不会遇到我认为的同样的内存问题...

您误用了 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 中分配了更多的 space — 在这样做之前它没有义务到 free() 行。

ssize_t getline(char **restrict lineptr, size_t *restrict n,
       FILE *restrict stream);

The application shall ensure that *lineptr is a valid argument that could be passed to the free() function. If *n is non-zero, the application shall ensure that *lineptr either points to an object of size at least *n bytes, or is a null pointer.

您的代码满足“*lineptr 是可以传递给 free() 的有效参数”标准;但是您将 *n 设置为零,因此第二个条件不相关。由于 *n 表示 "there is no memory allocated yet",它将忽略 *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 的 space,除非我知道它会全部被使用。

请注意,对于空指针和零长度,getline() 通常会分配 space,即使文件为空,它也会立即 returns -1。您应该采取措施释放它。由于 line 为空,即使 getline() 不分配 space,line 也可以安全地传递给 free()

如果编译正确(使用-g选项编译link),Valgrind会告诉您哪一行分配了泄漏的内存。如果你没有得到这些信息,你就是在滥用 Valgrind(或者,至少,没有充分利用它——如果你愿意,它可以告诉你更多)。