在C中逐行浏览文本文件

时间:2012-02-09 05:57:37

标签: c getline scanf

我一直在为我的CIS类做一个小练习,并且对C用于从文件中读取的方法感到困惑。我真正需要做的就是逐行读取文件并使用从每行收集的信息进行一些操作。我尝试使用getline方法和其他没有运气的方法。 我的代码目前如下:

int main(char *argc, char* argv[]){
      const char *filename = argv[0];
      FILE *file = fopen(filename, "r");
      char *line = NULL;

      while(!feof(file)){
        sscanf(line, filename, "%s");
        printf("%s\n", line);
      }
    return 1;
}

现在我正在使用sscanf方法获得seg错误,我不知道为什么。我是一名C总裁,只是想知道是否有一些我失踪的大事。 感谢

4 个答案:

答案 0 :(得分:118)

这么几行中出现了很多问题。我可能会忘记一些:

  • argv [0]是程序名,而不是第一个参数;
  • 如果要读取变量,则必须分配其内存
  • 一个永远不会在feof上循环,一个循环在IO函数上直到它失败,然后feof用于确定失败的原因,
  • sscanf用于解析一行,如果要解析文件,请使用fscanf,
  • “%s”将在第一个空格处停止,作为?scanf系列的格式
  • 读取一行,标准函数是fgets,
  • 从主要方式返回1意味着失败

所以

#include <stdio.h>

int main(int argc, char* argv[])
{
    char const* const fileName = argv[1]; /* should check that argc > 1 */
    FILE* file = fopen(fileName, "r"); /* should check the result */
    char line[256];

    while (fgets(line, sizeof(line), file)) {
        /* note that fgets don't strip the terminating \n, checking its
           presence would allow to handle lines longer that sizeof(line) */
        printf("%s", line); 
    }
    /* may check feof here to make a difference between eof and io failure -- network
       timeout for instance */

    fclose(file);

    return 0;
}

答案 1 :(得分:7)

要从文件中读取一行,您应该使用fgets函数:它从指定文件中读取一个字符串,直到换行符或EOF

在您的代码中使用sscanf根本不起作用,因为您使用filename作为格式字符串,以便从line读取到常量字符串文字%s

SEGV的原因是你写入line指向的未分配内存。

答案 2 :(得分:5)

假设您正在处理其他分隔符,例如\t标签,而不是\n换行符。

分隔符的更通用的方法是使用getc(),它一次抓取一个字符。

请注意,getc()会返回int,以便我们可以使用EOF测试相等性。

其次,我们定义类型为line[BUFFER_MAX_LENGTH]的数组char,以便在堆栈中存储最多BUFFER_MAX_LENGTH-1个字符(我们必须保存{{1}的最后一个字符终结者角色)。

使用数组可以避免使用\0malloc在堆上创建正确长度的字符指针。

free

如果您必须使用#define BUFFER_MAX_LENGTH 1024 int main(int argc, char* argv[]) { FILE *file = NULL; char line[BUFFER_MAX_LENGTH]; int tempChar; unsigned int tempCharIdx = 0U; if (argc == 2) file = fopen(argv[1], "r"); else { fprintf(stderr, "error: wrong number of arguments\n" "usage: %s textfile\n", argv[0]); return EXIT_FAILURE; } if (!file) { fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); return EXIT_FAILURE; } /* get a character from the file pointer */ while(tempChar = fgetc(file)) { /* avoid buffer overflow error */ if (tempCharIdx == BUFFER_MAX_LENGTH) { fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); return EXIT_FAILURE; } /* test character value */ if (tempChar == EOF) { line[tempCharIdx] = '\0'; fprintf(stdout, "%s\n", line); break; } else if (tempChar == '\n') { line[tempCharIdx] = '\0'; tempCharIdx = 0U; fprintf(stdout, "%s\n", line); continue; } else line[tempCharIdx++] = (char)tempChar; } return EXIT_SUCCESS; } ,那么您仍然可以使用此代码,但只有char *数组填充了一行的输入后,您才能使用strdup()数组。一旦完成,你必须line[]这个重复的字符串,否则你会得到内存泄漏:

free

答案 3 :(得分:4)

除了其他答案之外,在最近的C库(Posix 2008兼容)上,您可以使用getline。请参阅this answer(相关问题)。