strtok在这个实例中的确如何运作?

时间:2018-03-12 05:51:04

标签: c strtok

我一直在研究一个程序,该程序读取包含名称,年龄和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);
    }
}

2 个答案:

答案 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会为您保管:)