在C语言的递归函数中使用free()函数
我有一个基本的递归函数来遍历目录 代码中有一些内存泄漏。但是我找不到它们,我在一些行中尝试了在C语言的递归函数中使用free()函数,c,recursion,C,Recursion,我有一个基本的递归函数来遍历目录 代码中有一些内存泄漏。但是我找不到它们,我在一些行中尝试了free() 有6个allocs和4个free。我怎样才能做到6个allocs和6个free?我想我应该freedepthPath,不是吗?(如果是,我应该在哪里免费it?) 这是我的c程序: #include <stdio.h> #include <sys/stat.h> #include <stdlib.h> #include <string.h> #i
free()
有6个allocs和4个free。我怎样才能做到6个allocs和6个free?我想我应该free
depthPath
,不是吗?(如果是,我应该在哪里免费it?)
这是我的c程序:
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
void recursiveFoo (char *path);
int main(int argc, char **argv){
recursiveFoo (argv[1]);
return 0;
}
void recursiveFoo (char *path){
char *depthPath;
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d) {
while ((dir = readdir(d)) != NULL) {
depthPath= (char*)malloc(strlen(path) + strlen(dir->d_name) + 1);
strcpy(depthPath, path);
strcat(depthPath, "/");
strcat(depthPath, dir->d_name);
if(((strcmp(dir->d_name,".")!=0) && (strcmp(dir->d_name,".."))!=0) ){
recursiveFoo(depthPath);
free(depthPath);
}
}
printf("%s/",path );
closedir(d);
}
}
您没有为depthPath
分配足够的内存:
depthPath= (char*)malloc(strlen(path) + strlen(dir->d_name) + 1);
strcpy(depthPath, path);
strcat(depthPath, "/");
strcat(depthPath, dir->d_name);
生成的字符串需要一个额外的字节,用于结尾处的\0
要修复内存泄漏,可以添加free(depthPath)代码>到循环的底部,就在进入下一个迭代之前
或者,您可以修改代码以使用realloc()
而不是malloc()
,然后在循环完成后调用free()
。尝试此方法时,您可能希望将depthPath
初始化为NULL
当您递归到目录树的更深处时,该算法会分配O(n2)内存。为了避免这种情况,您可以修改方法,以便将path
参数本身传递给realloc(),以便为其他子目录腾出空间。但是,由于realloc()返回的指针值可能与传入的指针值不同,因此需要将指针值返回给调用方
为了保持原始API的使用,可以将带有realloc()
调用的实际递归函数封装到帮助函数中
static void recursiveFoo__(char **, int);
void recursiveFoo (const char *path) {
int depthPathLen = strlen(path);
char *depthPath = malloc(depthPathLen+1);
strcpy(depthPath, path);
recursiveFoo__(&depthPath, depthPathLen);
free(depthPath);
}
void recursiveFoo__ (char **depthPath, int depthPathLen){
DIR *d;
struct dirent *dir;
d = opendir(*depthPath);
if (d) {
while ((dir = readdir(d)) != NULL) {
int newPathLen = depthPathLen + strlen(dir->d_name) + 1;
char *newPath= realloc(*depthPath, newPathLen+1);
if (newPath == NULL) {
fprintf(stderr, "oops: %.*s/%s\n",
depthPathLen, *depthPath, dir->d_name);
break;
}
*depthPath = newPath;
strcpy(newPath+depthPathLen, "/");
strcpy(newPath+depthPathLen+1, dir->d_name);
if(((strcmp(dir->d_name,".")!=0) &&
(strcmp(dir->d_name,".."))!=0) ){
recursiveFoo__(depthPath, newPathLen);
}
}
printf("%.*s/\n", depthPathLen, *depthPath);
closedir(d);
}
}
现在,内存分配将为O(n)。此代码没有为复制到块中的字符串分配足够的内存:
depthPath= (char*)malloc(strlen(path) + strlen(dir->d_name) + 1);
strcpy(depthPath, path);
strcat(depthPath, "/");
strcat(depthPath, dir->d_name);
新字符串需要strlen(path)+strlen(dir->d_name)+strlen(“/”)+1
字符来解释“/”
和终止的'\0'
此外,为了修复您的漏洞,此代码
while ((dir = readdir(d)) != NULL) {
depthPath= (char*)malloc(strlen(path) + strlen(dir->d_name) + 1);
strcpy(depthPath, path);
strcat(depthPath, "/");
strcat(depthPath, dir->d_name);
if(((strcmp(dir->d_name,".")!=0) && (strcmp(dir->d_name,".."))!=0) ){
recursiveFoo(depthPath);
}
}
可以写成
while ((dir = readdir(d)) != NULL)
{
if(((strcmp(dir->d_name,".")==0) ||
(strcmp(dir->d_name,".."))==0) )
{
continue;
}
char *depthPath= malloc(strlen(path) + strlen(dir->d_name) + 2);
strcpy(depthPath, path);
strcat(depthPath, "/");
strcat(depthPath, dir->d_name);
recursiveFoo(depthPath);
free(depthPath):
}
我肯定会把重点放在泄漏报告之前的错误上。这些错误描述了无效的指针使用,这是未定义的行为,也可能会干扰内存跟踪。提示:使用s(n)printf
而不是strcat
stuff…对于free
,在不再需要时尽早释放路径!(需要它的地方是递归函数调用!)当我在包含大量不同大小文件的目录中尝试时,您的代码崩溃。幸运的是,您的目录中只有4个文件?漏洞已得到修复-free()
当前在if
语句体中调用,这意味着除非执行if
语句体,否则不会释放分配的内存。将free()
移动到if块之后。这样,如果调用了malloc()
,则将始终调用相应的free()
,而不是有时调用。你的代码有一些“气味”,所以如果有其他逻辑错误,我不会感到惊讶,但我会把它留在那里。好的,错误减少到1,我更新了问题。你能看看吗?这就是漏洞。在递归调用返回后释放depthPath
。我再次编辑,仍然有1个错误。好的,很难跟上您的编辑。在循环结束之前,将免费呼叫移动到if
之后。好的,非常感谢,它成功了。好的,错误减少到1,我更新了问题。你能看一下吗?
while ((dir = readdir(d)) != NULL)
{
if(((strcmp(dir->d_name,".")==0) ||
(strcmp(dir->d_name,".."))==0) )
{
continue;
}
char *depthPath= malloc(strlen(path) + strlen(dir->d_name) + 2);
strcpy(depthPath, path);
strcat(depthPath, "/");
strcat(depthPath, dir->d_name);
recursiveFoo(depthPath);
free(depthPath):
}