简体   繁体   中英

Assigning values to 2D array element of a struct in C

Im not sure why Im getting the output Im getting for my code, Im currently trying to assign values to a 2D array element of a struct:

typedef struct maximum {
    int mArray[5][4];
} Max;

int main(int argc, char* argv[]) {
    rows = 5;
    columns = 4;
    Max max;
    printf("%s \n", argv[1]);
    readFile(argv[1], max);

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < columns; j++) {
            printf("%d ", max.mArray[i][j]);
        }
        printf("\n");
    }

    if (argc < 2) {
        printf("Input file name missing...exiting with error code -1\n");
        return -1;
    }
}

int readFile(char* fileName, Max max) {
    FILE* in = fopen(fileName, "r");

    if (!in) {
        printf(
            "Child A: Error in opening input file...exiting with error code -1\n");
        return -1;
    }

    const char s[1] = ",";
    char line[100];
    char* token;
    int col;
    int rows;
    while (!feof(in)) {
        fgets(line, sizeof(line), in);

        rows = 0;
        col = 0;

        token = strtok(line, ",");

        while (token != NULL) {
            max.mArray[rows][col] = atoi(token);
            // printf("%d ", max->mArray[rows][columns]);

            printf("tok: %d \n", atoi(token));
            col++;
            token = strtok(NULL, ",");
        }
        // printf("\n");
        rows++;
    }

    return 0;
}

the output I get is:

2005943068 6422268 2005624145 8
2005561085 2005561059 1246939275 4199120
4199120 0 4201184 6422224
6422280 6422476 2005585088 1035772511
-2 6422280 2005561325 4201184 2005943068

Even though my input file is:

6,4,7,3
4,2,3,2
2,5,3,3
6,3,3,2
5,6,7,5

The tokens are correct as I've printed them before I did the 2D array assignment but for some reason when they're assigned the value is different when I try to print them in the main.

while(!feof(in))
{
    fgets(line, sizeof(line), in);

    rows = 0; ...

The last thing you do on the loop is rows++ . And on the second line of the loop you write rows=0 . And thus writing over an over on the first row only.

Also max is a struct. And inside max there is a vector. You need to pass the address of the struct to readFile() as in

int readFile(char*, Max*);

why strtok() and then atoi() to consume formatted input? fscanf() was written for scan f ormatted input. And would convert into numbers, and consume all data passing also the newlines. It should be easier...

Your thought of using fgets to perform line-oriented input on the contents of the file is a good one. In all but rare circumstances, it is much better to approach your read of either file-input or user-input in that way. You can then parse the information you need from the buffer filled in one or a number of ways.

One of your biggest problems here is:

int readFile(char* fileName, Max max)

where you are passing the struct max by-value . What this means is readFile receives a copy of the struct and any changes you make to the struct are lost on function return. Why? Max is type struct maximum , it is not an array so it is not converted to a pointer on access. Instead, you need to pass the address of max in order to operate on that memory address within the function so that the changes made are available back in the calling function.

(It is also curious that you chose to create a single-member struct holding a 2D array instead of simply using the 2D array itself. While perfectly legal -- it is not what you would generally choose to do)

Beyond that, you may want to consider passing a FILE* parameter instead of a filename to readFile . Why? if the file cannot be opened and validated in the caller, there is no reason to make a function call to attempt to read it.

To parse the values from each line read from the file, you can use strtok , or you can use a pair of pointers to work your way through the buffer, you can use a combination of strcspn/strspn or you can use sscanf -- which make more sense here. For example, you need (1) to ensure you attempt to fill no more than ROWS sets of values in mArray , (2) you need to read each line, and (3) you need to parse each integer value from your buffer to the elements of mArray . You can actually condition your loop control on all three parameters to ensure a successful read, eg

    int n = 0;
    char buf[MAXC];
    /* read/validate 4 integers per-row, protect array bounds */
    while (n < ROWS && fgets (buf, MAXC, in) &&
            sscanf (buf, "%d,%d,%d,%d", &max->mArray[n][0], &max->mArray[n][1],
                                        &max->mArray[n][2], &max->mArray[n][3]) == 4)
        n++;        /* increment row count */

In order to make the number of rows read available back in the caller -- a good choice is to return n; instead of return 0; . Making the changes suggested, you could do:

#define ROWS 5      /* if you need a constant, #define one (or more) */
#define COLS 4
#define MAXC 100

typedef struct maximum {        /* struct and typedef */
    int mArray[ROWS][COLS];
} maximum;

int readFile (FILE *in, maximum *max)
{
    int n = 0;
    char buf[MAXC];
    /* read/validate 4 integers per-row, protect array bounds */
    while (n < ROWS && fgets (buf, MAXC, in) &&
            sscanf (buf, "%d,%d,%d,%d", &max->mArray[n][0], &max->mArray[n][1],
                                        &max->mArray[n][2], &max->mArray[n][3]) == 4)
        n++;        /* increment row count */
    
    return n;       /* return number of rows successfully read */
}

Adding a main() that validates the return of readFile() to ensure you do not attempt to output more values that you have read, you could do:

int main(int argc, char *argv[]) {
    
    int n = 0;              /* row count */
    maximum max = {{{0}}};  /* struct with 2d array initialized all zero */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    if ((n = readFile (fp, &max)) != ROWS)  /* validate rows read from file */
        fprintf (stderr, "warning: %d rows filled in max->mArray.\n", n);
    
    for (int i = 0; i < n; i++){            /* output results */
        for (int j = 0; j < COLS; j++)
            printf (" %d", max.mArray[i][j]);
        putchar ('\n');
    }
}    

Example Use/Output

With your data in the file named dat/in5x4.csv , your use and results would be:

$ ./bin/struct2darr dat/in5x4.csv
 6 4 7 3
 4 2 3 2
 2 5 3 3
 6 3 3 2
 5 6 7 5

Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM