简体   繁体   English

segmentation fault从函数返回一个字符串数组

[英]segmentation fault return a string array from a function

I have created a function that creates a dynamic string array with dynamic string length and then I return it to my main function. 我创建了一个函数,创建一个动态字符串数组,动态字符串长度然后我将它返回到我的主函数。 Everything works fine inside my function but when I try to print the array in main I get a segmentation fault after the 4th string - first two string don't print out correct either. 在我的函数中一切正常但是当我尝试在main中打印数组时,我在第4个字符串之后得到了一个分段错误 - 前两个字符串也没有正确打印出来。 This part of the program is supposed to find out all entries in a directory and its sub-directories and store them in main memory. 程序的这一部分应该找出目录及其子目录中的所有条目并将它们存储在主存储器中。

Here's the result: 这是结果:

Path[0]=A/New Folder. - i=0
Path[1]=A/atext - i=1
Path[2]=A/a - i=2
Path[3]=A/alink - i=3
Path[4]=A/afolder - i=4
Path[5]=A/afolder/set008.pdf - i=0
Path[6]=A/afolder/anotherfolder - i=1
Path[7]=A/afolder/anotherfolder/folderOfAnotherFolder - i=0
Path[8]=A/afolder/anotherfolder/folderOfAnotherFolder/mytext - i=0
Path[9]=A/afolder/anotherfolder/mytext - i=1
Path[10]=A/afolder/set001.pdf - i=2
Entries in directory: A
��
��
A/a
A/alink
Segmentation fault

And here's the code: function: 这是代码:功能:

char ** getDirContents(char *dirName,char **paths ) 
{   
    DIR * tmpDir;
    struct dirent * entry;
    //char  tmpName[512];
    char * tmpName=NULL;
    struct stat node;
    int size=0;
    int i=0;
    //paths=NULL;

    if((tmpDir=opendir(dirName))==NULL){
        perror("getDirContents opendir"); 
        return NULL;
    }
    i=0;
    while ((entry=readdir(tmpDir))!=NULL) 
    {
        //if (entry->d_ino==0) continue;
        if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)//Ignore root & parent directories
            continue;but I

        tmpName =(char *)malloc(strlen(dirName)+strlen(entry->d_name)+2);
        strcpy(tmpName,dirName);
        strcat(tmpName,"/");
        strcat(tmpName,entry->d_name);
        //printf("\ntmpName[%d]:%s",count,tmpName);

        paths=(char**)realloc(paths,sizeof(char*)*(count+1));
        paths[count]=NULL;
        //paths[count]=(char*)realloc(paths[count],strlen(tmpName)+1);
        paths[count]=(char*)malloc(strlen(tmpName)+1);

        //memcpy(paths[count],tmpName,strlen(tmpName)+1);
        strcpy(paths[count],tmpName);
        printf("\nPath[%d]=%s - i=%d",count,paths[count],i);

        count++;

        if(lstat(tmpName,&node)<0)    
            { 
                printf("\ntmpName:%s",tmpName);
                perror("getDirContents Stat");
                exit(0);
            }
        if (S_ISDIR(node.st_mode))
            {
                getDirContents(tmpName,paths);//Subfolder
            }

        //printf("\n%s,iters:%d",tmpName,i);
        free(tmpName);
        tmpName=NULL;
        i++;
    }
close(tmpDir);
return(paths);
}

main: 主要:

char **A=NULL;
count=0;
A=getDirContents(dir1,NULL);
Aentries=count;
count=0;
//B=getDirContents(dir2,NULL);
printf("\nEntries in directory: %s",dir1);
for(i=0;i<Aentries;i++)
{
     printf("\n%s",A[i]);
}

count is a global variable count是一个全局变量

I just can't figure out what is wrong I think I use the return command properly. 我只是无法弄清楚出了什么问题我认为我正确地使用了return命令。 I also tried the same code with paths as a global variable and it worked fine (main printed out the correct results). 我也尝试使用路径作为全局变量的相同代码,它工作正常(主打印出正确的结果)。 I have a feeling it has something to do with the recursive call of my function 我觉得它与我的函数的递归调用有关

Your problem is that, as per the standard, your realloc call may (and probably will) return a pointer to a different memory location than the original . 您的问题是, 根据标准,您的realloc调用可能(并且可能会)返回指向与原始内存位置不同的内存位置的指针

It's a tricky one, and it's a little hard to explain and visualize, but I'll do my best. 这是一个棘手的问题,它有点难以解释和想象,但我会尽我所能。

When you call your function originally, it creates a new stack frame (let's call it A ). 当你最初调用你的函数时,它会创建一个新的堆栈帧(让我们称之为A )。 It allocates paths to an address (say 0x01 ), do some stuff with it, then the function calls itself recursively with the paths address as an argument. 它分配一个地址的paths (比如0x01 ),用它做一些东西,然后函数以paths地址作为参数递归地调用它自己。

When you call your function recursively, it creates a new stack frame (let's call it B ), in which you realloc the paths pointer - which changes its address from 0x01 to 0x02 - do some stuff with it, and then return it. 当您递归调用你的函数,它会创建一个新的堆栈帧(我们称之为B ),在您reallocpaths指针-这改变了从地址0x010x02 -做一些东西吧,然后返回。

But when B returns, the paths pointer in A still point to the old location, 0x01 , even though it's not valid anymore and has been moved to 0x02 . 但是当B返回时, Apaths指针仍然指向旧位置0x01 ,即使它已经无效并且已经移动到0x02

The solution is simple, make sure that you point paths to the new location when the recursive call ends . 解决方案很简单, 确保在递归调用结束时将paths指向新位置 So instead of: 所以代替:

getDirContents(tmpName,paths); //Subfolder

...you'd do: ......你做的:

paths = getDirContents(tmpName,paths); //Subfolder

Also, make sure you check the return value of realloc and malloc (against NULL ), and don't cast the return value of malloc . 另外,请确保检查reallocmalloc的返回值(反对NULL ),并且不要malloc的返回值

Your code has an Undefined Behavior . 您的代码具有未定义的行为

You call the function as: 您将该函数称为:

A=getDirContents(dir1,NULL);

and the function is defined as: 并且该功能定义为:

char ** getDirContents(char *dirName,char **paths ) 

Further you call realloc on paths . 此外,您在paths上调用realloc

paths=(char**)realloc(paths,sizeof(char*)*(count+1));

This causes Undefined Behavior. 这会导致未定义的行为。

The standard mandates that the pointer being passed to realloc should exactly match the pointer which was allocated dynamic memory using a memory management function. 标准要求传递给realloc的指针应该与使用内存管理功能分配动态内存的指针完全匹配。 Memory management functions specified by the standard are: aligned_alloc , calloc , malloc , and realloc . 标准指定的内存管理函数有: aligned_alloccallocmallocrealloc

The pointer( paths ) you are passing to realloc() was not returned by any of these and hence the Undefined Behavior. 您传递给realloc()的指针( paths )未被任何这些指针( paths )返回,因此未返回未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM