我在C程序(GNU on cygwin)中使用opendir/readdir
從一些嵌套目錄中將文件名收集到字符串數組中(該程序主要使用C89及更早版本的約定) 。由於我不知道文件的數量,我決定使用malloc/realloc
來執行動態內存分配。一個指針數組通過遞歸調用來收集文件名。問題是在以後的存儲步驟中早期調用getlist()
時存儲的文件名被損壞。在進入子目錄後,執行第二次調用realloc
並從子目錄出現,執行realloc
之後的存儲位於邊緣的字符串逐漸損壞,因爲在父目錄中收集了額外的文件名。realloc在遞歸存儲目錄/文件名期間咀嚼字符串數組
如果我使用單個malloc
賦值來分配內存來創建一個較大的初始指針數組,我避免了這個問題,但我希望能夠使用realloc
。任何人都可以指出我做錯了什麼,特別是我猜這是我在這種情況下如何使用realloc
?
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
// function prototypes
char ** getlist(char ** filelist,long int *numfiles,char *dirname);
extern int stat (const char *filename, struct stat *buf);
extern DIR * opendir (const char *_dirname);
extern struct dirent * readdir (DIR *dirstream);
int main(int narg, char* argv[])
{
// vars
char * dirname;
char **filelist, **traverse;
long int numfiles =0;
FILE* pfile;
//....................................
// and go ...
if ((filelist = (char **)malloc(sizeof(char *))) == NULL)
{
printf("Fatal malloc error!\n");
exit(3);
}
filelist = getlist(filelist,&numfiles,argv[1]); // argv[1] is dir name
// list the stored filenames and write to file
pfile = fopen("listoutput.txt","w");
printf("Stored filenames (N=%i):\n",numfiles);
traverse = filelist;
while(*traverse)
{
printf("%s\n",*traverse);
fprintf(pfile,"%s\n",*traverse);
traverse++;
}
fclose(pfile);
// free etc should go here...
return 0 ;
}
//-------------------------------------------------------------------------------
char ** getlist(char** filelist, long int *numfiles, char* dirname)
{
// variables
char filename[200];
char dirname_[200];
DIR * directory;
struct dirent * file;
strcpy(dirname_,dirname);
// for checking file type
// macro: int S_ISREG (mode_t m)
struct stat* filestat = malloc(sizeof(struct stat));
int sizeofchar = sizeof(char); // fields: mode_t st_mode, unsigned char d_namlen
char **traverse, **ptemp;
//aux
long int ii, icheck;
// check number of valid files in dirname and allocate memory in char pointer array
ii=0;
directory = opendir (dirname_);
while(file = readdir(directory))
{
sprintf(filename,"%s/%s",_dirname_,file->d_name);
icheck = stat(filename,filestat);
if (icheck==0)
{
if (S_ISREG(filestat->st_mode)) ii++;
}
else
{
printf("Couldn't check file type of file \"%s\" (icheck = %i)\n", filename, icheck);
}
}
// generate enough room for all the filename strings
if ((filelist=(char **)realloc(filelist,sizeof(char *)*(*numfiles+ii+1))) == NULL)
{
printf("Fatal realloc error!\n");
exit(3);
}
traverse = filelist + *numfiles;
// now store the filenames in filelist ...
(void) rewinddir (directory);
while(file = readdir(directory))
{
sprintf(filename,"%s/%s",dirname_,file->d_name);
icheck = stat(filename,filestat);
if (icheck==0 && S_ISREG(filestat->st_mode))
{
*traverse = (char *)malloc(sizeofchar*(strlen(filename)+1));
strcpy(*traverse,filename);
traverse++;
(*numfiles)++;
// spit out what we have so far
printf("\nCurrent list (looping):\n-----------\n");
ptemp = filelist;
ii=*numfiles;
while(ii--)
{
printf("%s\n",*ptemp);
ptemp++;
}
printf("\n-----------\n");
//sleep(1);
}
else if (icheck==0 && S_ISDIR(filestat->st_mode))
{
if (strcmp(file->d_name,".")!=0 && strcmp(file->d_name,"..")!=0)
{
printf("Processing folder %s\n", filename);
filelist = getlist(filelist,numfiles,filename);
traverse = filelist + *numfiles;
// spit out what we have so far
printf("\nCurrent list (returned from getlist):\n-----------\n");
ptemp = filelist;
while(*ptemp)
{
printf("%s\n",*ptemp);
ptemp++;
}
printf("\n-----------\n");
}
}
}
(void) closedir (directory);
*traverse = NULL;
return filelist;
}
想法:代碼省略了各種錯誤檢查 - 也許是在趕上這段代碼。檢查'malloc/realloc'返回。確保'sprintf(文件名,「%s /%s」,_ dirname,file-> d_name);'具有足夠的大小等等。另外,在動態系統中,目錄的重新掃描可能會比第一次更有效。建議檢查文件名列表的大小是否足夠。也可能要填零分配的內存。 – chux 2014-10-18 22:35:23
順便說一下,模式'ptr = realloc(ptr,...)'是一個非常糟糕的做法。如果'realloc'失敗,您將無法訪問原始指針並泄漏相關內存。 Google對於「realloc內存泄漏」的原因有很多。 – 2014-10-18 23:20:19
@chux,到目前爲止沒有任何改進,將繼續小打小鬧。可能會嘗試執行兩次dir搜索,第一次在單個malloc之前收集文件名的總數。 – 2014-10-18 23:29:48