【问题标题】:C: Writing and Reading a string to and from a binary fileC:在二进制文件中写入和读取字符串
【发布时间】:2010-03-10 08:47:26
【问题描述】:

我想将字符串以及许多其他数据存储在二进制文件中,我使用下面的代码(当我真正使用它时,字符串将被 malloc'd)我可以写入文件。我在十六进制编辑器中查看了它。我不确定我是否正确地编写了空终止符(或者如果我需要)。当我读回时,我得到的字符串长度与我存储的相同,但不是字符串。我做错了什么?

FILE *fp = fopen("mybinfile.ttt", "wb");

char drumCString[6] = "Hello\0";
printf("%s\n", drumCString);    
//the string length + 1 for the null terminator
unsigned short sizeOfString = strlen(drumCString) + 1;
fwrite(&sizeOfString, sizeof(unsigned short), 1, fp);

//write the string
fwrite(drumCString, sizeof(char), sizeOfString, fp);

fclose(fp);

fp = fopen("mybinfile.ttt", "rb");  

unsigned short stringLength = 0;
fread(&stringLength, sizeof(unsigned short), 1, fp);

char *drumReadString = malloc(sizeof(char) * stringLength);
int count = fread(&drumReadString, sizeof(char), stringLength, fp);

//CRASH POINT
printf("%s\n", drumReadString);

fclose(fp); 

【问题讨论】:

    标签: c string binaryfiles


    【解决方案1】:

    我看到了几个问题,有些问题,有些风格。

    • 您应该真正测试来自mallocfreadfwrite 的返回值,因为分配可能会失败,并且无法读取或写入任何数据。
    • sizeof(char)总是1,不需要乘以它。
    • 字符数组"Hello\0"实际上是7个字节长。您无需添加多余的空终止符。
    • 我更喜欢成语char x[] = "xxx";,而不是指定一个确定的长度(当然,除非你想要一个比字符串更长的数组)。
    • 当您fread(&drumReadString ... 时,您实际上是在覆盖指针,而不是它指向的内存。这是你崩溃的原因。应该是fread(drumReadString ...

    【讨论】:

      【解决方案2】:

      几个提示:

      1

      终止 \0 隐含在任何双引号字符串中,并且通过在末尾添加一个附加值,您最终会得到两个。以下两个初始化是相同的:

      char str1[6] = "Hello\0";
      char str2[6] = { 'H', 'e', 'l', 'l', 'o', '\0', '\0'};
      

      所以

      char drumReadString[] = "Hello";
      

      就足够了,指定数组的大小是可选的,这样初始化的时候,编译器会算出需要的大小(6字节)。

      2

      在写字符串的时候,还不如一次性写完所有字符(而不是一个一个字符的 sizeOfString 次):

      fwrite(drumCString, sizeOfString, 1, fp);
      

      3

      尽管对于普通的台式电脑场景来说并不常见,但 malloc 可以返回 NULL,您将从养成始终检查结果的习惯中受益,因为在嵌入式环境中,获得 NULL 并非不可能的结果。

      char *drumReadString = malloc(sizeof(char) * stringLength);
      if (drumReadString == NULL) {
              fprintf(stderr, "drumReadString allocation failed\n");
              return;
      }
      

      【讨论】:

      • 谢谢你,有一段时间了,我一直生活在托管代码领域。 cmets 非常感谢。
      【解决方案3】:

      你在阅读时做错了。 您已将 & 用于指针变量,这就是它给出分段错误的原因。

      我删除了它工作正常并且正确返回 Hello。

      int count = fread(drumReadString, sizeof(char), stringLength, fp);
      

      【讨论】:

        【解决方案4】:

        你不写终止NUL,你不需要,但你必须考虑在阅读时添加它。即 malloc stringLength + 1 char,读取 stringLength chars 并在已读取内容的末尾添加\0

        现在通常的警告是:如果您以此处的方式编写二进制文件,则有许多未说明的假设使您的格式难以移植,有时甚至移植到同一编译器的另一个版本——我见过编译器版本之间的结构更改的默认对齐方式。

        【讨论】:

          【解决方案5】:

          更多内容要添加到 paxdiablo 和 AProgrammer - 如果您将来要使用 malloc,只需从一开始就这样做。这是更好的形式,意味着您在切换时不必调试。

          此外,我还没有完全了解 unsigned short 的用法,如果您打算编写二进制文件,请考虑 unsigned char 类型通常是大小字节,这非常方便。

          【讨论】:

            【解决方案6】:

            您只需在 fread 函数中删除您的 &drumReadString。您只需在该函数中使用drumReadString,如 ganesh 所述。因为,drumReadString 是一个数组。数组类似于直接指向内存位置的指针。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-06-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多