【问题标题】:Weird bug with fopen() modifying char array? [C language]fopen() 修改字符数组的奇怪错误? 【C语言】
【发布时间】:2015-07-12 19:46:13
【问题描述】:

所以main() 应该提取我当前目录中的所有文件名并将它们放入一个数组中,然后检查这些文件是否是常规文件。然后,它将所有常规文件传递到fun()

问题在于,即使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

非常奇怪的是,如果我删除fun() 中的fopen() 语句,那么就不会出错。难道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

【问题讨论】:

  • 在进一步的readdir() 电话之后,您不能挂在dir-&gt;d_name 上,当然也不能在closedir() 之后。您必须使用strdup() 或其他方式复制它。
  • 这一行:'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) 以确保操作成功。
  • 关于这一行:'exit(EXIT_FAILURE);'仅仅因为一个文件不能被“统计”,并不意味着其他文件不能被“统计”。建议解决这个问题的逻辑,而不是突然退出程序。强烈建议阅读有关“stat”的手册页 2
  • 'fun()' 函数(可怕/无意义的函数名)除了将一些垃圾回显到标准输出之外什么都不做。文件“text.txt”(以“附加”模式打开)什么也没有收到。参数:'arfile'未使用。
  • 建议使用调试器单步执行代码,这样您就可以看到哪里出了问题。另外,为什么还要在命令行上有一个参数呢?该参数从未真正使用过。

标签: c arrays char fopen


【解决方案1】:

readdir 是不可重新输入的函数——它持有临时静态缓冲区,每次迭代后都会被覆盖,因此dir-&gt;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]);
}

您还可以查看readdir_r 等可重新输入的函数,但它们对您的情况没有多大帮助。

【讨论】:

  • 哦,有道理!非常感谢,你又为我节省了两个小时
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 2014-03-08
相关资源
最近更新 更多