在C中逐行读取txt文件

Read txt file line by line in C

我想逐行读取一个 txt 文件,每行存储在不同的变量中: 这是我要阅读的txt文件

Jenny
Woodbridge Ave 
Amber
Exeter street
Michael
Main Street
David
Plainfield ave

我确实喜欢


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

typedef struct info
{
   char name[20];
   char add[50];
}INFO;

int main(void){
    const char *fileName = "test.txt";
    FILE *file = fopen(fileName, "r");
    INFO* list = (INFO*)malloc(20*sizeof(INFO));


    readFromFile(file,list);
    fclose(file);
    free(list);
   return 0;
}
void readFromFile(FILE *file,INFO* list){
     int i = 0;
     while(!feof(file)){
      fscanf(file,"%s %s\n ",(list+i)->name,(list+i)->adds);
      i++;
     }
}

但我得到

Name:           Jenny
Addr:   Woodbridge
------------------------------
Name:           Ave
Addr:   Amber
------------------------------
Name:           Exeter
Addr:   street
------------------------------
Name:           Michael
Addr:   Main
------------------------------
Name:           Street
Addr:   David
------------------------------
Name:           Plainfield
Addr:   ave

我只是编辑了一点 所以我需要使用 fgets 逐行读取而不是 fscanf() 对吗?

%s 说明符读取输入流,直到找到一个空白字符,在您的情况下,每个地址有 2 个字,一旦您尝试读取它,它就会变得不平衡,第二个字地址被下一个周期读入name,也存在潜在的缓冲区溢出问题

你应该使用 %49[^\n],这个说明符会读取所有内容,直到找到换行符,包括 spaces。 49 是为了限制读取行的大小以避免提到的缓冲区溢出,在你的情况下你有 space 用于 50 个字符,最后一个字符将用于 null终结者。

feof 也不是在这种例程中发出文件结束信号的最佳方式,更多信息在 Why is “while ( !feof (file) )” always wrong?.

我在对以下工作示例的评论中解决了一些其他问题:

Online demo

int main()
{
    //casting malloc may make you program fail, it hides the lack of #include <stdlib.h>
    INFO* list = malloc(20 * sizeof *list); //using the the dereferenced variable 
                                            //is safer regarding future code refactoring
    const char *fileName = "test.txt";
    FILE *f = fopen(fileName, "r"); //dont forget to verify the return of fopen
    int i = read(f, list);

    for (int j = 0; j < i; j++) //test print
    {
        printf("Name: %s    Address: %s\n", list[j].name, list[j].add);
    }
}
int read(FILE *file, INFO *list)
{
    int i = 0;
    //use scanf as stop condition, [] notation is easier to read
    //limiting the size in scanf specifiers avoids buffer overflow
    while (fscanf(file, "%19s %49[^\n]", list[i].name, list[i].add) == 2)
    {
        i++;
    }
    //return i so that you know how many structs were read
    return i;
}

输出:

Name: Jenny    Address: Woodbridge Ave 
Name: Amber    Address: Exeter street
Name: Michael    Address: Main Street
Name: David    Address: Plainfield ave

so I need to use fgets to read line by line instead of fscanf() right?

fscanf(file,"%s %s\n ",.... 失败,因为 %s 没有根据 "Woodbridge Ave" 的需要将空格读入字符串,并且无法防止缓冲区溢出。

有很多方法可以解决这个任务。 fgets()最清楚

考虑一个辅助函数来读取一行并处理 fgets() 行输入的特性。根据需要进行调整。

// return 1 on success
// return EOF on end-of-file/input error
// else return 0
int read_line(FILE *file, int sz, char *line) {
  if (fgets(line, sz, file) == NULL) {
    return EOF; // EOF or rare input error
  }
  int len = strlen(line);
  if (len > 0 && line[len - 1] == '\n') {
    line[--len] = '[=10=]'; // lop off potential \n
  } else if (len + 1 == sz) { // no \n read, `line` full, so look for rest of input
    int ch;
    int extra = 0;
    while ((ch = fgetc(file)) != '\n' && ch != EOF) {
      extra = 1;
    }
    if (extra) {
      return 0;  // input too long
    }
  }
  return 1;
}

现在将文件以行对的形式读入INFO

int read_INFO(FILE *file, int n, INFO *list) {
  int i = 0;
  while (i < n 
      && read_line(file, sizeof list->name, list[i].name) == 1
      && read_line(file, sizeof list->add, list[i].add) == 1) {
    i++;
  }
  return i;
}

用法

  int n = 20;
  INFO *list = malloc(sizeof *list * n);
  if (list) {
    int number_read = read_INFO(file, n, list);
    if (number_read > 0) {
      // The happy path
    }
  }