使用 malloc() 后变量的大小是多少?

What is the size of variable after using malloc()?

我想了解动态内存分配的概念。我想知道分配内存后大小有什么变化。

我的代码如下。

#include <stdio.h>
#include <stdlib.h>

int main(){
    char *s;
    printf("Size before malloc: %d\n", sizeof(s));

    s = (char*)malloc(1024 * sizeof(char));
    printf("Size after malloc: %d\n", sizeof(s));
    
    printf("Size actual: %d\n", sizeof(s) * 1024);

    s[0] = 'a';
    s[1] = 'b';
    s[2] = 'c';
    s[3] = 'd';
    printf("Size by calculation: %d", sizeof(s) / sizeof(char));

    return 0;
}

当我执行这段代码时,我得到如下输出。

Size before malloc: 8
Size after malloc: 8
Size actual: 8192
Size by calculation: 8

那么为什么不分配内存后 returns 8192 作为大小。此外,当我将字符添加到 s 时,为什么不作为 4

所有变量的大小在其整个生命周期内都是恒定的。没有函数调用会改变变量的大小。

So why not returns 8192 as size after allocating memory.

因为该变量是char *s类型的对象,而您的系统上该类型的大小不是8192。

sizeof pointer给出指针本身的大小,而不是引用对象的大小。所以在现代 PC 机器上它将是 4(32 位 system/build)或 8(64 位 system/build)字节。

C 中没有可移植的方法来获取动态分配的内存块的大小。

一些评论。

sizeof 给出 size_t 类型。

printf("Size by calculation: %d", sizeof(s) / sizeof(char));

调用未定义的行为。您需要使用正确的格式:

 printf("Size by calculation: %zu", sizeof(s) / sizeof(char));

我总觉得图片在这种情况下很有帮助。

声明

char *s;

创建类型为 char *:

的单个对象
char *
+---+
|   | s
+---+

具有不确定值(不一定是 0 或任何特定值,每次程序 运行 时可能不同)。

声明

s = (char*)malloc(1024 * sizeof(char));

为 1024 char 个对象 在内存中的其他地方 分配 space,并将那个 space 中的第一个对象的地址分配给s:

char *        char
+---+         +---+
|   | s ----> |   | s[0]
+---+         +---+
              |   | s[1]
              +---+
              |   | s[2]
              +---+
               ...

s 变量的大小永远不会改变,只会改变它的值。在这种情况下,它的值是 address of s[0].

So why not returns 8192 as size after allocating memory. Further when I added chars into s why not getting as 4 ?

sizeof(s) 给出指针变量本身的大小,而不是它指向的对象的大小。您想将该调用写为

printf("Size actual: %d\n", sizeof *s * 1024);

s 类型 char *,在任何现实世界的系统上都将大于 1(4 或 8,视情况而定) . expression *s的类型是char,这里就是你要用的

Further when I added chars into s why not getting as 4 ?

您还没有 添加 任何东西到 s (或者更准确地说,它指向的缓冲区) - 您只为那些已经在那了。您为 1024 个 char 个对象分配了 space,并且该大小不会仅通过分配元素而改变。至关重要的是,像

s[1026] = some_value;

不会自动扩展分配的内存 - 您只是在该内存范围之外写入。您必须使用 realloc 库调用来增加分配块的大小。

此外,

printf("Size by calculation: %d", sizeof(s) / sizeof(char));

不符合您的预期 - 同样,sizeof(s) 为您提供指针变量本身的大小,而不是它所指向的对象的大小。 sizeof(*s) 也不起作用,因为它给你的是单个 char 对象的大小,而不是整个分配的 space。 必须跟踪你在一个单独的变量中分配了多少 space:

size_t num_elements = 1024;
char *s = malloc( sizeof *s * num_elements );

就像我上面说的,如果你以后需要扩展那个space,你需要使用realloc函数:

/**
 * Double the size of the allocated block.
 */
char *tmp = realloc( s, sizeof *s * (num_elements * 2) ); 
if ( tmp )
{
  s = tmp;
  num_elements *= 2;
}

如果realloc无法成功扩展缓冲区,它将return NULL并保留原来的缓冲区。因此,我们希望将结果分配给一个临时变量——我们不想冒 s 被设置为 NULL 的风险,从而失去我们对该内存的唯一引用。同样,在我们知道 realloc 调用成功之前,我们不想更新大小。

一些样式注释-

从 C89 开始,对 malloc(以及 callocrealloc)的转换是不必要的,通常被认为是不好的做法。比较普遍的做法是

T *p = malloc( sizeof *p * N ); // for any type T

由于表达式 *p 的类型为 T,因此 sizeof *p 等价于 sizeof (T)。这样您就不会在单个 malloc 调用中多次重复类型信息,从而减轻了维护负担(如果 T 发生变化,需要更新的内容更少)。这在 C++ 中是 not true 并且在 malloccallocrealloc 上仍然需要强制转换,但是如果你正在编写 C++,你一开始就不应该使用 C 风格的内存管理。

此外,请记住 sizeof 是一个 运算符 ,而不是函数 - 只有当操作数是类型名称或者是包含算术或的表达式时才需要括号其他优先级较低的运算符。例如,

sizeof x+y

被解析为

(sizeof x) + y

如果你想要表达式x+y的大小,那么你需要写

sizeof (x+y)