2014-10-25 5 views
0

Этого определения структуры, что я пытаюсь писать копии и читать из двоичного файлаКак устранить ошибку сегментации при чтении/записи в двоичный файл в C

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

Это мой код для записи двоичный файл (состояние автомобиля)

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

Это мой код для чтения из двоичного файла (для состояния автомобиля)

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

В прошлый раз я получил ошибку сегментации, не выделяя память новому автомобилю Why am I getting a segmentation failure?. На этот раз я сделал это. Я проверил этот Segmentation fault when reading a binary file into a structure и Segmentation fault while reading binary file in C, но мои поля были значениями, а не указателями. Кто-нибудь видит вопиющую проблему? Я не могу проверить что-либо bc всякий раз, когда я пытаюсь запустить это, я получаю эту ошибку. Проблема заключается в чтении, но я не уверен, что какой-то код в записи вызывает сбой чтения.

+2

Вы не записали терминатор нулевого символа для своих строк (strlen не включает это). На самом деле вам лучше писать 'sizeof' свои массивы, записывая все 20 байтов. Таким образом, каждая из ваших записей данных будет иметь тот же размер, и вы можете обращаться к ним напрямую, а не последовательно (если хотите). – ooga

+0

Я сделал терминатор, хотя с этой строкой. model [count] = 0; – committedandroider

+0

ooga я бы, но разве нехорошо быть под впечатлением, что вы не знаете, как долго будет строка? – committedandroider

ответ

0

'0' не является нулевым терминатором. 0 или '\ 0' (обратите внимание на отсутствие кавычек на первом и escape-символ на втором). '0' - значение 48, а не ноль.

Это допустимые варианты.

char separator = 0; 

или

char separator = '\0'; 

У вас ошибка:

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

Во-вторых, вы можете упростить код, а не писать разделитель нулевой как отдельный шаг, просто напишите полный строка, включая нулевой ограничитель.

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

Однако, как вы собираетесь читать строки назад? Какой вызов функции вы собираетесь использовать для чтения строки в двоичном формате, которая может быть переменной длины, с нулевым терминатором? Лучше было бы просто написать заполненный буфер, используя sizeof вместо strlen.

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

Однако, даже это является хрупким, потому что SizeOf() молча возвращает другое значение, если ваши элементы этой структуры изменяются из массива фиксированного символа в строку символов (указатель). Вы более безопасны с использованием констант.

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); 
+0

Спасибо за это, но я все равно получаю ошибку сегментации. разделитель имеет для меня больше смысла в этой ситуации – committedandroider

+0

Вы все еще получаете seg-ошибку после фиксации терминатора от '0' до 0? – codenheim

+0

да. Я могу получить часть кода для запуска. год был написан и прочитан отлично – committedandroider

Смежные вопросы