C语言 C:在二进制文件中写入和读取字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2415495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:47:50  来源:igfitidea点击:

C: Writing and Reading a string to and from a binary file

cstringbinaryfiles

提问by Aran Mulholland

I want to store strings in a binary file, along with a lot of other data, im using the code below (when i use it for real the strings will be malloc'd) I can write to the file. Ive looked at it in a hex editor. Im not sure im writing the null terminator correctly (or if i need to). when i read back out i get the same string length that i stored, but not the string. what am i doing wrong?

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

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

char drumCString[6] = "Hello
int count = fread(drumReadString, sizeof(char), stringLength, fp);
"; 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);

回答by sganesh

You are doing wrong while reading. you have put the & for the pointer variable that's why it gives segmentation fault.

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

I removed that it works fine and it returns Hello correctly.

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

char str1[6] = "Hello
char drumReadString[] = "Hello";
"; char str2[6] = { 'H', 'e', 'l', 'l', 'o', '
fwrite(drumCString, sizeOfString, 1, fp);
', '
char *drumReadString = malloc(sizeof(char) * stringLength);
if (drumReadString == NULL) {
        fprintf(stderr, "drumReadString allocation failed\n");
        return;
}
'};

回答by paxdiablo

I see a couple of issues, some problematic, some stylistic.

我看到了一些问题,有些是有问题的,有些是风格上的。

  • You should really test the return values from malloc, freadand fwritesince it's possible that the allocation can fail, and no data may be read or written.
  • sizeof(char)is always1, there's no need to multiply by it.
  • The character array "Hello\0"is actually 7 bytes long. You don't need to add a superfluous null terminator.
  • I prefer the idiom char x[] = "xxx";rather than specifying a definite length (unless you want an array longer than the string of course).
  • When you fread(&drumReadString ..., you're actually overwriting the pointer, not the memory it points to. This is the cause of your crash. It should be fread(drumReadString ....
  • 你真的应该从测试的返回值mallocfread并且fwrite由于它是可能的分配可能会失败,并没有数据可以被读取或写入。
  • sizeof(char)总是1,有没有必要乘以它。
  • 字符数组"Hello\0"实际上有 7 个字节长。您不需要添加多余的空终止符。
  • 我更喜欢这个习惯用法char x[] = "xxx";而不是指定一个确定的长度(除非你想要一个比字符串长的数组)。
  • 当您 时fread(&drumReadString ...,您实际上是在覆盖指针,而不是它指向的内存。这就是你崩溃的原因。应该是fread(drumReadString ...

回答by hlovdal

A couple of tips:

一些提示:

1

1

A terminating \0is implicit in any double quote string, and by adding an additional at the end you end up with two. The following two initializations are identical:

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

##代码##

So

所以

##代码##

is enough, and specifying the size of the array is optional when it is initialized like this, the compiler will figure out the required size (6 bytes).

就足够了,并且在像这样初始化时指定数组的大小是可选的,编译器会计算出所需的大小(6 个字节)。

2

2

When writing a string, you might just as well just write all characters in one go (instead of writing one by one character sizeOfString times):

写字符串时,不妨一口气写完所有字符(而不是一个一个字符写 sizeOfString 次):

##代码##

3

3

Even though not so common for a normal desktop pc scenario, malloc can return NULL and you will benefit from developing a habbit of always checking the result because in embedded environments, getting NULL is not an unlikely outcome.

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

##代码##

回答by vivek

You Just remove your &drumReadString in the fread function.You simply use drumReadString in that function as ganesh mentioned.Because,drumReadString is an array.Array is similar to pointers which point to the memory location directly.

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

回答by AProgrammer

You don't write the terminating NUL, you don't need to but then you have to think about adding it when reading. ie malloc stringLength + 1 char, read stringLength chars and add a \0at the end of what has been read.

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

Now the usual warning: if you are writing binary file the way you are doing here, you have lots of unstated assumptions which make your format difficult to port, sometimes even to another version of the same compiler -- I've seen default alignment in struct changes between compiler versions.

现在是通常的警告:如果您按照这里的方式编写二进制文件,您有很多未说明的假设,这使您的格式难以移植,有时甚至移植到同一编译器的另一个版本——我已经看到了默认对齐方式编译器版本之间的结构变化。

回答by zellio

Some more to add to paxdiablo and AProgrammer - if you are going to use malloc in the future, just do it from the get go. It's better form and means you won't have to debug when switch over.

还有一些要添加到 paxdiablo 和 AProgrammer - 如果您将来要使用 malloc,请从一开始就使用。这是更好的形式,意味着您不必在切换时进行调试。

Additionally I'm not fully seeing the use of the unsigned short, if you are planning on writing a binary file, consider that the unsigned char type is generally of size byte, making it very convenient for that purpose.

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