【问题标题】:segmentation fault return a string array from a function分段错误从函数返回字符串数组
【发布时间】:2012-03-28 05:38:29
【问题描述】:

我创建了一个函数,它创建一个具有动态字符串长度的动态字符串数组,然后我将它返回给我的主函数。在我的函数中一切正常,但是当我尝试在 main 中打印数组时,我在第 4 个字符串之后出现分段错误 - 前两个字符串也打印不正确。这部分程序应该找出目录及其子目录中的所有条目并将它们存储在主内存中。

结果如下:

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

这是代码: 功能:

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);
}

主要:

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 是一个全局变量

我只是不知道出了什么问题,我想我正确地使用了 return 命令。我还尝试了将路径作为全局变量的相同代码,它运行良好(主要打印出正确的结果)。 我觉得这与我的函数的递归调用有关

【问题讨论】:

  • 请把它归结为一个简单测试用例(不超过10-15行)。见sscce.org
  • 很好找到了。这真的是我的函数的递归调用我改变了这个:getDirContents(tmpName,paths);//子文件夹到那个:paths=getDirContents(tmpName,paths);//子文件夹现在可以正常工作了

标签: c arrays string function segmentation-fault


【解决方案1】:

您的代码有一个未定义的行为

你调用函数为:

A=getDirContents(dir1,NULL);

函数定义为:

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

您还可以在paths 上致电realloc

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

这会导致未定义的行为。

标准要求传递给 realloc 的指针应该与使用内存管理函数分配动态内存的指针完全匹配。标准规定的内存管理功能有: aligned_alloccallocmallocrealloc

您传递给realloc() 的指针(paths) 未由其中任何一个返回,因此未定义行为。

【讨论】:

  • 我不明白为什么它是未定义的,我把这个getDirContents(tmpName,paths);//子文件夹改为paths=getDirContents(tmpName,paths);//子文件夹它仍然是未定义的行为吗? main 调用中的 NULL 参数是否存在问题?在路径上调用 realloc 有什么问题?
  • 哦,我想我明白你的意思了
  • 等等,什么?使用NULL 指针调用realloc 是明确定义的行为:C11, 7.22.3.5/3, "如果ptr 是空指针,则realloc 函数的行为类似于malloc 函数指定的大小。”
【解决方案2】:

您的问题是,根据标准,您的 realloc 调用可能(并且可能会)返回指向不同于原始内存位置的指针

这是一个棘手的问题,并且有点难以解释和形象化,但我会尽力而为。

当你最初调用你的函数时,它会创建一个新的堆栈帧(我们称之为A)。它将paths 分配给一个地址(比如0x01),用它做一些事情,然后函数以paths 地址作为参数递归调用自身。

当你递归调用你的函数时,它会创建一个新的堆栈帧(我们称之为B),你在其中realloc paths 指针 - 它的地址从0x01 更改为0x02 -用它做一些事情,然后返回它。

但是当B 返回时,A 中的paths 指针仍指向旧位置0x01,即使它不再有效并已移至0x02

解决方案很简单,确保在递归调用结束时将paths 指向新位置。所以而不是:

getDirContents(tmpName,paths); //Subfolder

...你会这样做:

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

另外,请务必检查reallocmalloc(针对NULL)和don't cast the return value of malloc 的返回值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 2013-03-25
    • 2014-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多