使用fgets将行复制到字符串数组中?

我有一个我正在尝试编写的C程序,它打算反转文件的行。 我仍然非常擅长C(虽然我来自Java背景),所以我很可能用指针等犯错误,但我已经尝试过每一次都在查阅手册。 这有点任务。

程序的要点是反转文件的内容,数量最多为MAX_LINES,每行不超过MAX_CHARS。 我想尝试的方法如下:使用fgets从文件读取,80个字符或直到EOL,存储该字符串,并重复该过程,直到达到EOF或MAX_LINES,使用侧面的计数器。 之后我只是将相同的字符串放在不同的数组中,从second_array [counter]变为0.但是,我遇到了将字符串实际放入第一个数组的问题。 这是我到目前为止所拥有的:

1 #include  2 #include  3 4 #define MAX_LINES 100 5 #define MAX_CHAR 80 6 7 int main(int argc, char *argv[]) 8 { 9 if(argc != 2) 10 goto out; 11 FILE *fp; 12 char *str[MAX_CHAR]; 13 char buffer[MAX_CHAR]; 14 char *revstr[MAX_CHAR]; 15 int curr_line = 0, i = 0, j =0; 16 17 fp = fopen(argv[1],"r"); 18 19 out: 20 if (fp == NULL && argc != 2){ 21 printf("File cannot be found or read failed.\n"); 22 return -1; 23 } 24 25 /* printf("This part of the program reverses the input text file, up to a maximum of 100 lines and 80 characters per line.\n The reversed file, from the last (or 100th) line to the first, is the following:\n\n"); */ 26 27 /* fgets reads one line at a time, until 80 chars, EOL or EOF */ 28 while(curr_line < MAX_LINES && ((fgets(buffer, MAX_CHAR, fp)) != NULL)){ 29 30 str[i] = buffer; 31 ++j; 32 ++i; 33 } 34 35 for(i = 0; i < 4; ++i) 36 printf("%s \n", str[i]); 37 38 39 printf("END OF PROGRAM RUN."); 40 return 0; 41 } 

在同一目录中,我有一个“txt”文件,其中包含以下行:

 is this a test this is a test this is not a test 

当我编译并运行程序(./a.out txt)时,我得到以下输出:

 this is not a test this is not a test this is not a test END OF PROGRAM RUN. 

显然这意味着覆盖了同一个位置,但我不确定如何纠正这个问题(如上所述,指针对我来说仍然很陌生)。 谁能澄清这里发生了什么? 我需要使用2Darrays吗? 任何帮助将不胜感激。

滥用buffer

麻烦的是你继续将指针buffer存储在str[i] ,但buffer只包含最后一行读取。

你必须复制读取的行,也许使用strdup()

 str[i++] = strdup(buffer); 

需要担心错误检查,但从概念上讲,这是处理它的一种简单方法。

你能澄清一下为什么会这样吗? fgets()的声明是char *fgets() ,我得到的印象是它暂时返回指向当前从文件中读取的行的指针!

实际上, fgets()返回两个值之一:

  • EOF或其他I / O错误上的NULL,或
  • buffer ,指向传递给函数的字符串的指针。

特别是,它不会自动为您创建新的存储空间。 如果你想要,你可能需要从POSIX查看readline()

因此,对fgets()调用每次都使用相同的数组, buffer ,以便每个连续的行读取覆盖前一行。 这就是为什么你需要以某种方式复制每一行,以及为什么我建议使用strdup()作为一种简单的方法。


的strdup()

函数strdup()是POSIX的一部分,但不是标准的C.但是,它很容易实现:

 char *strdup(const char *str) { size_t len = strlen(str) + 1; char *dup = malloc(len); if (dup != 0) memmove(dup, str, len); return(dup); } 

错误报告

您应尽可能避免使用goto ,这可以通过此代码轻松完成。 您的双重用途错误消息实际上最终会使省略参数的用户感到困惑,或者提供的参数太多。 提供两个单独的错误消息,一个用于程序的参数数量不正确,另一个用于无法打开文件。

 if (argc != 2) { fprintf(stderr, "Usage: %s file\n", argv[0]); exit(1); } fp = fopen(argv[1], "r"); if (fp == 0) { fprintf(stderr, "%s: failed to open file %s (%d: %s)\n", argv[0], argv[1], errno, strerror(errno)); exit(1); } 

请注意,应该在stderr上报告stderr ,而不是stdout ; 这就是错误输出通道的用途。

在您的代码中,您正在使str数组的每个索引指向相同的数组缓冲区。 这就是为什么你在str数组中得到evey索引的相同值(缓冲区中的值)的原因。 你可以像这样使用数组代码

 #define MAX_LINES 100 #define MAX_CHAR 80 int main(int argc, char *argv[]) { if(argc != 2) goto out; FILE *fp; char str[MAX_LINES][MAX_CHAR]; char buffer[MAX_CHAR]; char *revstr[MAX_CHAR]; int curr_line = 0, i = 0, j =0; fp = fopen(argv[1],"r"); out: if (fp == NULL && argc != 2){ printf("File cannot be found or read failed.\n"); return -1; } /* printf("This part of the program reverses the input text file, up to a maximum of 100 lines and 80 characters per line.\n The reversed file, from the last (or 100th) line to the first, is the following:\n\n"); */ /* fgets reads one line at a time, until 80 chars, EOL or EOF */ while(curr_line < MAX_LINES && ((fgets(buffer, MAX_CHAR, fp)) != NULL)){ //str[i] = buffer; memcpy(str[i], buffer, strlen(buffer)); curr_line++; ++j; ++i; } for(i = 0; i < 4; ++i) printf("%s \n", str[i]); printf("END OF PROGRAM RUN."); return 0; } 

您也没有修改变量currn_line