Previously stored strings are overwritten by fgets

2019-09-20 14:05发布

问题:

I'm reading records from a CSV file using fgets() to read the file one line at a time, and strtok() to parse the fields in each line. I'm encountering a problem where fgets() overwrites a string that was previously written, in favor of the new string.
Here's an example of what I mean by that:

record.csv (This is the file I'm reading in)

John,18
Johann,29

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct customer {
    char *name;
    int age;
} Customer;

int main(void) 
{
    FILE *csv_data;
    char line[100], *token;
    Customer newData[2];

    csv_data = fopen("record.csv", "r");
    // Index 0 for John's data, index 1 for Johann's data
    int i = 0;

    /* loops until end of file */
    while(fgets(line, 100, csv_data)) {

        /* name field */
        token = strtok(line, ",");
        if (token != NULL) {
            newData[i].name = token;        
        }

        /* age field */
        token = strtok(NULL, ",");
        if (token != NULL) {
            // atoi() converts ascii char to integer
            newData[i].age = atoi(token);
        }
        i++;
    }
    /* print John's records */
    printf("%s\n", newData[0].name);
    printf("%d\n", newData[0].age);

    /* print Johann's records */
    printf("%s\n", newData[1].name);
    printf("%d\n", newData[1].age);

    return 0;
}


When we compile and execute this, it prints out:

Johann
18
Johann 
29

"John" in newData[0].name gets overwritten with "Johann" during the second iteration of the while loop. Notice however that only the strings get mixed up, but not the integers. I suspect this has to do with fgets because when I modified the above source to only run fgets once, the output for "John" was as it should be.
Maybe I'm misusing fgets (or perhaps my assumption is wrong), but could someone give me some pointers on why the strings are being overwritten with each calls to fgets?

Second Update: Thank-you very much again to all the commenters and the answerers. Good to know those things which I was not aware of. The source works perfect now.

回答1:

You are not copy the string but the pointer to the string.

A very simple way to copy the string, but note that this limit the size of the string at 99 characters.

typedef struct customer {
    char name[100];
    int age;
} Customer;

strcpy(newData[i].name, token);   


回答2:

Do:

newData[i].name = malloc( strlen( token ) + 1 );
strcpy( newData[i].name, token );

or define name member as char name[64]; and then again strcpy( newData[i].name, token ); without malloc. The 64 bytes for name can be more or less.



标签: c csv fgets strtok