0

I have a structure in C whose object I am writing to a file in C, while reading the same file again the last object is getting repeated two times. How can I resolve this and why is this happening?

#include<stdio.h>                                                                                                                                                                                                
#include<string.h>                                                                                                                                                                                               

typedef struct car {                                                                                                                                                                                             
    int id;                                                                                                                                                                                                      
    char *name;                                                                                                                                                                                                  
    int price;                                                                                                                                                                                                   
    char *colors[5];
} car;

int main()
{
    car obj1 = { .id = 5,
                .name =  "honda city zx",
                .price =  1500, 
                .colors = {"red", "black", "blue"}
    };
    car obj2 = { .id = 6,
                .name =  "honda city",
                .price =  2500,
                .colors = {"lal", "kala", "neela"} 
    };
    FILE *fp;
    fp = fopen("car_details.dat", "w");
    fwrite(&obj1, sizeof(obj1), 1, fp); 
    fwrite(&obj2, sizeof(obj2), 1, fp);
    fclose(fp);
    fp = fopen("car_details.dat", "r");
    car obj;
    while(!feof(fp))
    {
        fread(&obj, sizeof(obj), 1, fp);
        printf("id : %d\nname : %s\nprice : %d\ncolors : {%s, %s, %s}\n", obj.id, obj.name, obj.price, obj.colors[0], obj.colors[1], obj.colors[2]);
    }

    return 0;
}

The output is :

id : 5                                                                                                                                                                                                           
name : honda city zx                                                                                                                                                                                             
price : 1500                                                                                                                                                                                                     
colors : {red, black, blue}                                                                                                                                                                                      
id : 6                                                                                                                                                                                                           
name : honda city                                                                                                                                                                                                
price : 2500                                                                                                                                                                                                     
colors : {lal, kala, neela}                                                                                                                                                                                      
id : 6                                                                                                                                                                                                           
name : honda city                                                                                                                                                                                                
price : 2500                                                                                                                                                                                                     
colors : {lal, kala, neela}  

However the expected output was each object to be printed once.

id : 5                                                                                                                                                                                                           
name : honda city zx                                                                                                                                                                                             
price : 1500                                                                                                                                                                                                     
colors : {red, black, blue}                                                                                                                                                                                      
id : 6                                                                                                                                                                                                           
name : honda city                                                                                                                                                                                                
price : 2500                                                                                                                                                                                                     
colors : {lal, kala, neela}  

So my question is why is this happening and how can I resolve this?

EDIT : When I tried printing the position of my pointer inside the loop

while(!feof(fp)) 
{
    fread(&obj, sizeof(obj), 1, fp);
    printf("The pointer is at %ld\n", ftell(fp));                                                                                                                                                        
    printf("id : %d\nname : %s\nprice : %d\ncolors : {%s, %s, %s}\n\n", obj.id, obj.name, obj.price, obj.colors[0], obj.colors[1], obj.colors[2]);
}

I was getting :

The pointer is at 64                                                                                                                                                                                             
{object}                                                                                                                                                                                    

The pointer is at 128                                                                                                                                                                                            
{object}                                                                                                                                                                                     

The pointer is at 128 
{object} 

How is this possible? I have read that whenever fread reads the stream , it shifts the pointer after reading that much number of bytes. So when this time the loop ran for the second time it should have shifted the file pointer to the end of file but it didn't. Why is this happening? Am I lacking any concept? Please pardon me I am a beginner!

Kitpul Bhatt
  • 34
  • 1
  • 7
  • 28
  • Its because feof test a flag that is only set after trying to read beyond the end of file. After you have read the two first records, the flag will not be set. When you do the third read, it will read 0 bytes and set the flag stating that the end of file has been reached. The next call the feof will detect that the end of file flag has been set. So in order to detect if the end of file is reached, you must test the number of bytes read by the `read` function. It will be 0 when the end of file is reached. The content if the read buffer will be whatever was there before the read. – chmike Feb 10 '20 at 13:20
  • There is another problem with this code. When you write `obj1` and `obj2`, you don't write the strings in the file. You only write the pointers to the first characters of the strings. Look into the file, you won't see the strings. The output yields the expected result because the pointer are still valid after the read. This wouldn't work if you read the objects from another function. Try it. – chmike Feb 10 '20 at 13:26
  • So how should I write can you please guide me the correct way – Kitpul Bhatt Feb 10 '20 at 13:27
  • for testing the return value of `read` use the following code: `while (fread(&obj, sizeof(obj), 1, fp) == sizeof(obj)) { ... }`. For saving and retrieving the record with strings, it is more complicate and can't be explained in a comment. There is no simple solution with C. Sorry. – chmike Feb 10 '20 at 13:36
  • does that mean, I have to explicitly store the data pointed by the pointers – Kitpul Bhatt Feb 10 '20 at 16:00
  • yes and there are different way to do it. In fact, you should write the individual data fields one by one in the file, and reverse the operation to read them. When writing multibyte values like integer, float or double you must also take care of endianess. This mean pick one and use it consistently. Another solution is to write the object fields in ASCII. No need to take care of endianess. You could use one line per object, etc. – chmike Feb 10 '20 at 16:07

0 Answers0