tags:

views:

318

answers:

3

Given a file (e.g. myfile.txt) with this content (always three lines):

 0 2 5 9 10 12
 0 1 0 2 4 1 2 3 4 2 1 4
 2 3 3 -1 4 4 -3 1 2 2 6 1

How can we parse the file, such that it is stored in arrays, just as if they were hard coded this way:

int Line1[] = { 0, 2, 5, 9, 10, 12 };

int Line2[] =    { 0, 1, 0,  2, 4, 1,  2, 3, 4, 2, 1, 4 };

double Line3[] = { 2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1 };

Update: based on comments by wrang-wrang. I am currently stuck with this code.

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

int main  ( int arg_count, char *arg_vec[] ) {
    int ch;
    FILE * fp;
    int i;

    if (arg_count <2) {
        printf("Usage: %s filename\n", arg_vec[0]);
        exit(1);
    }


    //printf("%s \n\n", arg_vec[i]); // print file name

    if ((fp = fopen(arg_vec[1], "r")) == NULL) { // can't open file

        printf("Can't open %s \n", arg_vec[1]);
        exit(1)
    }



    const unsigned MAX_N=1000;
    int Line1[MAX_N];
    int Line2[MAX_N];
    double Line3[MAX_N];
    unsigned N3=0;


    // Parsing content

    while ((ch = fgetc(fp)) != EOF) {

        if (ch=='\n' || ch=='\r') break;
        ungetc(ch,fp);

        assert(N3<MAX_N);
        fscanf(fp, " %1f", &Line3[N3++]);

        // not sure how to capture line 1 and 2 for 
        // for array Line1 and Line2
     }

         fclose(fp);

         // This fails to print the content the array
         for (int j=0; j <Line3; j++) {
             printf(Line3[j],"\n");
         }    

    return 0;
}

In principle I have problem in:

  1. Finding ways of how to assign each line to the correct array.
  2. Printing out the content of the array (for checking).
+3  A: 

strtok() in string.h should get the job done.

Steve K
strtok() is rather unsafe in certain situations, and is also going to still leave him stuck with `char *` data.
Chris Lutz
+1 as this is the right tool for the job if you know what you are doing and are careful. `strtok_r()` is the reentrant version and can be better to use than plain `strtok()` in most circumstances. There are still issues with these functions, e.g. they modify the string that is being parsed (so make a copy first) and they won't operate on a constant string (again, make a copy first).
mhawke
+1  A: 
  1. You're going to need dynamically allocated arrays. Unless you can be absolutely sure at compile time of the amount of data you're going to read in (and you can't, or at least shouldn't), you're going to have to use pointers to arrays allocated with malloc() and realloc(). If you don't know how to do this, read up on memory management in C.
  2. You're going to need to convert char * (textual) data to numeric types. My personal favorite functions are strtol() and strtod(), but there are also atoi() and atof() functions that may be avaliable. However, since we're working with a file stream, here, you may have much better luck with fscanf() to do the conversion for you. All of these functions are in the standard library, except strtod(), which is C99-specific (so it's in there if you're lucky).

If you don't know how to use any of the functions named there, it should be easy to find manpages for them, either on your system (section 3, e.g. man 3 malloc) or the internets (malloc(3))

Chris Lutz
+1  A: 

Here's a less-usual approach that makes only a single pass over the input bytes. Scanf will skip whitespace for you, but you don't want it skipping newlines. As long as your newlines immediately follow the last non-space character, reading a single character and putting it back if it's not a newline will work. A more robust solution could manually parse the whitespace and put back the first nonspace char before scanf.

Perhaps just copying the nonspace characters into a buffer and using one of the string->number conversions (sscanf, strtol, etc.) would be simpler.

It's more common to read entire lines at once using a library function, then parse the lines. There's nothing in ANSI C that will do that for you, let alone for arbitrary line length.

#include <stdio.h>
#include <assert.h>

const unsigned MAX_N=1000; /* use malloc/realloc if it matters to you */
double Line3[MAX_N];
unsigned N3=0;

unsigned c;
FILE *f;
f=fopen("myfile.txt","r");
while ((c=fgetc(f)) != EOF) {
  if (c=='\n'||c=='\r') break;
  ungetc(c,f);
  assert(N3<MAX_N);
  fscanf(f," %lf",&Line3[N3++]); /* the space means 'skip whitespace' */
} /* Line3 holds N3 items */

/* similar for int except fscanf " %d" */
wrang-wrang
For what it's worth, it should _always_ matter to you whether or not your code gets buffer overflows. Also, a better way to structure it (in my opinion) is to write a function that takes a file, and returns a (probably `malloc()`ed) array of `int`s. That way, you have less duplicate code.
Chris Lutz
@wrang-wrang: I have update my code. Please advice.
neversaint