【问题标题】:Where are character arrays in dynamically allocated structs stored? [duplicate]动态分配的结构中的字符数组存储在哪里? [复制]
【发布时间】:2012-10-08 16:57:57
【问题描述】:

可能重复:
C Array Instantiation - Stack or Heap Allocation?

当动态分配包含 char 指针的结构时,实际的 char 指针会发生什么情况?它存储在哪里?

一旦结构体被释放,char指针是否也随之释放?

例如考虑以下结构:

struct mix
{
    int a;
    float b;
    char *s;
};

typedef struct mix mix;

然后是为它分配内存的以下代码:

int main()
{
    mix *ptr = (mix*)malloc(sizeof(mix));

    ptr->a = 3;
    ptr->b = 4.5f;
    ptr->s = "Hi, there, I'm just a really long string.";

    free(ptr);

    return 0;
}

*s 是否在堆栈上分配,然后与*ptr 一起释放?我可以想象它确实是在堆栈上分配的,因为它不是以任何方式动态分配的(除非 malloc 有一些我不知道的功能)。我猜想*s 的“超出范围”将是释放*ptr 的时候。还是我完全错了? :)

非常感谢!

【问题讨论】:

  • 根据 C 标准,您不应该知道东西在哪里。自动变量管理发生......自动。使用malloc() 动态分配的东西,co 是free()'d。如果你正确使用它们,你会得到有效的指针,这就足够了。为什么你想知道东西在哪里?
  • @AlexeyFrunze 这甚至都不是那个的复制品,而且您之前的评论完全无法理解或解决 OP 的误解。
  • @AlexeyFrunze 当你进行编程时,你最终会遇到一种叫做调试的东西。它是一种故障排除形式,使用称为调试器的特定程序,指定以受控形式运行您的程序。调试时,您将需要寻找特定的常见错误,例如动态内存泄漏、堆栈溢出、由不正确的指针地址导致的代码失控、数组越界访问……等等。如果您不知道变量在内存中的分配位置,则无法使用调试器找到这些错误。当您尝试一个时,您会注意到这一点。
  • 我的错,对不起。我自己也使用调试器,没问题。

标签: c struct dynamic-memory-allocation


【解决方案1】:

char* 成员 s 的空间在调用 malloc() 后与 mix 的其余成员一起分配在堆上(您不需要转换其返回值) .分配给s 的字符串文字不是在堆或堆栈上分配的,而是实际二进制文件的一部分并且具有静态存储持续时间。所以这个:

ptr->s = "Hi, there, I'm just a really long string.";

将字符串文字的地址分配给ptr->s。如果您希望ptr->s 指向字符串文字以外的其他内容,那么您需要为它使用malloc() 内存。对于每个malloc(),都必须有一个free(),因此ptr->s 必须在ptr 之前是free()d(如果ptr->s 仅指向动态分配内存)。

在调用free() 之后,取消引用ptr 是未定义的行为。

【讨论】:

  • 只是为了检查我是否正确,说ptr->s是用户从命令行输入的,为了不遇到输入大小的任何问题,我还需要分配记住它,对吗?
  • @Nobilis,正确的。您还需要确保在读取用户输入时不会超出分配给ptr->s 的缓冲区。
  • 我明白了,非常感谢:)
【解决方案2】:

当你用malloc()动态分配mix时,你实际上是在分配一块内存来存储mix结构数据成员,即

  • int (a)
  • float (b)
  • 指针指向char (s)

当你调用free()时,你只需释放那个块。

所以,你不分配字符串,你只分配字符串指针

如果您想动态分配字符串,您必须显式执行(通过另一个调用malloc()),并且为避免内存泄漏,您还应该使用free() 显式释放字符串。

【讨论】:

    【解决方案3】:

    当您为ptr 分配内存时,会为结构的所有成员分配内存,包括指针s,这与为结构的任何其他成员分配的内存没有什么不同。

    您将字符串文字分配给s,所以它通常存储在只读部分中很好。否则,您还需要为ptr->sfree 提供malloc。由于它是字符串文字,因此无需在此处释放 s(这样做是 UB)。

    【讨论】:

      【解决方案4】:

      mix* ptr 在堆栈上分配。 ptr 指向的内容,mix 类型的变量,在堆上动态分配,包括指针s

      请注意s 没有指向任何东西,指针没有做任何有用的事情。您必须将其设置为指向可以分配到任何地方的东西。当你的结构被释放时,它指向的任何东西都不会被释放。在这种情况下,您将其设置为指向在 ROM 中分配的常量字符串文字,因此您无需担心。

      【讨论】:

        【解决方案5】:

        *s 是否在栈上分配

        *s(即解引用指针s 的结果)根本没有分配。在malloc 之后,ptr->s 是一个未初始化的指针。它不指向任何东西,并且表达式 *(ptr->s) 具有未定义的行为,直到您执行 ptr->s = "Hi, etc"

        一旦您将ptr->s 初始化为指向字符串文字,*(ptr->s) 就是字符串文字的第一个字符,因此它可能存在于可执行文件的某些数据部分中。除了结构的 sizeof(mix) 字节(在 32 位实现上可能是 12 个字节)之外,没有任何东西是动态分配的。

        【讨论】:

          【解决方案6】:
          what happens with the actual char pointer? Where is it stored? 
          

          char* 也像其他成员一样,占用一些字节(在 64 位机器中占用 8 个字节,类似于其他指针)。在您的情况下,您正在为堆中的该结构实例分配内存。所以这个指针的内存也将分配在为该结构实例分配的同一个堆块中。

          考虑一下这段代码。这给出了 char* 的位置:

          #include <stdio.h>    
          typedef struct
          {
              int a;
              float b;
              char *s;
          }mix;    
          int main()
          {
          
          printf("\n%d ,float:%d, int:%d, char*:%d", sizeof(mix), sizeof(float), sizeof(int), sizeof(char*));
          
          return 0;
          }
          

          所以这个结构的大小是 16 字节。由 4 字节整数、4 字节浮点数和 8 字节字符*组成。 (在 64 位操作系统中,如果操作系统是 32 位,则 char* 将为 4 个字节。)

          And once the struct is freed, is the char pointer freed along with it?
          

          通常 char* 指向的块不会被释放(如果它指向 malloc() 分配的块)。只有结构块将被释放。我们知道 free() 需要在分配期间返回的有效地址以进行和平解除分配。如果您在没有释放该 char* 的情况下释放,则会导致内存泄漏。

          但是你的情况"Hi, there, I'm just a really long string.";

          上面给出的字符串是字符串字面量,分配在程序的只读部分。

          使用gcc -S Yourprogram.c

          这将生成 .s 文件。您可以查看此字符串的 .read_only 部分。所以即使你删除了你的结构实例,也不会有内存泄漏。因为您只是指向一个只读地址。你根本没有为这个字符串分配内存。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-17
            • 2022-01-18
            • 1970-01-01
            • 1970-01-01
            • 2013-12-25
            相关资源
            最近更新 更多