【问题标题】:How to resolve segmentation error in reading/writing to binary file in C如何解决在 C 中读取/写入二进制文件时的分段错误
【发布时间】:2014-10-25 23:48:43
【问题描述】:

这是我试图写入和读取二进制文件副本的结构定义

   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 structureSegmentation fault while reading binary file in C,但我的字段是值,而不是指针。 有没有人看到一个明显的问题?每当我尝试运行它时,我都无法测试任何东西,我得到了那个错误。问题似乎是阅读,但我不确定写作中的某些代码是否导致阅读失败

【问题讨论】:

  • 您没有为您的字符串写出空字符终止符(strlen 不包括它)。实际上,你最好写sizeof你的数组,写所有20个字节。这样一来,您的每条数据记录都将具有相同的大小,因此您可以直接访问它们,而不是按顺序访问它们(如果您愿意的话)。
  • 我用这条线做了终结者。模型[计数] = 0;
  • 错字。 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);
  • 不用担心(不正确的)分隔符,只需将二进制字符串写为 strlen(s)+1

标签: c file binary structure


【解决方案1】:

'0' 不是空终止符。 0 或 '\0' 是(注意第一个没有引号,第二个没有转义字符)。 '0' 是值 48,而不是零。

这些是有效的选项。

char separator = 0;

char separator = '\0';

你有一个错误:

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

其次,您可以简化代码,而不是将分隔符 null 作为单独的步骤编写,只需写出完整的字符串,包括 null 终止符。

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' 修复为 0 后仍然出现 seg 错误?
  • 是的。我现在可以得到一些代码来运行。一年写得很好,读得很好
  • 记住 string[20] 只能容纳 19 个字符,第 20 个即 string[19] 是 nul 字节 '\0'
猜你喜欢
  • 1970-01-01
  • 2014-05-02
  • 2021-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多