0

I am new to C and I need to read in a .txt file where there are 3 fields in each line separated by a comma, and I need to save it into an array. I am wondering how to do this? Here is an example file:

0, "test", 100
1, "hi", 2
2, "goodbye", 0

So I am wondering how to read the file line by line and to store each element into an array. I have started by defining a struct:

typedef struct data {
  int col1;
  char *col2;
  int col3;
} data_t;

Could anyone help me out to get started with the file opening?

BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
user2516663
  • 99
  • 1
  • 10

3 Answers3

0

For file opening there is a standard library (include stdio.h) function named fopen. It has the following declaration:

FILE *fopen(const char *filename, const char *mode);

As you can see it expects you to provide a pointer to const char for both filename and mode (read/write/read+write). It will return a pointer to a FILE so inside the function where you intend to work with it you'd have to declare one like this:

FILE *my_file;

It's also a good idea to initialize it to NULL so that you can check for errors when using fopen.

In your main function (purely for reading):

FILE *my_file = NULL;
my_file = fopen("filename.txt", "r");

And check for the returned pointer:

if (my_file == NULL)
    //error message etc.
cytoscope
  • 129
  • 2
  • Here is the syntax I am using then, is this right? int main() { FILE *my_file; FILE *fopen("data", "r"); } – user2516663 Feb 12 '14 at 23:46
  • Okay so I understand this now. So does this open the whole file or just the first line? Now what I want to do is read the first line which will have the format: int,string,int and what I want to do is store each field as an element in the array. From what I have found online I need to use the strtok function. Is that correct? – user2516663 Feb 13 '14 at 00:00
  • @user2516663 It gives you a pointer to the file. To get individual lines you'd use something like the `getline()` function. `strtok` is a way of doing it. You just provide the string and the delimiter (in your case the comma). – cytoscope Feb 13 '14 at 00:11
  • Hmm I am still really confused on this. So my_file is a pointer to my txt file, and now do I need a new variable to equal the first line? – user2516663 Feb 13 '14 at 00:31
  • @user2516663 check out [this](http://stackoverflow.com/questions/3501338/c-read-file-line-by-line) link. The first answer gives you an idea of how to do line-by-line reading and what variables are involved. – cytoscope Feb 13 '14 at 00:35
0

The SQLite shell has an .import command that reads CSV. It is worthy of study. You can find it here; search for CSVReader to see how it's coded.

Doug Currie
  • 40,708
  • 1
  • 95
  • 119
0

simply sample(check omit)

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

#define NUMOFDATA 10

typedef struct data {
    int col1;
    char *col2;
    int col3;
} data_t;

int main(){
    data_t data_array[NUMOFDATA];
    int data_count = 0;
    char line[128];
    FILE *fp;
    fp=fopen("data.txt", "r");
    while(fgets(line, sizeof(line), fp)){
        int col1, col3;
        char col2[64];
        if(sscanf(line, "%d, %63[^,], %d", &col1, col2, &col3)==3){
            char *cl2p = col2;
            data_array[data_count].col1 = col1;
            data_array[data_count].col3 = col3;
            if(col2[0] == '"'){
                char *p = strchr(&col2[1], '"');
                if(p)
                    *p = '\0';
                cl2p = &col2[1];
            }
            data_array[data_count].col2 = strdup(cl2p);
//printf("%d, \"%s\", %d\n",data_array[data_count].col1,data_array[data_count].col2,data_array[data_count].col3);
            if(++data_count == NUMOFDATA)break;
        }
    }
    fclose(fp);
    return 0;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • I suggest you use the `m` modifier in the scanf string fields (i.e. `%m[^,]`, so that the memory for the string gets allocated by scanf. This makes the whole thing much more robust (otherwise you have an buffer overflow). Also instead of reading into an intermediary buffer use fscanf directly on the file. So `size_t data_count; for(data_count=0; i<10; i++) { char **col2 = &(data_array[i].col2); if( !fscanf(fp, "%d, %[^,], %d", &(data_array[i].col1), col2, &(data_array[i].col3) ) break; size_t c2l = strlen(*col2)-1; if( (*col2)[0]=='"' && (*col2)[c2l]=='"' ) memmove(*col2, *col2+1, c2l-1); }` – datenwolf Feb 13 '14 at 13:37
  • @datenwolf It was a plan that does not provided such checks, but was added by your recommendation. but It had not add `m` option because there is no common. I leave the choice of the questioner. – BLUEPIXY Feb 13 '14 at 13:47
  • Then the proper test would be `0 < fscanf(…)` since `E…` codes are negative. – datenwolf Feb 13 '14 at 14:28
  • @datenwolf It is better to test the number of elements simply. – BLUEPIXY Feb 13 '14 at 14:34
  • What if all but the first column are optional? – datenwolf Feb 13 '14 at 14:41
  • @datenwolf Could you please to the questioner that kind of thing? I do not need your suggestions. – BLUEPIXY Feb 13 '14 at 14:59