简体   繁体   中英

C: Reading data values into structs

I have a csv file with information where the parts of it are separated with a ",". What I want to do is take this information and store it in different struct variables but I don't know how to make it so that the information is stored there.

This is my main file:

struct items beer [100];

int main(int argc, char **argv) {
    char *oneline, *tok;
    char envara[512];
    char delim [] = ",";
    FILE *fp;
    int i = 0;
    fp = fopen("varor.csv", "r");

    printf("ID\n");

    while (!feof(fp)) {
        if (fp == NULL) {
            fprintf(stderr, "File varor.csv could not be opened\n");
            exit(-1);
        }
        fgets(envara, 512, fp);
        envara[strlen(envara) -1] = '\0'; 

        printf("En rad; %s\n", envara);

        oneline = strdup(envara);
        tok = strtok(oneline, delim);

        while (tok != NULL) {
            printf("%s\n", tok);
            tok = strtok(NULL,delim);
        }
    }
    return 0;
}

And this is my struct:

struct items {
    int itemnumber;
    char name [100];
    float price;
    float volyme;
    char types [100];
    char style [100];
    char package [20];
    char country [20];
    char producer [50];
    float alcohol_amount;
};

Reading a file line-by-line should be done using fgets . It will return a null pointer if the stream you read is at end-of-file. Using feof is wrong .

Despite tokenizing the read line is sometimes a better approach, you can use the sscanf too to extract data from each line into your struct items . To make my example easier to read, I've changed the struct items as follows:

typedef struct item_t {
    char name[20];
    float weight;
    unsigned long id;
    float price;
} Item;

If you don't have a header line in your CSV file, you can parse it as simple as:

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

#define MAX_ITEM 5

typedef struct item_t {
    char name[20];
    float weight;
    unsigned long id;
    float price;
} Item;

int main() {
    Item items[MAX_ITEM];
    int i = 0, parsedData;

    char line[512];
    FILE* csvFile = fopen("test.csv", "r");

    if(csvFile == NULL) {
        perror("Failed to open file.");
        exit(EXIT_FAILURE);
    }

    while(fgets(line, sizeof(line), csvFile) != NULL && i < MAX_ITEM) {
        parsedData = sscanf(line, "%20[^,],%f,%lu,%f",
                items[i].name, &items[i].weight, &items[i].id, &items[i].price);
        if(parsedData == 4)
            items[i++].name[19] = '\0';
        else
            fprintf(stderr, "Format error in line: %s\n", line);
    }

    fclose(csvFile);
    return 0;
}

In my example the first value can contain spaces too, the %20[^,] part of the format string means: read anything that is not a comma character up to 20 characters.

Live Demo

Note: using the sscanf function is not safe, it can cause overflows and undefined behaviours in many ways. So, it's your responsibility to keep the fields of your CSV file parsable by the format string, and to keep the parameter list of the sscanf function proper. My example will skip the current line if it contains more than 20 characters before the first comma, but eg cannot prevent integer overflows if you specify too long number for id . To write safer code, consider writing your own conversion functions for each different fields with appropriate input checks, then use eg the tokenization of lines with these functions to fill your struct items .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM