如何保存char **对象?

时间:2013-05-14 19:36:22

标签: c arrays string file memory

今天,我问我,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)

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

2 个答案:

答案 0 :(得分:13)

指针被保存到数字(或更好的地址)这样的文件中,因此您的代码工作的事实是由于您可能正在保存并在同一个程序中将它们加载到同一程序中而产生的错觉(因此, string是文字,它们的地址大部分是固定在数据段中的。)

你正在做的是完全错误的,因为数据在内存中的布局如下(我假设有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);
}

答案 1 :(得分:3)

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