Thread: Read a file (binary) into an array of structs

  1. #1
    Registered User
    Join Date
    Apr 2009
    Posts
    2

    Read a file (binary) into an array of structs

    Hi, I am writing a program that writes data to a file in binary mode and then lets you read it back in but I am having trouble with getting it to read anything from the file using fread().

    Code:
    void reportStats(struct engineer *engineers) {
         FILE *filePtr;
         filePtr = fopen("BOCTable.dat", "rb");
         char choice;
         int i;
         printf("Please select the type of report you require\n\n");
         printf("\ta\tList of all assigned engineers\n");
         printf("\tc\tList of all on-call engineers\n\n");
         printf("Please enter your choice: ");
         scanf("%c", &choice);
         fflush(stdin);
         if(choice == 'a') {
                   fread(engineers, sizeof(struct engineer), 64, filePtr);
                   for(i=0; i<64; i++) {
                           if(engineers[i].assignmentState == 'a') {
                                printf("\n\n%s\n", engineers[i].name);
                           }
                   }
         }
         else if(choice == 'c') {
              fread(engineers, sizeof(struct engineer), 64, filePtr);
              for(i=0; i<64; i++) {
                       if(engineers[i].assignmentState == 'c') {
                                printf("\n\n%s\n", engineers[i].name);
                           }
                   }
         }
         getch();
    }
    Now for some reason, all that does is go to a new line and print nothing. I have set up a counter variable that is used to write each engineer into the next element of the struct array but for some reason, the counter is showing 2618116 instead of 1/2/3 etc each time I add a new engineer.

    If more code is needed, I can provide the whole file that I have so far.

  2. #2
    Registered User Drogin's Avatar
    Join Date
    Oct 2005
    Location
    Norway
    Posts
    105
    I implemented my own write-function and compiled it with the code you supplied.
    Worked like a charm.

    So the problem are PROBABLY somewhere else in your code.
    But stay with me.

    #1. Try to avoid using getch(). I don't think it's part of the ANSI/ISO standard.

    #2. Try to avoid using magic numbers in your code. (Why did you use exactly 64?)
    Do something like this instead:
    Code:
    int numberOfEngineers = 64;
    and use the variable instead.


    #3. Put on some errorchecking on those stream-functions. Check for errors.
    For example:
    Code:
      pFile = fopen ( "myfile.bin" , "rb" );
      if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
    This way you'll detect if something's wrong with the file I/O, and not your code.

    #4. Why are you flushing stdin?
    fflush() makes sure buffers are written to a file.
    stdin is input, not output(means this stream are used for reading, not writing).
    So what actually happens here is implementation-dependent.
    Put simply: there's no reason to call fflush() on stdin.




    About the code that you didnt supply,there are 2 things I suspect:
    #1. Did you make sure you closed/flushed the output-stream? (The stream you used for writing).

    #2. When you call the reportStats(struct engineer *engineers) function, did you remember to supply a pointer to an array that is large enough?
    Because the reportStats() function reads all 64 engineers and puts them into the memory where the pointer you supplied are.

    So you would have to do something like this when you call the function:
    Code:
    int main() {
      engineer data[64];
      reportStats(data); // The data-pointer now holds enough space in memory for 64 structs  
      return 0;
    }
    Last edited by Drogin; 04-11-2009 at 06:00 PM.

  3. #3
    Registered User
    Join Date
    Apr 2009
    Posts
    2
    Thanks for the reply. I know about the error checking, just didn't put it in here for some reason.

    Anyway, I used 64 because at the start of my main method, I created an array of structs as
    Code:
    struct engineer engineerTable[64];
    I used getch() as a test in that function while trying to debug.

    Full code so far:

    Code:
    #include <stdio.h>
    #include "printh.h"
    
    struct engineer {
           int contractNumber;
           char name[16];
           int age;
           char sex;
           char language[20];
           char assignmentState;
    };
    
    void loadData();
    void clearEngineers();
    void addEngineer(struct engineer *, int);
    void assignEngineer(struct engineer *);
    void addField();
    void reportStats(struct engineer *);
    void saveData();
    void displayMenu();
    void displayHeader();
    
    
    int main() {
        
        char choice;
        int count;
        struct engineer engineerTable[64];
        
        do {
            displayHeader();
            displayMenu();
            scanf("%c", &choice);     
            fflush(stdin);  
            if(choice == 'e') {
                 system("cls");
                 addEngineer(engineerTable, count);
                 system("cls");
            }
            else if(choice == 'o') {
                 system("cls");
                 addField();
                 system("cls");
            }
            else if(choice == 'a') {
                 system("cls");
                 assignEngineer(engineerTable);
                 system("cls");
            }
            else if(choice == 'r') {
                 system("cls");
                 reportStats(engineerTable);
                 system("cls");
            }
            else if(choice == 'c') {
                 system("cls");
                 clearEngineers();
                 system("cls");
            }
            else if(choice == 'x') {
                 break;
            }
            else {
                 printf("\n\nThat is not a valid option...\n\n");
                 sleep(600);
                 system("cls");
            }
        }
        while(choice != 'x');
        return 0;
        
    }
    
    void displayHeader() {
         printH("BOC Pipeline Engineer Management Console");
    }
    
    void displayMenu() {
         printf("\te\tEnter a new engineer\n");
         printf("\to\tEnter a new oil field\n");
         printf("\ta\tAssign an engineer to field\n");
         printf("\tr\tGenerate a report\n");
         printf("\tc\tClear the engineer table\n");
         printf("\tx\tExit and save\n\n");
         printf("Please enter your choice: ");
    }
    
    void loadData() {
    }
    
    void clearEngineers() {
         char temp;
         FILE *filePtr;
         filePtr = fopen("BOCTable.dat", "w");
         if(filePtr == NULL) {
                    printf("There was an error while opening the file, please try again.");
         }
         else {
              printf("Are you sure you wish to clear the database? (y/n): ");
              scanf("%c", &temp);
              fflush(stdin);
              if(temp == 'y') {
                      fprintf(filePtr, "");
                      fclose(filePtr);
                      printf("\n\nData successfully erased :)");
                      sleep(700);
              }
              else if(temp == 'n') {
                   printf("\nExiting to main menu");
                   sleep(700);
              }
         }
    }
    
    void addEngineer(struct engineer *engineers, int counter) {
         FILE *filePtr;
         filePtr = fopen("BOCTable.dat", "ab+");
         if(filePtr == NULL) {
                    printf("There was an error while opening the file. Please try again");
         }
         else {
              fread(counter, sizeof(int), 1, filePtr);
              printf("counter is %d\n\n", &counter);
              printf("\nPlease enter the name of the engineer: ");
              scanf("%s", engineers[counter].name);
              printf("\nPlease enter the age of the engineer: ");
              scanf("%d", &engineers[counter].age);
              fflush(stdin);
              printf("\nPlease enter the sex of the engineer (m or f): ");
              scanf("%c", &engineers[counter].sex);
              fflush(stdin);
              printf("\nPlease enter the contract number of the engineer: ");
              scanf("%s", &engineers[counter].contractNumber);
              fflush(stdin);
              printf("\nPlease enter the language spoken by the engineer: ");
              scanf("%c", &engineers[counter].language);
              fflush(stdin);
              printf("\nPlease enter engineer assignment type (a - assigned/c - on call): ");
              scanf("%c", &engineers[counter].assignmentState);
              fflush(stdin);
              
              counter++;
              fwrite(&counter, sizeof(int), 1, filePtr);
              fwrite(engineers, sizeof(struct engineer), 64, filePtr);
              fclose(filePtr);
         }
    }
    
    void assignEngineer(struct engineer *engineers) {
    }
    
    void addField() {
    }
    
    void reportStats(struct engineer *engineers) {
         FILE *filePtr;
         filePtr = fopen("BOCTable.dat", "rb");
         if(filePtr == NULL) {
                    printf("There was an error opening the file, please try again");
                    exit(1);
         }
         else {
              char choice;
              int i;
              printf("Please select the type of report you require\n\n");
              printf("\ta\tList of all assigned engineers\n");
              printf("\tc\tList of all on-call engineers\n\n");
              printf("Please enter your choice: ");
              scanf("%c", &choice);
              fflush(stdin);
              if(choice == 'a') {
                   fread(engineers, sizeof(struct engineer), 64, filePtr);
                   for(i=0; i<64; i++) {
                           if(engineers[i].assignmentState == 'a') {
                                printf("\n\n%s\n", engineers[i].name);
                           }
                   }
              }
              else if(choice == 'c') {
                   fread(engineers, sizeof(struct engineer), 64, filePtr);
                   for(i=0; i<64; i++) {
                       if(engineers[i].assignmentState == 'c') {
                                printf("\n\n%s\n", engineers[i].name);
                           }
                   }
              }
              getch();
         }
    }
    
    void saveData() {
    }

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Now for some reason, all that does is go to a new line and print nothing. I have set up a counter variable that is used to write each engineer into the next element of the struct array but for some reason, the counter is showing 2618116 instead of 1/2/3 etc each time I add a new engineer.


    If more code is needed, I can provide the whole file that I have so far.
    I think we should take a peek at this counter, don't you?

    Yes, more code is needed.

    fflush works reliably only on ouput streams, not input. you can pull the newline off the keyboard buffer by using a getchar(), right after the scanf().

    Vart also showed a neat tip for this, adding one space just before the %c in
    scanf(" %c", charVariable);

    makes scanf() pass over the left over newline char, with nary a whimper.

    Vart may not be Jewish, but I think of this as the "Passover" tip.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Newbie homework help
    By fossage in forum C Programming
    Replies: 3
    Last Post: 04-30-2009, 04:27 PM
  2. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  3. Read file in 2D array
    By Chook in forum C Programming
    Replies: 1
    Last Post: 05-08-2005, 12:39 PM
  4. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM