0

I am looking to read a csv file line by line and write each column to arrays in C. Essentially I want to convert the following Python code to C:

import csv
date = []
x = []
y = []
with open("file.csv") as old:
    read = csv.reader(old,delimiter = ',')
    for row in read:
        date.append(row[0])
        x.append(float(row[1]))
        y.append(float(row[2]))

The csv file has 128 rows and three columns; date,x,y. My thoughts:

char Date[];
int Date[128], i;
for(i = 0; i < 128; i++)
{
     Date[i] = x;
}

This is a simple example I have attempted to fill an array with values within a for loop. I want to know how I can modify this to fill arrays with each line of a csv file split by the ',' delimiter? I want to use the fscanf function but am unsure about how to incorporate it into the above setting?

Attempt:

FILE* f = fopen("file.csv", "r");
fscanf(f, "%char, %f %f",  time, &value, &value);

Update:

The following code reads in a text file of my data and outputs to the screen:

#include <stdio.h>

int main(void)
{
    char buff[128];
    FILE * myfile;

    myfile = fopen("File.txt","r");

    while (!feof(myfile))
    {
        fgets(buff,128,myfile);
        printf("%s",buff);
    }

    fclose(myfile);

    return 0;
}

Instead of outputting to the screen, I want to store each column as an array. Any suggestions on how to do this?

Update 2.

I have updated the code as follows:

#include <stdio.h>
#include<string.h>
int main(void)
{
    char buff[128];
    char * entry;
    FILE * myfile;

    myfile = fopen("file.txt","r");

    while(fgets(buff,128,myfile)){
        puts(buffer);
        entry = strtok(buff,",");
        while(entry!=NULL)
        {
            printf("%s\n",entry) ;
            entry = strtok(NULL,",");
        }
    }

    return 0;
}

Final Update.

I have found an example that does something very similar and is much more intuitive for me (given my limited ability in C)

https://cboard.cprogramming.com/c-programming/139377-confused-parsing-csv-txt-file-strtok-fgets-sscanf.html

Updated code

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

int main()
{

char line[200];
int i = 0;      
int x[50];
int y[50];
int z[50];
FILE *myFile;
myFile = fopen("file.txt", "rt");
while(fgets(line, sizeof line, myFile) != NULL)
{

    if(sscanf(line,  "%d,%d,%d",  &x[i], &y[i],&z[i]) == 3)
    {
        ++i;
    }
}
//Close the file
fclose(myFile);
getch();

return 0;

}

This code works for me provided $x$, $y$ and $z$ are integers/floats. However, when $x$ is a date, I am unable to parse it. The date is of the form $Year-Month-day-Time$.

My attempt

I have tried changing the line

 if(sscanf(line,  "%d,%d,%d",  &x[i], &y[i],&z[i]) == 3)

to

if(sscanf(line, "%d-%d-%d-%d",&year[i],&month[i], &day[i],&time[i], "%d,%d",   &y[i],&z[i]) == 3)

and have declared new arrays

int year, int month, int day, int time

However, this approach gives garbage as the output. Any suggestions on how to modify this code to read and parse dates correctly?

Sjoseph
  • 853
  • 2
  • 14
  • 23
  • Consider using a library? [Here](https://github.com/JamesRamm/csv_parser) – Srini Aug 01 '17 at 17:58
  • Forget for a moment trying to deal with the columns and all that. Please just start by writing a function, in standard c that opens the file and reads it one line at a time and prints the line. Your code should have a while loop that looks like this `while (fgets(buf, bufsize, f)) { puts(buf); }` – Brad S. Aug 02 '17 at 03:06
  • Thanks for the suggestion, Brad S. Could you please explain/expand the code please? – Sjoseph Aug 02 '17 at 09:22

1 Answers1

0

You can use strtok to split a string by delimiter.

This describes the function. It includes a simple example.

Each call gives you a substring, ending where the delimiter was found. You can then copy that substring into a string in an array of strings (of max length, if you know the max length) (or you can have an array of pointers to strings, and allocate memory for each one before the copy to strlen(substring) + 1 (+1 for NULL terminator).

Note that strtok temporarily modifies the existing string, so you must either use it right away or copy it. If you just save a pointer to what strtok returns, when you finish the sequence of strtok calls the string will be restored to its original form and your "substrings" will not be what you expect. (See answer to this question for an explanation.)

And, please do not use !feof(myfile) to control the exit from your loop. See this post for an explanation. Since BradS gave an alternative in his comment, and it is not your main question, I won't repeat him here.


OK, looking at your sscanf approach and your question about dates:

I have used the various scanf and printf functions many times; I have never seen two different format strings in the same call, with parameters in the middle. From the function prototypes, this can't work. I think the only reason it compiles is because the variable parameter list in a variadic function does not have type checking. It will simply ignore these parameters: "%d,%d", &y[i],&z[i], because these are output parameters which do not correspond to anything in the format string. You can do something like:

if(sscanf(line, "%d-%d-%d-%d,%d,%d",&year[i],&month[i], &day[i],&time[i],&y[i],&z[i]) == 6)

This includes all the parameters in the format string.

Also, you mention creating arrays like this:

int year, int month, int day, int time

Those are not arrays. They are simple integers. You can declare an array like:

int year[MAX_SIZE];

I personally have found the scanf set of functions rather difficult to deal with; if the format string doesn't quite match the reality in the string you won't get what you expect/need. That is why I like strtok. But not everyone is comfortable with it; it is not the most obvious or intuitive interface.

Basya
  • 1,477
  • 1
  • 12
  • 22
  • As I am completely new to C, I am really struggling to follow your suggestion, I have used strtok to split each line in the text file and am now printing the output to the screen. How do I save/copy each substring to the correct array? i.e. entry one of each line to array one , entry two of each line to array two.. – Sjoseph Aug 02 '17 at 11:37
  • Sorry, I just saw this comment now. I see that since then you have marked this as a solution and posted a "final update" . Does that mean you have it working, or do you still need more help? – Basya Aug 02 '17 at 15:18
  • I have a working version, posted above, however I have one final issue regarding date parsing? – Sjoseph Aug 02 '17 at 16:15
  • Thanks very much. That makes a lot more sense and works very well. As i get more experience with C, I will attempt to convert to strtok. – Sjoseph Aug 03 '17 at 08:18
  • I guess strtok is not for the fainthearted :-) It is not necessarily a better solution, just one I personally have had success with.I am glad you have it working. C takes a little while to get into; then it's a lot of fun! Happy learning. – Basya Aug 03 '17 at 08:23