关于getline:在C语言中逐行浏览文本文件

Going through a text file line by line in C

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

1
2
3
4
5
6
7
8
9
10
11
12
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
"
, line);
      }
    return 1;
}

现在我用sscanf方法遇到段错误,我不确定为什么。 我是一个C菜鸟,只是想知道我是否缺少一些大图景。
谢谢


这么少的行就有这么多问题。我可能会忘记一些:

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

所以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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
, 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;
}


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

在代码中完全不能使用sscanf,因为您将filename用作格式字符串,以便从line读取为常量字符串文字%s

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


假设您要处理其他分隔符,例如\t选项卡,而不是
换行符。

一种更通用的定界符方法是使用getc(),它一次捕获一个字符。

请注意,getc()返回一个int,以便我们可以测试与EOF的相等性。

其次,我们定义类型为char的数组line[BUFFER_MAX_LENGTH],以便在堆栈上最多存储BUFFER_MAX_LENGTH-1个字符(我们必须将最后一个字符保存为\0终止符)。

使用数组避免了需要使用mallocfree在堆上创建正确长度的字符指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#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
"

                        "usage: %s textfile
"
, argv[0]);
         return EXIT_FAILURE;
    }

    if (!file) {
         fprintf(stderr,"error: could not open textfile: %s
"
, 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.
"
);
            return EXIT_FAILURE;
        }

        /* test character value */
        if (tempChar == EOF) {
            line[tempCharIdx] = '\0';
            fprintf(stdout,"%s
"
, line);
            break;
        }
        else if (tempChar == '
'
) {
            line[tempCharIdx] = '\0';
            tempCharIdx = 0U;
            fprintf(stdout,"%s
"
, line);
            continue;
        }
        else
            line[tempCharIdx++] = (char)tempChar;
    }

    return EXIT_SUCCESS;
}

如果必须使用char *,则仍然可以使用此代码,但是strdup() line[]数组一旦充满了一行的输入就可以使用。完成后,必须free此重复的字符串,否则会发生内存泄漏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#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;
    char *dynamicLine = NULL;

    if (argc == 2)
         file = fopen(argv[1],"r");
    else {
         fprintf(stderr,"error: wrong number of arguments
"

                        "usage: %s textfile
"
, argv[0]);
         return EXIT_FAILURE;
    }

    if (!file) {
         fprintf(stderr,"error: could not open textfile: %s
"
, argv[1]);
         return EXIT_FAILURE;
    }

    while(tempChar = fgetc(file))
    {
        /* avoid buffer overflow error */
        if (tempCharIdx == BUFFER_MAX_LENGTH) {
            fprintf(stderr,"error: line is too long. increase BUFFER_MAX_LENGTH.
"
);
            return EXIT_FAILURE;
        }

        /* test character value */
        if (tempChar == EOF) {
            line[tempCharIdx] = '\0';
            dynamicLine = strdup(line);
            fprintf(stdout,"%s
"
, dynamicLine);
            free(dynamicLine);
            dynamicLine = NULL;
            break;
        }
        else if (tempChar == '
'
) {
            line[tempCharIdx] = '\0';
            tempCharIdx = 0U;
            dynamicLine = strdup(line);
            fprintf(stdout,"%s
"
, dynamicLine);
            free(dynamicLine);
            dynamicLine = NULL;
            continue;
        }
        else
            line[tempCharIdx++] = (char)tempChar;
    }

    return EXIT_SUCCESS;
}


除了其他答案,在最新的C库(符合Posix 2008的情况)上,您可以使用getline。请参阅此答案(针对相关问题)。