Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言的递归函数中使用free()函数_C_Recursion - Fatal编程技术网

在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):
    }