Search code examples
cstringsplitscanfarchive

Splitting a long string


I have an archive results.csv and I need to read the first two lines of this archive, split the second one and print them out on output.txt. Somehow it's not printing anything, yet I don't know the reason.

I didn't add the functions that I'm sure are fine.

Command: a.c results.csv

First line: date,home_team,away_team,home_score,away_score,tournament,city,country,neutral

Second line: 18721130,Scotland,England,0,0,Friendly,Glasgow,Scotland,FALSE

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

typedef struct
{
    char *line1;
    long int date;
    char *h_team;
    char *a_team;
    int gols_h_team;
    int gols_a_team;
    char *reason;
    char *city;
    char *country;
    char *neutral_field;

}Data;

void alloc_Data(Data *d, int size)
{
d->line1 = (char*)malloc(50*sizeof(char)); 
d->h_team = (char*)malloc(30*sizeof(char)); 
d->a_team = (char*)malloc(30*sizeof(char)); 
d->reason = (char*)malloc(30*sizeof(char)); 
d->city = (char*)malloc(30*sizeof(char)); 
d->country = (char*)malloc(30*sizeof(char)); 
d->neutral_field = (char*)malloc(9*sizeof(char)); 
}

void store(Data *d, FILE *input, FILE *output, int size)
{

    fscanf(input,  "%s", d[0].line1);
    fprintf(output,  "%s\n", d[0].line1);

    for(int i = 1; i < size; i++)
    {
        fscanf(input, "%li,%[^,]s%[^,]s%d,%d,%[^,]s%[^,]s%[^,]s%[^,]s", &d[i].date, d[i].h_team, d[i].a_team, &d[i].gols_h_team, &d[i].gols_a_team, d[i].reason, d[i].city, d[i].country, d[i].neutral_field );
        fprintf(output, "%li,%s,%s,%d,%d,%s,%s,%s,%s\n", d[i].date, d[i].h_team, d[i].a_team, d[i].gols_h_team, d[i].gols_a_team, d[i].reason, d[i].city, d[i].country, d[i].neutral_field );

    }

}

int main(int argc, char *argv[])
{
    FILE *input;
    FILE *output;
    char *string = "output.txt";
    int size = 2;

    open_input(argv, &input);   
    open_output(string, &output);   

    Data *d;
    d = (Data*)malloc(size*sizeof(Data)); 
    alloc_Data(d, size);

    store(d, input, output, size);

    free(d);

    return 0;
}

Solution

  • OP's fscanf() format is messed up with an s after %[^,] and missing ,. @Gem Taylor

    A better alternative is to read all lines using fgets(). (including the first)

    // fscanf(input, "%li,%[^,]s%[^,]s%d,%d,%[^,]s%[^,]s%[^,]s%[^,]s",...d[i].neutral_field );
    
    #define EXPECTED_MAX_BUFFER_SIZE 150
    char buffer[EXPECTED_MAX_BUFFER_SIZE * 2];  // suggest using 2x expected max size
    if (fgets(buffer, sizeof buffer, input)) {
    

    Then parse the team results with sscanf(). Using a " %n" at the end is an easy way to test if the entire sscanf() succeeded with no extra junk. sscanf() deserve width limits and complex scans benefit with some defines to manage the specifiers. Notice no s after "%29[^,]"

        int n = 0;
        #define FDat "%li ,"
        #define FScr "%d ,"
        #define Ftxt " %29[^,],"
        #define Fneu " %8[^,]"
        sscanf(buffer, FDat Ftxt Ftxt FScr FScr Ftxt Ftxt Ftxt Fneu " %n", 
            &d[i].date, d[i].h_team, d[i].a_team, 
            &d[i].gols_h_team, &d[i].gols_a_team, 
            d[i].reason, d[i].city, d[i].country, d[i].neutral_field, &n);
    
        if (n > 0 && buffer[n] == '\0') {
          // success
          fprintf(output, ...
        } else {
          // bad input
        }