此函数中缺少free()导致内存泄漏

问题描述 投票:0回答:3

以下代码用于查找c中基本shell的可执行文件的路径。如您所见,我动态分配path变量,然后检查路径是否存在(通过辅助函数lstat中的cmd_exists)。然后我返回路径变量。我的问题是,这会导致内存泄漏,因为path永远不会被释放。在我返回它的值之前我无法释放路径,并且截至目前我无法想出释放已分配的内存的任何方法。如果有人能帮助我,我会很感激。谢谢

char * find_path(char * mypath, char * command){
     char * token = strtok(mypath, "#");
     while(token != NULL){
                         /*token size + 1 (for /) + command size*/
          char * path = calloc(strlen(token)+1+strlen(command)+1, sizeof(char));
          strcat(path, token);
          strcat(path, "/");
          strcat(path, command);
          if(cmd_exists(path) == 1){
             return path;
          }
          token = strtok(NULL, "#");
     }
     return NULL;
}
c free dynamic-memory-allocation
3个回答
4
投票

这确实是C的问题之一。内存所有权可能相当困难,因为C ++中没有RAII概念(基本上没有自动析构函数)。

我看到3个解决方案如何解决这个问题:

  • 3的最糟糕的解决方案是拥有一个全局静态缓冲区,让你的find_path函数填充这个缓冲区,并将一个指针返回给调用者。这个技巧被很多其他标准C函数使用,但是它也有很多问题(通常不是线程安全的,如果它是线程安全的,那么下一个调用可能会覆盖之前的返回值)。有关具有此行为的函数,请参阅https://en.cppreference.com/w/cpp/utility/program/getenv(查看顶部的警告)。
  • 稍微好一点的解决方案是记录函数的返回值,并清楚告诉调用者释放返回指针是负责任的。如果他没有,你会得到内存泄漏。有关使用此行为的函数,请参阅https://en.cppreference.com/w/c/experimental/dynamic/strdup
  • 另一种解决方案是让调用者以最大大小向您的函数传递缓冲区。所以不添加char *,而是添加char *size_t参数(size_t表示char *缓冲区的大小)。然后你的find_path函数可以填充这个缓冲区。有关具有此行为的函数,请参阅https://en.cppreference.com/w/cpp/string/byte/strncpy。这种方法的问题是如果缓冲区不够大,你的函数需要返回一个失败,调用者必须传递一个更大的缓冲区。一些Windows函数通过让函数返回“预期”缓冲区大小来解决这个问题,所以如果调用失败(因为缓冲区不够大),调用者可以使用返回值来查看缓冲区应该有多大,并分配更大的缓冲区。

我的首选解决方案取决于实际情况。如果存在有意义的最大缓冲区大小(例如,最大文件路径),我将采用第三种替代方案。我会采取第二种选择是最大缓冲区大小很难预测。在任何情况下,我都不会使用第一种替代品。


2
投票

你需要在两个可能的地方有free

  1. 如果cmd_exists返回false,则需要释放路径。
  2. 如果cmd_exists返回true,则需要在调用方法中有空。

1.

 while(token != NULL){
                     /*token size + 1 (for /) + command size*/
      char * path = calloc(strlen(token)+1+strlen(command)+1, sizeof(char));
      strcat(path, token);
      strcat(path, "/");
      strcat(path, command);
      if(cmd_exists(path) == 1){
         return path;
      }

      free(path);   // 1. Here

      token = strtok(NULL, "#");
 }
 return NULL;

2.

 char *temp = find_path(...);
  .....//do your stuff
  if (temp) free(temp);

0
投票

您可以要求呼叫者释放内存:

// in caller
char * s = find_path("/mypath", "command");
// do something about `s`
free(s);
© www.soinside.com 2019 - 2024. All rights reserved.