简体   繁体   中英

Read from a csv file , separate every line and every field in C

I have a csv file in which I have to separate every line (\\n) and every field (,) in this line. My goal is to create an array of structs. Every struct in each "box" of the array must contains 4 fields of every line. How can I write it in c? I thought to use fscanf and fgets but I don't know how to use them together because with fgets I want to divide lines while with fscanf i want to divide fields .

Final situation :

| 0 , noto, 233460, 32209.073312 | 1, piangea, 4741192, 811.. | 2 ,spenti! , .... |

| position 0 in the array | position 1 in the array | position 2 in the array |

records.csv

0,noto,233460,32209.073312
1,piangea,4741192,81176.622633
2,spenti!,1014671, 4476.013614
3,misericordia,496325,61628.929334
4,quando,4476757,10838.641053

main.c

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

struct _SortedArray {
    int id;
    char field1[12];
    int field2;
    float field3;
};

int main() {
    FILE *fd;
    int res;

    struct _SortedArray files[101];
    int n;


    fd = fopen("records.csv", "r");
    if (fd == NULL) {
        perror("Error");
        exit(1);
    }

    char r[100];
    n = 0;

    while (n<6) {

        if(fgets(r,100,fd)!=NULL){
            puts(r);
            fscanf(r, "%[^,],%[^,],%[^,],%[^\n]\n", &files[n].id, &files[n].field1, &files[n].field2, &files[n].field3);
        }

        n++;
    }

    for(int i=0;i<6;i++){
        printf(" INT:%c,CHAR:%s //",files[i].id, files[i].field1);
    }
    return 0;
}

Your code contains various little problems and a major inconsistency. The major inconsistency is that you should use sscanf instead of fscanf to process the line returned by fgets .

But that is not all:

  • misericordia has 12 characters. As C strings require a NULL terminator, field1 must have at least 13 as size
  • the format characters should be consistent with the type of the fields
  • when you read into a char array, the array decays to a pointer: you must not add th &

So the line could become:

sscanf(r, "%d,%[^,],%d,%f", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3)

Other possible improvements:

  • identifiers starting with _ should be reserved for those that you do not use. Close to an opinion, but here you should better use SortedArray
  • replace plain magic values for sizes with the sizeof operator where you can. If you later change a size, you will have to change it in one single place in your code (best practice: Don't Repeat Yourself)
  • control the result of input functions (here [s]scanf to be robust against erroneous input data
  • eventually control that nothing is left at the end of line
  • only try to print as many lines as you could read
  • remove unused variables (a nice compiler should emit warnings)
  • always limit input of string to the size of the buffer ( %12[^,] )

The code could become:

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

struct SortedArray {
    int id;
    char field1[13];
    int field2;
    float field3;
};

int main() {
    FILE *fd;
    // int res;

    struct SortedArray files[101];
    int n;


    fd = fopen("records.csv", "r");
    if (fd == NULL) {
        perror("Error");
        exit(1);
    }

    char r[100];
    for (n=0; n<sizeof(files)/sizeof(files[0]); n++) {

        if(fgets(r,sizeof(r),fd)==NULL){
            break;
        }
            char dummy[2];    // to control nothing is left on end of line
           //puts(r);
           if (4 != sscanf(r, "%d,%12[^,],%d,%f%1s", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3, dummy)) {
               perror("Incorrect line");
               fprintf(stderr, "Line %d : %s\n", n+1, r);
        }
    }

    for(int i=0;i<n;i++){
        printf(" INT:%d,CHAR:%s //",files[i].id, files[i].field1);
    }
    return 0;
}

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