servoRob
servoRob

Reputation: 3

Trying to store data from file to arrays of structure

In the function below in my program, I am trying to read numbers from a text file and enter them to arrays of structure x,y,mass accordingly. The text file looks like this:

 1 2 3 //first number is x, second is y, and third is mass
 1 2 3
 1 2 3
 #include <stdio.h>
 #include <stdlib.h>
 #define MAX 100
 struct cg { 
float x, y, mass;
 }masses[MAX];

int readin(void)
{
FILE *file = fopen("test.txt", "r");
int count;
if (file == NULL) {
    printf("Error: can't open files.\n");
    return 1;
}
else {
    while (1) {
         char c = fgetc(file);
         
        if (c != EOF) {
            if (count == 0) {
                masses[count].x = c;
            }
            else if (count == 1)
            {
                masses[count].y = c;
            }
            else if (count == 2)
            {
                masses[count].mass = c;
            }
            if (count != 3) {
                count++;
            }
            else { count = 0; }

        }
        else {
            break;
        }
        
    }
}
fclose(file);
}

I wrote this so far but i dont know if im going the correct way

Upvotes: 0

Views: 83

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84561

If you are just getting started, get started correctly. When you approach a problem that requires reading lines of data, use a line oriented input function to read the data (e.g. fgets or POSIX getline). This allows you to validate the read separate and apart from parsing values from the line.

After reading and validating a line of data, you can then parse that data into whatever values you need. There are a great many tools available. sscanf, strtod, strtok or simply walking a pointer over each character in your line buffer comparing character-by-character as you go and taking the needed action.

Here, sscanf provides a very convenient way to parse 3 floating-point values from a line of text. (and use double instead of float for any engineering related work and always use integer values for currency). If you did not know how many values you were reading from each line, then walking strtod through the buffer would work fine.

Validate, validate, validate. If you read it -- validate what your read. If you convert it -- validate your conversion took place (and if needed that the value is within the expected range).

Putting those pieces together, you can do something similar to the following to read 3-values from each line into an array of struct (up to MAX elements). The code expects the filename to read as the first argument (or it will read from stdin by default if no arguments are given):

#include <stdio.h>

enum { NMEMB = 3, MAX = 100, MAXC = 512 };

typedef struct {
    double x, y, mass;
} cg;

int main (int argc, char **argv) {

    int n = 0;                      /* masses index */
    char buf[MAXC] = "";            /* buffer for each line */
    cg masses[MAX] = {{ .x = 0 }};  /* array of cg initialized to 0 */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (n < MAX && fgets (buf, MAXC, fp)) {  /* read each line */
        cg tmp = { .x = 0 };                    /* temporary struct */
        /* you should validate complete line read here */
        /* parse values into tmp and validate */
        if (sscanf (buf, "%lf %lf %lf", &tmp.x, &tmp.y, &tmp.mass) == 3)
            masses[n++] = tmp;      /* assign tmp to massess, increment n */
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (int i = 0; i < n; i++)
        printf ("masses[%2d]  %5.2f %5.2f %5.2f\n", 
                i, masses[i].x, masses[i].y, masses[i].mass);

    return 0;
}

(note: I have left validating that a whole line was read as an exercise. strlen and then checking that the last character read is '\n' will suffice)

Example Input File

$ cat ../dat/int3x20.txt
21 61 78
94 7 87
74 1 86
79 80 50
35 8 96
17 82 42
83 40 61
78 71 88
62 20 51
58 2 11
32 23 73
42 18 80
61 92 14
79 3 26
30 70 67
26 88 49
1 3 89
62 81 93
50 75 13
33 33 47

Example Use/Output

$ ./bin/cg ../dat/int3x20.txt
masses[ 0]  21.00 61.00 78.00
masses[ 1]  94.00  7.00 87.00
masses[ 2]  74.00  1.00 86.00
masses[ 3]  79.00 80.00 50.00
masses[ 4]  35.00  8.00 96.00
masses[ 5]  17.00 82.00 42.00
masses[ 6]  83.00 40.00 61.00
masses[ 7]  78.00 71.00 88.00
masses[ 8]  62.00 20.00 51.00
masses[ 9]  58.00  2.00 11.00
masses[10]  32.00 23.00 73.00
masses[11]  42.00 18.00 80.00
masses[12]  61.00 92.00 14.00
masses[13]  79.00  3.00 26.00
masses[14]  30.00 70.00 67.00
masses[15]  26.00 88.00 49.00
masses[16]   1.00  3.00 89.00
masses[17]  62.00 81.00 93.00
masses[18]  50.00 75.00 13.00
masses[19]  33.00 33.00 47.00

Lastly, always compile with warnings enabled, and do not accept code until it compiles cleanly without warning. To enable warnings add -Wall -Wextra to your gcc compile string. (add -pedantic for several additional warnings). For VS (cl.exe on windoze), add /Wall. For clang, add -Weverything. Read and understand each warning. They will identify any problems, and the exact line on which they occur.

Upvotes: 1

Related Questions