【问题标题】:Using fgets() and strtok() to read in a file line-by-line in C?使用 fgets() 和 strtok() 在 C 中逐行读取文件?
【发布时间】:2012-09-19 16:46:12
【问题描述】:

我正在尝试使用 fgets 和 strtok() 逐行读取文件,并创建每个不同信息行的链接列表。

现在,我只是将信息放入一个数组中,只是想弄清楚如何正确读取信息,但它不能正常工作。

在 while(fgets) 部分,它似乎正确地将所有内容加载到数组中,并打印出来。然而,在该循环执行后,我尝试打印出整个数组,我得到了非常奇怪的结果。这主要是最后一行的一部分,而不是完整的单词或大部分内容。

例如,如果我正在阅读:

Simpson, Homer, Male, 1976
Simpson, Marge, Female, 1978
Simpson, Bart, Male, 2002 
Simpson, Lisa, Female, 2004 
Simpson, Maggie, Female, 2011 

我最后得到的打印输出是这样的:

le
Simpson
 Maggie


Simpson
 Maggie
e
ale
Simpson
 Maggie
e
e
Simpson
 Maggie
 Female
 2011

请告诉我哪里出错了,谢谢!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRINGSIZE 10
#define LINESIZE 128

struct person{
    char firstName[MAXSTRINGSIZE];
    char lastName[MAXSTRINGSIZE];
    char gender[MAXSTRINGSIZE];
    int birthYear;
    struct person *next;
} *first, *current;


int main (void){
    static const char filename[] = "Assignment1file.txt";
    FILE *myfile = fopen ( "Assignment1file.txt", "r" );

    int i=0;
    int j=0;
    int k=0;
    int l=0;
    char *result[10][4];
    char line[LINESIZE];
    char *value;

    for(i=0; i<9; i++){
        for(j=0;j<4;j++){
            result[i][j] = NULL;
        }
    }
    i=0;

    // loop through each entry in Assignment1file
    while(fgets(line, sizeof(line), myfile)){

        //load last name
        value = strtok(line, ",");
        result[i][0] = value;
        printf("%i 0 %s", i, value);


        //load first time
        value = strtok(NULL, ",");
        result[i][1] = value;
        printf("%i 1 %s", i, value);

        // load gender
        value = strtok(NULL, ",");
        result[i][2] = value;
        printf("%i 2 %s", i, value);

        // load birth year
        value = strtok(NULL, "\n");
        result[i][3] = value;
        printf("%i 3 %s", i, value);
        printf("\n");

        for(j=0;j<4;j++){
            printf("%s\n", result[i][j]);
        }


        //go to next line
        i++;
    }   

    // read out the array
    for(k=0; k<5; k++){
        for(j=0;j<4;j++){
            printf("%s\n", result[k][j]);
        }
    }

    fclose(myfile);
    return 0;
}

【问题讨论】:

  • strtok 将返回一个指向原始字符串部分的指针。调用 strtok 时会修改原始字符串。

标签: c fgets strtok


【解决方案1】:

这段代码有几个问题。我已经快速修改了您的代码以达到预期的效果。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRINGSIZE 10
#define LINESIZE 128

struct person{
    char firstName[MAXSTRINGSIZE];
    char lastName[MAXSTRINGSIZE];
    char gender[MAXSTRINGSIZE];
    int birthYear;
    struct person *next;
} *first, *current;


int main (void){
    FILE *myfile = fopen ( "Assignment1file.txt", "r" );
    int i=0;
    int j=0;
    int k=0;
    int l=0;
    char *result[10][4];
    char line[LINESIZE];
    char *value;

    for(i=0; i<=9; i++){
        for(j=0;j<=4;j++){
            result[i][j] = NULL;
        }
    }
    i=0;

    // loop through each entry in Assignment1file
    while(fgets(line, sizeof(line), myfile)){
        //load last name
        value = strtok(line, ", ");
        result[i][0] = strdup(value);
    printf("last: %s\n", value);


        //load first time
        value = strtok(NULL, ", ");
        result[i][1] = strdup(value);
    printf("first: %s\n", value);

        // load gender
        value = strtok(NULL, ", ");
        result[i][2] = strdup(value);
    printf("gender: %s\n", value);

        // load birth year
        value = strtok(NULL, " \n");
        result[i][3] = strdup(value);
    printf("birth year: %s\n", value);

        //go to next line
        i++;
    }   

    // read out the array
    for(k=0; k<5; k++){
        for(j=0;j<4;j++){
            printf("%s\n", result[k][j]);
        }
    }

    fclose(myfile);
    return 0;
}

人们已经对这一变化的细节发表了评论。

【讨论】:

  • 如果其他答案被删除,这不一定有用。您介意添加一些细节吗?
【解决方案2】:

strtok() 在line[] 中返回指针,因此当您读取下一行时,您保存的所有指针现在都指向存储文件最后一行的位置。

您可以像这样为字符串的每一位分配内存:

//load last name
value = strtok(line, ",");
result[i][0] = malloc(strlen(value) + 1);
strcpy(result[i][0], value);

顺便说一句,您不需要在开始时将循环设置为NULL,您可以这样做:

char *result[10][4] = {0};

【讨论】:

    【解决方案3】:

    strtok 将修改原始字符串。因此,您存储的先前指针在每次迭代后不再存在。

    简单的解决方案是使用:strdup 来分配和复制值。

    只需修改您对value 的分配:

    result[i][0] = value;
    

    收件人:

    result[i][2] = strdup(value);
    

    【讨论】:

    【解决方案4】:

    如果需要,您需要将令牌复制到单独的存储中。

    strtok() 会修改你读入行的缓冲区,并将分隔符替换为 NUL 字符,并返回指向缓冲区中某个位置(即当前标记的开头)的指针。

    当你读取下一行时,缓冲区将被新数据填充,因此,你保存的所有指针都没有用,因为以前的数据现在已经消失了。

    引用documentation:

    为了确定标记的开始和结束,函数首先从开始位置扫描 delimiters 中包含的第一个字符 not(它成为 令牌的开始)。然后从这个token的开头开始扫描delimiters中包含的第一个字符,它成为token的end。

    这个记号的结尾被函数自动替换为一个空字符,并且记号的开始由函数返回。

    并且(强调我的):

    str
    要截断的 C 字符串。 此字符串的内容被修改并分解为更小的字符串(标记)。
    或者,可以指定一个空指针,在这种情况下,函数会继续扫描之前成功调用函数的位置。

    分隔符:
    包含分隔符的 C 字符串。
    这些可能因一次调用而异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 2013-02-08
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      相关资源
      最近更新 更多