2015-07-12 1 views
0

Таким образом, main() должен извлечь все имена файлов в моем текущем каталоге и поместить их в массив, а затем проверить, являются ли файлы обычными файлами. Затем он передает все обычные файлы в fun().Странная ошибка с изменением массива char fopen()? [C language]

Проблема заключается в том, что, несмотря на то, main() проходит в действительный массив, некоторые элементы массива (не все из них) удаляются после того, как он передается в fun()

//Output of command line before array is passed into fun() 
reg 0: a.out 
reg 1: myar 
reg 2: proj2.tex 
reg 3: myar.c 
reg 4: ar 
reg 5: makefile 
reg 6: new.c 
reg 7: newfile.txt 
reg 8: newar 

//Output of command line after passed into fun() 
reg 0: 
reg 1: 
reg 2: 
reg 3: myar.c 
reg 4: 
reg 5: 
reg 6: 
reg 7: newfile.txt 
reg 8: newar 

Крайне странно, что , если я удалю оператор fopen() в fun(), тогда ничего не получится. Может ли быть так, что fopen() что-то менять не должно? Код приведен ниже:

1 #include <stdio.h> 
    2 #include <stdlib.h> 
    3 #include <dirent.h> 
    4 #include <sys/stat.h> 
    5 
    6 void fun(char* arfile, char** filenames, int file_count) 
    7 { 
    8  int i; 
    9  FILE* f = fopen("text.txt", "a"); 
10 
11  for (i=0;i<file_count;i++){ 
12   printf("reg %d: %s\n",i,filenames[i]); 
13   fflush(stdout); 
14  } 
15 
16  fclose(f); 
17 } 
18 
19 
20 int main (int argc, char** argv) 
21 { 
22  struct stat s; 
23  DIR *d; 
24  struct dirent *dir; 
25  int i, file_count = 0, reg_count = 0; 
26  char **filenames, **regular_files; 
27  char *arfile; 
28 
29  if (argc != 2) 
30   exit(EXIT_FAILURE); 
31  else 
32   arfile = argv[1]; 
33 
34  d = opendir("."); 
35 
36  while ((dir = readdir(d)) != NULL){ 
37   file_count++; 
38  } 
39 
40  closedir(d); 
41  filenames  = malloc(file_count*sizeof(char*)); 
42  regular_files = malloc(file_count*sizeof(char*)); 
43 
44  d = opendir("."); 
45 
46  for (i = 0; (dir = readdir(d)) != NULL; i++){ 
47   filenames[i] = dir->d_name; 
48  } 
49 
50  closedir(d); 
51 
52  for (i = 2; i < file_count ; i++){ 
53   if (stat(filenames[i], &s) == -1) { 
54    perror("Unable to read file stats"); 
55    exit(EXIT_FAILURE); 
56   } 
57 
58   if (S_ISREG(s.st_mode)){ 
59    regular_files[reg_count] = filenames[i]; 
60    reg_count++; 
61   } 

62  } 
63 
64  for (i=0;i<reg_count;i++){ 
65   printf("reg %d: %s\n",i,regular_files[i]); 
66   fflush(stdout); 
67  } 
68  fun(arfile, regular_files, reg_count); 
69 
70  free(filenames); 
71  free(regular_files); 
72  return 0; 
73 } 
74 
+1

Вы не можете висеть на 'dir-> d_name' после дополнительных' readdir() 'вызовов и, конечно, не после' closedir() '. Вам придется скопировать его с помощью 'strdup()' или что-то еще. –

+0

Эта строка: 'filenames [i] = dir-> d_name;' имеет две проблемы: 1) это не будет копировать имя, а только адрес dir-> d_name. предложите strcpy (имена файлов [i], dir-> d_name); 2) malloc() выделил только массив указателей на char. Каждые имена файлов [i] фактически нигде не указаны. (следует инициализировать их для всех NULL, чтобы сделать бесплатные вызовы free()): filenames [i] = malloc (strlen (dir-> d_name) +1); Конечно, каждый вызов malloc должен сопровождаться проверкой (! = NULL), чтобы убедиться, что операция прошла успешно. – user3629249

+0

относительно этой строки: 'exit (EXIT_FAILURE);' Просто потому, что один файл не может быть «stat'ed», не означает, что другие файлы не могут быть «stat'ed». Предложите логику обойти эту проблему, а не внезапно выйти из программы. Строго рекомендуем прочитать man page 2 относительно 'stat' – user3629249

ответ

1

readdir не является reenterable функция - она ​​имеет временный статический буфер, который перезаписаны после каждой итерации, так что данные, указанные на dir->d_name становится недействительным. Вы должны скопировать их, то есть с strdup():

for (i = 0; (dir = readdir(d)) != NULL; i++) {  
    filenames[i] = strdup(dir->d_name); 
} 

И не забудьте освободить выделенные строки:

for (i = 0; i < file_count; i++) {  
    free(filenames[i]); 
} 

Вы также можете посмотреть на reenterable функции как readdir_r, но они не очень полезны в твоем случае.

+0

О, это имеет смысл! Большое спасибо, вы просто спасли меня еще два часа – loukouk