# Read a file (binary) into an array of structs

This is a discussion on Read a file (binary) into an array of structs within the C Programming forums, part of the General Programming Boards category; Hi, I am writing a program that writes data to a file in binary mode and then lets you read ...

1. ## 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");
scanf("%c", &choice);
fflush(stdin);
if(choice == 'a') {
for(i=0; i<64; i++) {
if(engineers[i].assignmentState == 'a') {
printf("\n\n%s\n", engineers[i].name);
}
}
}
else if(choice == 'c') {
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. 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?)
Code:
int numberOfEngineers = 64;

#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;
}

3. 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 clearEngineers();
void assignEngineer(struct engineer *);
void reportStats(struct engineer *);
void saveData();

int main() {

char choice;
int count;
struct engineer engineerTable[64];

do {
scanf("%c", &choice);
fflush(stdin);
if(choice == 'e') {
system("cls");
system("cls");
}
else if(choice == 'o') {
system("cls");
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;

}

printH("BOC Pipeline Engineer Management Console");
}

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");
}

}

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') {
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 {
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 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");
scanf("%c", &choice);
fflush(stdin);
if(choice == 'a') {
for(i=0; i<64; i++) {
if(engineers[i].assignmentState == 'a') {
printf("\n\n%s\n", engineers[i].name);
}
}
}
else if(choice == 'c') {
for(i=0; i<64; i++) {
if(engineers[i].assignmentState == 'c') {
printf("\n\n%s\n", engineers[i].name);
}
}
}
getch();
}
}

void saveData() {
}

4. 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.