0

I'm trying to read from a file and print out what's in the file. Data in file is something like the following and consist of 100 rows and 10 columns.

-1,0.53,1,1,1,0,0.8,1,0.5,0

Here is what I have tried:

    #include <stdio.h>
    #include <stdlib.h>
    #define NUMBEROFINPUT 100 //100 inputs.
    #define NUMBEROFCOLUMN 10 //10 rows.

    int main(){
        int *dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];

        FILE *dataFileptr;
        dataFileptr = fopen("group5_8.txt", "r");
        if (dataFileptr == NULL){
           perror("Error");
           return 1;
        }

        for(int i = 0; i < NUMBEROFINPUT; ++i){
            for(int j = 0; j < NUMBEROFCOLUMN; ++j){
               fscanf(dataFileptr, " %f", &dataFileInput[i][j]);
               printf("a[%d][%d] = %.2f\n", i+1,j+1, dataFileInput[i][j]);
            }
        }
    }

However, I'm only getting 0.00 when I print out the result. I'm still rather new to C programming. What am I doing wrong?

8
  • 1
    just int dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN]; is enough instead of int *dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN]; Commented Nov 19, 2020 at 18:25
  • Does your fscanf statement skip over the comma seperator between each number in the input? Commented Nov 19, 2020 at 18:26
  • @IrAM fscanf is used with %f, instead of int a float would be the right way Commented Nov 19, 2020 at 18:26
  • What you have declared is an array of pointers to int. Commented Nov 19, 2020 at 18:26
  • Not sure the commas will be skipped. Commented Nov 19, 2020 at 18:27

3 Answers 3

3

You can follow another approach also using getline

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

#define NUMBEROFINPUT 2 //100 inputs.
#define NUMBEROFCOLUMN 10 //10 rows.

int main(){
    int i, j;
    float dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];
    FILE *dataFileptr;
    char* aline = NULL;
    size_t size = 0;

    dataFileptr = fopen("group5_8.txt", "r");
    if (dataFileptr == NULL){
       perror("Error");
       return 1;
    }
    while(getline(&aline, &size, dataFileptr) != -1) 
    {
        line[strcspn(aline, "\n")] = 0;
        char * sep = strtok(aline, ",");
        printf("%s\n", sep);
        while((sep = strtok(NULL, ",")) != NULL) 
        {
            printf("%s\n", sep);
        }
    }
    return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Tokenizing the line is another good approach, though worth noting that getline() is POSIX so not all compilers will provide it. Declaring a character array of, e.g. 512 chars and then using fgets() would be a standard option. When tokeniizing with strtok() there is no need to trim the '\n' first, just include it, e.g. ",\n" in your list of delimiters.
No worries, I liked your answer and that was one of the ways I would have approached it. So always worth lending a few pointers to help (in repayment for those I have received in the past :) Though I will add, in all other cases, your use of line[strcspn(aline, "\n")] = 0; to trim the '\n' is 100% correct and the correct way to go. And if you need the length of the resulting string, simply size_t len; line[(len = strcspn(aline, "\n"))] = 0; is a great way to go.
2

Declaring a 2D array and then looping to fill each elements from a file is a horribly fragile way to write an input routine. What happens if there is one float too few? (You invoke Undefined Behavior and all bets are off)

A good approach is a line-oriented approach where you read a row of floats at a time, and then, parse the needed floats from each line with either strtok() (or if empty fields are possible, strsep()), or you can use a pair of pointers and strtof() to work down the line, or with a known fixed number of floats per-line, sscanf() will do. All allow the validation of each float read.

Can you read one float at a time with fscanf()? Sure, you just need to keep separate counters and when a row worth of floats are read, reset your column count and increment the row count. Repeat until your run out of rows, or you file ends. Whichever happens first. One other caveat in reading one float at-a-time is you need some way to validate each row has the correct number of floats. You can do that by setting a separate variable to contain the number of columns in the first row, and then compare the number in each successive row with the first row count.

You could do that as follows:

    char c;
    int rows = 0, col = 0, cols = 0, rtn;
    float dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];
    ...
    while (rows < NUMBEROFINPUT) { /* while less than NUMBEROFINPUT rows */
        /* read float saving character that follows and the return */
        rtn = fscanf (dataFileptr, "%f%c", &dataFileInput[rows][col], &c);
        if (rtn < 1)                        /* if nothing read or EOF, break */
            break;
        else if (rtn == 1 || c == '\n') {   /* if only float read or next is \n */
            col++;                          /* increment no of col */
            rows++;                         /* increment no. of rows */
            if (cols && col != cols) {      /* if cols set validate cols no. in col */
                fprintf (stderr, "error: unequal number of columns, row: %d\n", rows);
                return 1;
            }
            if (!cols)                      /* if first row, set no. of cols */
                cols = col;
            col = 0;                        /* reset col for next row */
        }
        else            /* both values read and char not '\n' */
            col++;      /* increment col count */
    }
    
    for (int i = 0; i < rows; ++i)          /* output results */
        for (int j = 0; j < cols; ++j)
           printf("a[%d][%d] = %.2f\n", i+1,j+1, dataFileInput[i][j]);

By using the col and rows indexes above, you are keeping track of the state of your read. By returning if (cols && col != cols), after cols is set by the first row number of columns, you force all subsequent rows to contain that number of values ensuring your 2D array is completely filled.

Example Use/Output

Seting dataFileptr to stdin and reading your example input with stdin would result in:

$ ./bin/read2Dcsv <<< -1,0.53,1,1,1,0,0.8,1,0.5,0
a[1][1] = -1.00
a[1][2] = 0.53
a[1][3] = 1.00
a[1][4] = 1.00
a[1][5] = 1.00
a[1][6] = 0.00
a[1][7] = 0.80
a[1][8] = 1.00
a[1][9] = 0.50
a[1][10] = 0.00

There are many ways to do this. A line-oriented approach provides the most flexible and robust approach, but you can make a float at a time approach reasonably flexible as well. Let me know if you have any further questions.

Comments

1

You should change the following line:

int *dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];

as follows:

float dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];

Alternatively, you can declare the array as double and read using %lf

I also had to skip the commas as follows:

#include <stdio.h>
#include <stdlib.h>
#define NUMBEROFINPUT 100 //100 inputs.
#define NUMBEROFCOLUMN 10 //10 rows.

int main(){
    float dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];
    
    FILE *dataFileptr;
    dataFileptr = fopen("group5_8.txt", "r");
    if (dataFileptr == NULL){
       perror("Error");
       return 1;
    }

    for(int i = 0; i < NUMBEROFINPUT; ++i){
        for(int j = 0; j < NUMBEROFCOLUMN; ++j){
           fscanf(dataFileptr, "%f", &dataFileInput[i][j]);
           fgetc(dataFileptr);
           printf("a[%d][%d] = %.2f\n", i+1,j+1, dataFileInput[i][j]);
        }
    }
    
    fclose(dataFileptr);
}

Note the call to fgetc.

For the sake of completion, I would like you to note that the reading is successful even when using an int* array. The printing fails because the data is interpreted as an int* and then converted to a float. To interpret the bytes stored in the int* array element, first cast the address of the element to a pointer to float, then get the value of the float stored at this address. Same code except for the print statement.

#include <stdio.h>
#include <stdlib.h>
#define NUMBEROFINPUT 100 //100 inputs.
#define NUMBEROFCOLUMN 10 //10 rows.

int main(){
    int *dataFileInput[NUMBEROFINPUT][NUMBEROFCOLUMN];
    
    FILE *dataFileptr;
    dataFileptr = fopen("group5_8.txt", "r");
    if (dataFileptr == NULL){
       perror("Error");
       return 1;
    }

    for(int i = 0; i < NUMBEROFINPUT; ++i){
        for(int j = 0; j < NUMBEROFCOLUMN; ++j){
           fscanf(dataFileptr, "%f", &dataFileInput[i][j]);
           fgetc(dataFileptr);
           printf("a[%d][%d] = %.2f\n", i+1,j+1, *((float *) &dataFileInput[i][j]));
        }
    }
    
    fclose(dataFileptr);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.