Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Reading integers from a file and storing them into variables

MrPigeonMrPigeon AustraliaMember Posts: 8

Hey guys, I've written this test program to try and better understand reading from a file. I've run into a few problems though. Here is my code:

int main(void) {

int     valueA=0, valueB=0, valueC=0, valueD=0, valueE=0;

FILE *file;

//file = fopen("U:\\GENG1003\\input1.dat", "r");

if (file == 0) {

    printf("Could not open file.\n");

} else {

    int data;

    while ((data = fgetc(file)) != EOF && (data = fgetc(file)) != '\n') {

        fscanf(file, "%d %d %d %d %d", &valueA, &valueB, &valueC, &valueD, &valueE);
    }

}

printf("a = %d; b = %d; c = %d; d = %d; e = %d;", valueA, valueB, valueC, valueD, valueE);

return 0;

}

If I have in input1.dat just a single line comprised of 0 1 4 -6 3. Then the result I get is "a = 1; b = 4; c =-6; d =3; e = 0;" So what happened to the first 0?
Also, if I add another line to input1.dat (i.e 0 -1 2 -5 2) then I get an even stranger result "a = 1; b = 2; c =-5; d =2; e = 0;".

Anyone care to explain to me what I'm doing wrong?

«1

Comments

  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭
    while ((data = fgetc(file)) != EOF && (data = fgetc(file)) != '\n')
    

    you wouldn't want that.. you've stored a value in data on the first assignment.

    while(((data = fgetc(file)) != EOF) && data != '\n')
    

    Since you're dealing with a text file, I'd suggest using fgets and sscanf

    char file_buf[BUFSIZ];
    
    while(fgets(file_buf, sizeof file_buf, file) != NULL)
    {
        if((sscanf(file_buf, "%d %d %d %d %d", 
            &valueA, &valueB, &valueC, &valueD, &valueE)) != 5)
        {
            puts("conversion of types failed");
        }
        else
        {
            // do something with valueA-E
        }
    }
    
  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭
    value = fopen("yourfile.txt","r");
    

    value is an int, but fopen returns a pointer to a FILE object.

    FILE *filepointer = fopen("yourfile.txt", "r");
    
    if(filepointer != NULL)
    {
      // do file operations
      fclose(filepointer);
    }
    ...
    
    printf("%d, %d, %d, %d, %d", v1, v2, v3, v4, v5, value);
    

    that one has too many arguments. :P

    I dunno what the code tag button is supposed to do, but I use pre and html entities for less than / greater than... they seem to work

    < pre >

    #include & lt ; header.h & gt ;
    source code
    



    < /pre >

    no spaces with the tag stuff... there may be other tags too...

  • MrPigeonMrPigeon AustraliaMember Posts: 8

    Ok so I tried using sscanf instead and now, I'm getting one less variable stored?

    Here's what I have:

    int main(void) {
    
    double  valueA=0.0, valueB=0.0, valueC=0.0, valueD=0.0, valueE=0.0;
    
    FILE *file;
    
    file = fopen("U:\\GENG1003\\input1.dat", "r");
    
    if (file == 0) {
    
        printf("Could not open file.\n");
    
    } else {
    
        char file_buf[5];
    
        while (fgets(file_buf, sizeof file_buf, file) != NULL) {
    
            sscanf(file_buf, "%lf %lf %lf %lf %lf", &valueA, &valueB, &valueC, &valueD, &valueE);
        }
    
    printf("a = %.3f; b = %.3f; c = %.3f; d = %.3f; e = %.3f;", valueA, valueB, valueC, valueD, valueE);
    printf("\n");
    
    return 0;
    

    }

    And I get the output "a = 3.000; b = -6.000; c = 0.000; d = 0.000; e = 0.000;" when input1.dat contains just a single line: 0 1 4 -6 3. What's going on? :/

  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭
    char file_buf[5];
    

    I'd suspect that the buffer wasn't large enough to store the entire line of the file's data; since you initialized your variables to 0.0, the variables that weren't affected retained their value of 0.0 in the printf statement.

    I tried your code and got the same result; I have no idea as to why 3 and -6 were stored in valueA and valueB and not 0 and 1. When I increased the buffer size, I got the expected result.

    scanf, fscanf, sscanf all return an integer value of the number of items that were properly converted and stored in variables, which you can use to determine whether or not the read was as expected. For example, if you expected to store 3 values and sscanf returned 1, then you know something went wrong somewhere.


    @tienkhoanguyen depending on the file's data, fscanf may fail to convert variables with format specifiers other than the type expected.

    For the text files anyway, if you store the file's data into a character buffer, you can parse that buffer before trying to convert it to make sure its format is correct for what you expect it to be. That way, you can avoid any potential stream errors that may make the program appear "loopy."

    glad the code tags helped. :) I had the goofy output too when I began posting here again. I tried them as a last resort before giving up.

    I had a couple of intro c++ type courses in the early 2000s, but hated them. I haven't coded much of anything since then, but I do like C... it's easier for me to follow.

  • MrPigeonMrPigeon AustraliaMember Posts: 8

    @psuedocoder Ah I see, I had the file_buf set to 5 as I knew that there was only going to be 5 values per line. I've increased it to 15 and it works perfectly now. I just have one last question. Say if input1.dat has two lines eg.
    "0 1 4 -6 3
    0 1 -5 3 4"

    How would I get it to store the first line as variables, print them and then move on to the next line?

  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭

    fgets stores what is read as one contiguous string, so it needs to be large enough to hold the longest line in the file. Something like 3 0 1 -5 3 4 would appear as a string of characters - "3 0 1 -5 3 4" and require a buffer of 13 elements.

    If you don't need to preserve the data for calculations, then you could print them after you convert them

    while(fgets(...) != NULL)
    {
        sscanf(....);
        printf(....);
    }
    

    If you need each set for later calculations, then you'll need a container of some type; you can create a fixed sized array and hope that it isn't too large or too small, or you can read the file to find out how many elements your file has and then dynamically allocate some space for them.

    HTH

  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭

    I rarely look for EOF unless I'm using fgetc.

    int ch;
    
    while((ch = fgetc(in_file)) != EOF)
       fputc(ch, out_file);
    

    I usually do something like

    unsigned char buf[BUFSIZ];
    
    while(fread((unsigned  char *)buf, sizeof(buf), 1, in_file) == 1)
        printf("%d\n", fwrite((unsigned char *)buf, sizeof(buf), 1, out_file));
    

    I wouldn't call your apps lame; the issue really is the code isn't standard so unless people have an environment to build and execute the programs, there really isn't much one can do to test them out.

    for giggles, try something like

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_ROWS 24
    #define MAX_COLS 80
    
    #define WALL_LT  0xB0
    #define WALL_MD  0xB1
    #define WALL_DK  0xB2
    
    typedef struct
    {
        unsigned char screen[(MAX_ROWS * MAX_COLS) + 1];
    
    } fake3d;
    
    void initDisplay(fake3d *);
    void fake3d_corridor(unsigned char *);
    
    int main(void)
    {   
        fake3d display;
    
        initDisplay(&display);
    
        fake3d_corridor(display.screen);
        puts(display.screen);
        getchar();
    
        return 0;
    }
    
    void initDisplay(fake3d *tmp)
    {
        memset(tmp->screen, ' ', MAX_COLS * MAX_ROWS);
        tmp->screen[MAX_COLS * MAX_ROWS] = 0;
    }
    
    void fake3d_corridor(unsigned char *buf)
    {
        int i, j = 1;
    
        for(i=0; i < MAX_ROWS; ++i)
        {
            memset(&buf[i * MAX_COLS], WALL_LT, 20);
            memset(&buf[i * MAX_COLS] + 60, WALL_LT, 20);
        }
    
        for(i=0; i < MAX_ROWS; ++i)
        {
            if(i < 8)
            {
                memset(&buf[i * MAX_COLS] + 20, WALL_MD, j);
                memset(&buf[i * MAX_COLS] + (52 + 8 - j), WALL_MD, j);
                ++j;
            }
            else if(i == 8)
            {
                j = 8;
                memset(&buf[i * MAX_COLS] + 20, WALL_MD, j);
                memset(&buf[i * MAX_COLS] + 52, WALL_MD, j);
            }
            else if(i > 16)
            {
                if(j >= 0)
                {
                    memset(&buf[i * MAX_COLS] + 20, WALL_MD, j);
                    memset(&buf[i * MAX_COLS] + (52 + 8 - j), WALL_MD, j);
                }
    
                --j;
            }
            else
            {
                memset(&buf[i * MAX_COLS] + 20, WALL_MD, j);
                memset(&buf[i * MAX_COLS] + 52, WALL_MD, j);
            }
        }
    }
    
    void fake3d_faceWall(unsigned char *buf)
    {
        int i;
    
        for(i=0; i < MAX_ROWS; ++i)
            memset(&buf[i * MAX_COLS], WALL_LT, MAX_COLS);
    }

    it's standard c, so if there are no errors, it should compile with any c compiler.

  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭

    I've managed to find my copy of BCC 5.5 (free command line tools version), but it lacks the graphics stuff. It runs without the need for dosbox though. Ah pointers... they bring back a lot of unpleasant memories. :P How about something like

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #pragma pack(1)
    
    typedef struct
    {
        char name[20];
        char seat;
        float cost;
    } S_DATA;
    
    int writeRecords(FILE *, S_DATA *, int);
    int readARecord(FILE *, S_DATA *, int);
    int readAllRecords(FILE *, S_DATA *, int);
    
    int main(void)
    {
        FILE *f = fopen("data.dat", "wb");
    
        if(f)
        {
            S_DATA sdata[] = { { "name 1", 'A', 10.0 },
                               { "name 2", 'B', 15.0 },
                               { "name 3", 'C', 20.0 },
                               { "name 4", 'D', 25.0 },
                               { "name 5", 'E', 30.0 }
                             };
    
            S_DATA test = { "Test", 'Z', 100.0 };
    
            printf("write file returned %d\n", 
                 writeRecords(f, sdata, sizeof(sdata)/sizeof(sdata[0])));
            printf("write test returned %d\n", 
                 writeRecords(f, &test, 1));
    
            fclose(f);
        }
    
        // read back record 3
    
        f = fopen("data.dat", "rb");
    
        if(f)
        {
            S_DATA record = { 0 };
            S_DATA *all = malloc(sizeof(S_DATA) * 6);
    
            printf("read record 3 returned %d\n", 
                 readARecord(f, &record, 3));
    
            // print record's contents
            printf("\n\nname: %s\nseat: %c\ncost: %0.2f\n",
                   record.name, record.seat, record.cost);
    
            if(all)
            {
                int i;
                memset(all, 0, sizeof(S_DATA) * 6);
                printf("\n\nread all records returned %d\n", 
                     readAllRecords(f, all, 6));
    
                for(i=0; i < 6; ++i)
                {
                    printf("\n--- RECORD [%d] ---\n\nname: %s\nseat: %c\ncost: %0.2f\n\n",
                           i + 1, all[i].name, all[i].seat, all[i].cost);
                }
    
                free(all);
            }
            fclose(f);
        }
    
        getchar();
        return 0;
    }
    
    int writeRecords(FILE *f, S_DATA *tmp, int nelements)
    {
        return fwrite((S_DATA *)tmp, sizeof(S_DATA) * nelements, 1, f);
    }
    
    int readARecord(FILE *f, S_DATA *tmp, int record)
    {
        if(record < 0)
            record = 1;
    
        fseek(f, (record - 1) * sizeof(S_DATA), SEEK_SET);
        return fread((S_DATA *)tmp, sizeof(S_DATA), 1, f);
    }
    
    int readAllRecords(FILE *f, S_DATA *tmp, int nelements)
    {
        fseek(f, 0L, SEEK_SET);
        return fread((S_DATA *)tmp, sizeof(S_DATA) * nelements, 1, f);
    }
    
  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭

    @tienkhoanguyen said:
    I am still trying to understand the asterisk sign in C.

    do you mean pointers?

  • pseudocoderpseudocoder Member Posts: 701 ✭✭✭

    Do you mean casting? I'll cast void * since it helps me visualize what data type I'm trying to make use of; for example, the fwrite / fread functions.

    size_t fwrite ( void * ptr, size_t size, size_t count, FILE * stream );
    size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
    
    unsigned char buffer[100];
    fwrite((unsigned char *)buffer, sizeof(buffer), 1, file_ptr);
    
    void somefunc(const void *var)
    {
        int x = *(const int *)var;
    
        printf("x = %d", x);
    }
    
    inside main()
    
    int num = 110;
    somefunc(&num);
    // or maybe
    somefunc((const int *)&num);
    
«1
Sign In or Register to comment.