我一直在研究一个程序,该程序读取包含名称,年龄和GPA值的CSV文件。 代码似乎通过文件读取正常但我有解决它的问题,因为程序没有正确地标记值。由于某种原因,它正确地读取了行,然后当我尝试使用strtok来解析它时,它每次只获取名称。 CSV的格式为:
name1, age1, GPA,
name2, age2, GPA,
等
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student{
char name[50];
int age;
double GPA;
};
int main(int argc, char *argv[]){
FILE *fp;
char buffer[255];
struct Student students[100];
int i = 0;
if (argc != 2){
printf("Incorrect input\n\n");
exit(-1);
}
fp = fopen(argv[1], "r");
if(fp == NULL){
printf("Error: Empty File\n\n");
exit(-1);
}
//takes the next line of the CSV and puts it in the next student
while(fgets(buffer, 255, fp) != NULL){
printf("%s\n", buffer);
strcpy(students[i].name, strtok(buffer, ","));
printf("%s\n", buffer);
students[i].age = atoi(strtok(buffer, ","));
printf("%s\n", buffer);
students[i].GPA = atof(strtok(buffer, ","));
printf("%s\n", buffer);
i++;
}
for(int i = 0; i < 9; i++)
{
printf("%s, %d, %f\n", students[i].name, students[i].age, students[i].GPA);
}
}
答案 0 :(得分:2)
这段代码修改工作合理(只要数据中没有格式错误):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student
{
char name[32];
int age;
double GPA;
};
int main(int argc, char *argv[])
{
FILE *fp;
char buffer[255];
struct Student students[100];
if (argc != 2)
{
fprintf(stderr, "Usage: %s grades-file\n", argv[0]);
exit(-1);
}
fp = fopen(argv[1], "r");
if (fp == NULL)
{
fprintf(stderr, "%s: failed to open file %s for reading\n", argv[0], argv[1]);
exit(-1);
}
int i;
for (i = 0; fgets(buffer, sizeof(buffer), fp) != NULL; i++)
{
char *token;
buffer[strcspn(buffer, "\n")] = '\0';
printf("[%s]\n", buffer);
strcpy(students[i].name, (token = strtok(buffer, ",")));
printf("[%s] [%s]\n", buffer, token);
students[i].age = atoi((token = strtok(NULL, ",")));
printf("[%s] [%s]\n", buffer, token);
students[i].GPA = atof((token = strtok(NULL, ",")));
printf("[%s] [%s]\n", buffer, token);
}
for (int j = 0; j < i; j++)
{
printf("%s, %d, %.1f\n", students[j].name, students[j].age, students[j].GPA);
}
return 0;
}
请注意,此代码会捕获strtok()
中token
的返回值。它应该在调用任何其他函数之前检查token
是否为null,因此编写的代码相当脆弱。 strcspn()
调用可以在输入行的末尾删除换行符,但如果行末没有换行符,也可以正常工作。
另请注意strtok()
如何屠杀字符串。一旦它隔离了第一个标记,就会有一个空值代替分隔符(,
)。此后,buffer
不会更改 - 因此代码也会打印token
。
数据文件:
Gavin Thomas, 12, 67.3
Adelie Newman, 13, 89.214
Karen Gibson, 15, 94.599
示例输出(程序csv17
):
$ csv17 data.csv
[Gavin Thomas, 12, 67.3]
[Gavin Thomas] [Gavin Thomas]
[Gavin Thomas] [ 12]
[Gavin Thomas] [ 67.3]
[Adelie Newman, 13, 89.214]
[Adelie Newman] [Adelie Newman]
[Adelie Newman] [ 13]
[Adelie Newman] [ 89.214]
[Karen Gibson, 15, 94.599]
[Karen Gibson] [Karen Gibson]
[Karen Gibson] [ 15]
[Karen Gibson] [ 94.599]
Gavin Thomas, 12, 67.3
Adelie Newman, 13, 89.2
Karen Gibson, 15, 94.6
$
答案 1 :(得分:0)
根据strtok(3)(man 3 strtok)的联机帮助页:
strtok()函数将字符串分解为零或更多的序列 非空的令牌。在第一次调用strtok()字符串时 解析应该在str中指定。在每个后续调用应该 解析相同的字符串,str必须为NULL。
另外,如果你想知道它是如何运作的:
对strtok()的一系列调用,它们对同一个字符串进行操作 维护一个指针,确定从哪个点开始 寻找下一个标记。
基本上strtok会为您保管:)