Reputation: 33
My program needs to read from a binary file to a linked list, this function doing it well and allocating the right memory for it but for some reason it doing another loop before it breaks. tried looking for a good solution for it with no luck, and the last struct in the linked list getting junk.
The struct:
typedef struct
{
char id[10];
char * first_name;
char * last_name;
int age;
char gender;
char * username;
char * password;
char * description;
int hobbies[4];
struct Person * next_client;
}Person;
here is some code:
Person * input_from_file(Person * member)
{
int str_size;
Person * clients_start = NULL;
FILE * filePointerRead;
filePointerRead = fopen("input.bin", "rb");
if (filePointerRead != NULL){
while (1){
member = NULL;
member = (Person*)malloc(sizeof(Person));
fread(&member->id, sizeof(char), ID_DIGITS + 1, filePointerRead);
fread(&str_size, sizeof(int), 1, filePointerRead);
member->first_name = (char*)malloc(str_size*sizeof(char));
fread(member->first_name, sizeof(char), str_size, filePointerRead);
//more reading from file
member->next_client = NULL;
clients_start = receive_clients_info(clients_start, member); //function to put the received struct from file to end of the linked list
if (feof(filePointerRead))
break;
}
fclose(filePointerRead);
}
return clients_start;
}
Upvotes: 1
Views: 6661
Reputation: 16540
any easy way to accomplish the task is:
calculating the total length of each complete record in the file
(from your code, I assume all records are the same length)
fopen( ..inputfile.. )
if fopen not successful,
then
perror()
exit( EXIT_FAILURE );
endif
// implied else, fopen successful
while(completelength == fread( the complete length into a local buffer))
{
...extract each field from local buffer into struct...
...place struct into linked list...
}
//when get here, reading/building linked list is done
fclose( inputfile )
...
Upvotes: 0
Reputation: 600
The issue you are having is that feof() does not return true until the EOF flag of a file is set, and the EOF flag of a file is not set until an attempt to read the file fails because there is no data left in the file to read.
Here is an example: imagine that the file has 1 byte in it and you have a loop that reads the file one byte at a time.
The first time through the loop, one byte is read and given back to the program. If the program tests feof() it will still return FALSE because reading the file succeeded.
The second time through the loop, all of the bytes from the file have already been read so 0 byes are read and returned to the program, at this time, the EOF flag is set because reading the file failed due to reaching the end. At this point feof() will then return TRUE.
In my example, you went through the loop twice even though there was only one byte in the file. The same is happening to your code.
To solve the problem, always check the result of the fread() call. It returns the number of items (not bytes) read. By the way, fread() will always read an entire item and never a partial item. If fread() returns fewer items than you expect, break out of the loop. Usually, you will break out of the loop because you have reached the end of the file, but there is a chance that there was some other error -- maybe somebody pulled the power cord to an external hard drive. If you want to see why fread() did not read anything, you can then use feof() or ferror().
Upvotes: 1
Reputation: 726809
The problem with calling feof
is that it wouldn't return you a "true" unless you have attempted a read when you are at the EOF
. In other words, if your file has exactly 100 bytes, and you have successfully attempted reading exactly 100 bytes, feof
would return "false" until you try reading at least one more byte.
That is the reason why you should avoid feof
in favor of checking the return value of fread
, which tells you how many bytes has been read from file:
if (fread(&member->id, sizeof(char), ID_DIGITS + 1, filePointerRead) != ID_DIGITS + 1) {
// The code above knows that sizeof(char) is always 1.
// For other data types you need to compute the actual size
// by multiplying sizeof(T) by the number of items that you read.
break;
}
Do the same in all places where you call fread
.
Comparison with !=
works because fread
always returns the exact size that you pass when it can complete the request:
Upon successful completion,
fread()
shall return the number of elements successfully read which is less thannitems
only if a read error or end-of-file is encountered.
Upvotes: 4
Reputation: 53016
Check fread()
instead of foef()
, there are many answers on Stack Overflow about that, feof()
returns true when the EOF indicator is set, fread()
will set it when reading past the end of the file.
fread()
will return 0
or less than the requested bytes when the end of the file is reached, but your program requires one extra loop in which fread()
tries to read past the end of the file, and it will set the EOF
indicator.
See this “while( !feof( file ) )” is always wrong
Upvotes: 2