0

This is the struct definition that I am trying to write copies of to and read from binary file

   typedef struct carType Car;
struct carType {
   int vehicleID;
   char make[20];
   char model[20];
   int year;
   int mileage;
   double cost;
   Car *next;
};

This is my code for writing to a binary file(state of the Car)

   void writeBinFile(Car *headPointer)
{
     char fileName[20];
     //prompt user for name of textfile to print to 
    scanf("%s", fileName);
    FILE *ftp;
    Car *start =  headPointer->next;
    ftp = fopen(fileName, "wb");
    char separator = '0';
    while(start != NULL)
    {
       //write out 1 cell of data, cell contains 4 bytes
        fwrite(&start->year,sizeof(int), 1, ftp);
        fwrite(start->make,sizeof(char), strlen(start->make), ftp);
        fwrite(&separator, sizeof(char), 1, ftp); 
        fwrite(start->model, sizeof(char), strlen(start->make), ftp);
        fwrite(&separator, sizeof(char), 1, ftp);
        fwrite(&start->cost, sizeof(float), 1, ftp);
        fwrite(&start->mileage, sizeof(float),1,ftp);
        fwrite(&start->vehicleID, sizeof(int), 1, ftp);
        start = start->next;
    }
    fclose(ftp);
}

This is my code for reading from a binary file(to state of the car)

    void readFromBinFile(Car *headPointer)
{
      char fileName[20];
     //prompt user for name of textfile to print to 
    scanf("%s", fileName);
    FILE *ftp;
    Car *previous =  headPointer;
    ftp = fopen(fileName, "rb");
    Car *current;
    //go until the end of file is reached
    while(!feof(ftp))
    {
            current = (Car *)malloc(sizeof(Car));
            previous->next = current;
             //program receives 1 cell, that cell contains 4 bytes
             fread(&current->year, sizeof(int),1,ftp);
             printf("%d\n",current->year);
             char make[25];
             int count = 0;
             char oneAtATime= 'a';
             while(oneAtATime != '0') 
             { 
                    fread(&oneAtATime, sizeof(char),1,ftp);
                   if(oneAtATime!='0')
                   {
                      make[count] = oneAtATime;
                        count++;
                   }
            } 
            make[count] = 0;
           strcpy(current->make, make);
             char model[25];
              count = 0;
              oneAtATime= 'a';
             while(oneAtATime != '0') 
             { 
                    fread(&oneAtATime, sizeof(char),1,ftp);
                   if(oneAtATime!='0')
                   {
                      model[count] = oneAtATime;
                        count++;
                   }
            } 
            model[count] = 0;
           strcpy(current->model, model);
           fread(&current->cost, sizeof(float),1, ftp);
           fread(&current->mileage, sizeof(int),1,ftp);
           fread(&current->vehicleID, sizeof(int),1,ftp);
         previous = previous->next;
    } 
    fclose(ftp);
} 

Last time I got a segmentation error from not allocating memory to the new car Why am I getting a segmentation failure?. I made sure to do that this time. I checked this one Segmentation fault when reading a binary file into a structure and Segmentation fault while reading binary file in C but my fields were values , not pointers. Does anyone see a glaring issue? I can't test anything bc whenever i try to run this, i get that error. The problem seems to be the reading but i am not sure if some code in the writing is causing the reading to fail

Community
  • 1
  • 1
committedandroider
  • 8,711
  • 14
  • 71
  • 126
  • 2
    You didn't write out the null-character terminator for your strings (strlen doesn't include that). Actually, you'd be better writing `sizeof` your arrays, writing all 20 bytes. That way, each of your data records will have the same size and you could therefore access them directly as opposed to sequentially (if you wished to). – ooga Oct 25 '14 at 23:54
  • I did the terminator though with this line. model[count] = 0; – committedandroider Oct 25 '14 at 23:59
  • ooga i would but isnt good to be under the impression that you dont know how long a string is? – committedandroider Oct 26 '14 at 00:02
  • typo typo. `fwrite(start->model, sizeof(char), strlen(start->make), ftp);` --> `fwrite(start->model, sizeof(char), strlen(start->model), ftp);`, `fwrite(&start->cost, sizeof(float), 1, ftp);fwrite(&start->mileage, sizeof(float),1,ftp);` --> `fwrite(&start->cost, sizeof(double), 1, ftp);fwrite(&start->mileage, sizeof(int),1,ftp);` – BLUEPIXY Oct 26 '14 at 00:03
  • like i would do that, but make isn't going to be set 25 letters – committedandroider Oct 26 '14 at 00:06
  • You set your separator to the character `0`, not the null-terminator `\0`. I don't understand your "don't know how long a string is" comment. If you wrote the whole 20 bytes, it would include the null-terminator, so you would know how long it was. – ooga Oct 26 '14 at 00:09
  • 1
    Instead of bothering with the (incorrect) separator, just write strings in binary as strlen(s)+1 – codenheim Oct 26 '14 at 00:12

1 Answers1

0

'0' is not the null terminator. 0 or '\0' are (note the lack of quotes on the first and the escape char on 2nd). '0' is value 48, not zero.

These are valid options.

char separator = 0;

or

char separator = '\0';

You have an error:

fwrite(start->model, sizeof(char), strlen(start->make), ftp);   // 'make' size used to write 'model'

Secondly, you can simplify your code rather than writing the separator null as a separate step, just write out the full string, including null terminator.

fwrite(start->make, 1, strlen(start->make) + 1, ftp);

However, how do you intend to read the strings back in? What function call are you going to use to read a string in binary that maybe variable length, with a null terminator? Better would be to just write the padded buffer using sizeof instead of strlen.

fwrite(start->make, 1, sizeof(start->make), ftp);

However, even this is brittle, because sizeof() will silently return a different value if your struct members are changed from a fixed character array to a character string (pointer). You are safer using constants.

const int SMALL_STRING_LEN = 20;
const int MAKE_LEN = SMALL_STRING_LEN;
const int MODEL_LEN = SMALL_STRING_LEN;

char make[MAKE_LEN];
char make[MODEL_LEN];

fwrite(start->model, 1, MODEL_LEN, ftp);
fwrite(start->make, 1, MAKE_LEN, ftp);
codenheim
  • 20,467
  • 1
  • 59
  • 80