从文件中读取多行并转换为单行字符串的程序

时间:2017-11-17 04:44:13

标签: c

我正在尝试创建一个将文件路径作为命令行参数的C程序。我的程序然后逐行读取该文件,删除结束字符并将其添加到字符串,所以最后字符串是输入文件,但只在一行。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


int main(int argc, char **argv){

  FILE *input = fopen(argv[1], "r");
  char *line = NULL;
  char buffer[100];
  char temp[200];


  line = fgets(buffer, 100 *sizeof(char), input);

  while(line != NULL){
    line[strlen(line)-1] = '\0';
    strcat(temp, line); 
    line = fgets(buffer, 100 *sizeof(char), input);
  }

  printf("%s\n", temp);
  fclose(input);
}

我输入了一个包含数据的文件:

This is Line 1
line 2
line 3
and this is line 4

并期望字符串 This is Line 1line 2line 3and this is line 4

但确实如此 and this is line 1

感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

以下程序适合我。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


int main(int argc, char **argv){

  FILE *input = fopen(argv[1], "r");
  char *line = NULL;
  char buffer[100]={0};
  char temp[200]={0};


  line = fgets(buffer, 100 *sizeof(char), input);

  while(line != NULL){
      strcat(temp, line);     
      temp[strlen(temp)-1] = '\0';
      line = fgets(buffer, 100 *sizeof(char), input);
  }

  printf("%s\n", temp);
  fclose(input);
}

答案 1 :(得分:0)

您冒着未定义行为的风险(1)无法验证input实际上是为阅读打开的有效文件流,以及(2)未能跟踪存储的最大字符数temp允许存储的字符多于你有空间(你会因未能检查参数计数大于1而调用未定义的行为,但是参数向量fopen)末尾的 sentinel NULL只会导致argv失败 - - 但是因为你没有检查......)。

在查看可能的修复之前,让我们看看一些常规编码点。请勿在代码中使用幻数,例如fopen100

200

通过在每个源文件的开头定义常量,如果你需要随着时间的推移调整它们,你就不必去挑选每个声明,循环变量,测试子句等等。以确保你做了所有必要的修改。

在使用命令行参数之前,验证您的参数计数/* if use need constants, #define them or use an enum */ enum { BUFSZ = 100, TMPSZ = 200 }; int main (int argc, char **argv){ char buffer[BUFSZ] = "", /* read buffer */ temp[TMPSZ] = ""; /* buffer for combined lines */ ):

argc

从您打开的任何文件中读取之前:

    if (argc < 2 ) {   /* validate at least 1 argument given */
        fprintf (stderr, "error: insufficient input, usage: %s file\n", argv[0]);
        return 1;
    }

使用 if (!input) { /* validate file open for reading */ fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); return 1; } 阅读时,除非您放弃第一行,否则在输入fgets循环以读取文件之前无需单独的fgets

while

验证 while (fgets(buffer, BUFSZ, input)) { /* read each line */ ... } 中读取的最后一个字符是否为buffer个字符:

'\n'

现在要防止 Undefined Behavior 。您只有 size_t len = strlen (buffer); /* get length */ if (len && buffer[len - 1] == '\n') /* check if last is '\n' */ buffer[--len] = 0; /* overwrite with nul-char */ 个字符可用,如果您打算将TMPSZ用作字符串,则必须确保为 nul-terminatedating 字符{{1}留出空间}作为最后一个角色。 (temp相当于'\0'(零))。因此,检查长度,到目前为止存储的字符数,最多写入一个 '\0'中剩余的字符数,

0

如果你在上面的测试中没有到达temp的末尾,那么 if (TMPSZ <= nchr + len + 1) { /* room to fit in buffer? */ strncat (temp, buffer, TMPSZ - nchr - 1); /* only what fits */ nchr = TMPSZ - 1; /* nchr is max (+1 for nul-char) */ temp[nchr] = 0; /* affirmatively nul-terminate */ break; /* bail - all full */ } 将适合temp,所以只需复制它并更新总字符数:

buffer

那就是它。完全放在一起,您可以从作为第一个参数给出的文件中读取(或者如果没有给出参数,则默认来自temp)并将所有行组合成一行直到 strcat (temp, buffer); /* copy buffer to temp */ nchr += len; /* update nchr */ } 个字符,例如< / p>

stdin

示例使用/输出

TMPSZ - 1

TMPSZ = 20

的示例

让我们进行测试。我们设置#include <stdio.h> #include <string.h> /* if use need constants, #define them or use an enum */ enum { BUFSZ = 100, TMPSZ = 200 }; int main (int argc, char **argv){ char buffer[BUFSZ] = "", /* read buffer */ temp[TMPSZ] = ""; /* buffer for combined lines */ size_t nchr = 0; /* total character count */ FILE *input = argc > 1 ? fopen (argv[1], "r") : stdin; if (!input) { /* validate file open for reading */ fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); return 1; } while (fgets(buffer, BUFSZ, input)) { /* read each line */ size_t len = strlen (buffer); /* get length */ if (len && buffer[len - 1] == '\n') /* check if last is '\n' */ buffer[--len] = 0; /* overwrite with nul-char */ if (TMPSZ <= nchr + len + 1) { /* room to fit in buffer? */ strncat (temp, buffer, TMPSZ - nchr - 1); /* only what fits */ nchr = TMPSZ - 1; /* nchr is max (+1 for nul-char) */ temp[nchr] = 0; /* affirmatively nul-terminate */ break; /* bail - all full */ } strcat (temp, buffer); /* copy buffer to temp */ nchr += len; /* update nchr */ } if (input != stdin) fclose (input); /* close file if not stdin */ printf ("'%s'\n(%zu chars)\n", temp, nchr); /* output temp */ return 0; } 并验证我们的代码是否能够正确防止在$ ./bin/cmblines <dat/cmblines.txt 'This is Line 1line 2line 3and this is line 4' (44 chars) 结束后写作,

TMPSZ = 20

仔细看看,如果您有其他问题,请告诉我。