使用fgets()和strtok()在C中逐行读取文件?
我正在尝试使用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 #include #include #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()
返回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};
这段代码有几个问题。 我已经快速修改了你的代码以完成预期的工作。
#include #include #include #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; }
人们已经对这一变化的细节进行了评论。
strtok
将修改原始字符串。 因此,在每次迭代后,您存储的先前指针不再存在。
简单的解决方案是使用: strdup来分配和复制值。
只需在任何地方修改您的value
分配:
result[i][0] = value;
至:
result[i][2] = strdup(value);
如果需要,您需要将令牌复制到单独的存储中。
strtok()
将修改读取行的缓冲区,并用NUL字符替换分隔符,并返回指向缓冲区中某个位置的指针(即当前标记的开头)。
当您在下一行中读取时,缓冲区将填充新数据,因此,您保存的所有指针都是无用的,因为之前的数据现在已经消失。
从文档引用:
为了确定令牌的开始和结束,该函数首先从起始位置扫描未包含在分隔符中的第一个字符(它成为令牌的开头 )。 然后从令牌的这个开头开始扫描包含在分隔符中的第一个字符,这将成为令牌的结尾 。
令牌的这一端由函数自动替换为空字符,并且该函数返回令牌的开头 。
并且(强调我的):
海峡
C字符串要截断。 修改此字符串的内容并将其分解为更小的字符串(标记)。
或者,可以指定空指针,在这种情况下,该function继续扫描先前成功调用该函数的位置。分隔符:
包含分隔符的C字符串。
这些可能因呼叫而异。