【问题标题】:How are char ** objects saved? [closed]char ** 对象是如何保存的? [关闭]
【发布时间】:2013-05-09 05:18:21
【问题描述】:

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

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)

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

【问题讨论】:

  • 您的程序不可能产生这些结果,因为字符串从未写入文件。哎呀,您发布的代码甚至没有从文件中读取。所以这是一个巨魔帖子。
  • char** 不是对象,而是指针。字节保存在文件中。
  • 下次您在 SO 提出问题时,发布您运行的实际代码,不要从内存中重构它,或者用一堆省略号对其进行编辑。这对于那些对 C 了解甚少并倾向于产生各种他们没有意识到是错误的错误想法的初学者来说尤其重要。

标签: c arrays string file memory


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 所以要保存一个像“Foo”、“Long string”和“Bar”这样的字符串数组,我必须实现自己的数组结构?
    • @PaulA.Warkentin 你为什么要发布巨魔问题?您发布的代码不可能产生您声称的结果。
    • @JimBalter - 不幸的是它的行为可能是这样的 - 但前提是读取和写入是在可执行文件的同一运行中完成的。读取的指针可能指向写入的相同静态文字。在很多层面上它仍然是“错误的”,但它是可能的。
    • @Roddy,不,它不能,因为 OP 的代码在打印其内容之前将 array 设置为 malloc 的结果,并且从不读入它。 OP 显然没有发布实际的代码......它可能只是打印相同的数组而不更改它......或者它可能会重新读取相同的地址,正如你所建议的那样。但是为什么要猜测 OP 什么时候会发布这样的废话呢?
    • @JimBalter:实际上 array 是 malloc 的,但是它的内容被设置为指向字符串文字的指针,然后这些指针被保存到文件中,因此 array 具有动态地址没有发挥作用。
    猜你喜欢
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 2013-02-09
    • 2021-03-20
    • 2018-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多