2

今天,我问我,char **对象是如何保存在内存中或二进制文件中的。我使用以下代码片段对其进行了测试:

char **array  = (char *)malloc(3 * sizeof(char *));

array[0] = "Foo";         // Length: 3
array[1] = "Long string"; // Length: 11
array[2] = "Bar";         // Length: 3   => Full length: 17

int length = 17;

我将此数组写入文件:

FILE *file = fopen(...);
fwrite(array, length, 1, file);
fclose(file);

很棒的是,当我使用以下代码从文件中再次读取此数组时,成功读取了字符串长度,而不会保存超过 17 个字节。

FILE *file   = fopen(...);
int   length = 17;

char **array = (char *)malloc(length);

int index        = 0;
int parsedLength = 0;
while (parsedLength < length)
{
    char *string       = array[index];
    int   stringLength = strlen(string);

    printf("%i: \"%s\" (%i)\n", index, string, stringLength);

    parsedLength += stringLength;
    ++index;
}

我得到的输出等于:

0: "Foo" (3)
1: "Long string" (11)
2: "Bar" (3)

编译器如何知道数组中的每个字符串有多长?

4

2 回答 2

13

指针被保存到像数字(或更好的地址)这样的文件中,因此您的代码工作的事实是一种错觉,这是由于您可能在同一运行中将它们保存并加载到同一个程序中(所以因为这些字符串是文字,它们的地址大多固定在数据段中)。

你正在做的是完全错误的,因为数组在内存中的布局如下(我假设 4 字节指针):

XXXXXXXX YYYYYYYY ZZZZZZZZ ( = 12 bytes)
   ^        ^        ^
   |        |       pointer to "Bar"
   |      pointer to "Long String"
 pointer to "Foo"

但是您将 17 个字节保存到文件中,其中 12 个只是内存地址。

要在文件中正确保存字符串,您当然需要存储包含的全部数据及其长度。就像是:

for (int i = 0; i < ARRAY_LENGTH; ++i) {
  char *string = array[i];
  unsigned int length = strlen(string);
  fwrite(&length, sizeof(unsigned int), 1, out);
  fwrite(string, sizeof(char), length, out);
}

for (int i = 0; i < ARRAY_LENGTH; ++i {
  unsigned int length;
  fread(&length, sizeof(unsigned int), 1, in);
  array[i] = calloc(sizeof(char), length);
  fread(array[i], sizeof(char), length, in);
}
于 2013-05-14T19:41:27.940 回答
3

不要认为你的程序有效。尝试编写一个读取文件的新程序,或尝试使用十六进制编辑器打开二进制文件。字符串中不存在。 char ** array是指针数组而不是 char 数组,它的大小在 32 位公共环境中为 3*4 = 12。

于 2013-05-14T19:42:23.537 回答