【问题标题】:What is the size of variable after using malloc()?使用 malloc() 后变量的大小是多少?
【发布时间】:2021-11-16 21:47:58
【问题描述】:

我试图理解动态内存分配的概念。我想知道分配内存后大小的变化是什么。

我的代码如下。

#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

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

【问题讨论】:

  • 欢迎来到 SO。 s 是一个指针。给指针赋值不会改变它的类型或大小。它始终是一个指针,并且具有指针的大小。无法获取s 指向的分配内存的大小。大小由您决定。
  • 我明白了,谢谢。有没有办法跟踪大小?例如,我可以在后面的代码中获得其余的尺寸吗?
  • %d printf 格式说明符错误。 sizeof 运算符的结果是数据类型 size_t,而不是 intsize_t 的正确格式说明符是 %zu。格式说明符%d 可能适用于大多数 32 位平台,但我不确定它是否适用于 64 位平台。为了在所有平台上都安全,您应该始终使用正确的格式说明符。
  • 短语实际大小最好表述为分配的内存
  • "有没有办法跟踪大小?"使用变量! size_t size = 1024; char *s = malloc(size); /* ... 42 lines later ... */ printf("allocated %zu bytes for s.\n", size);

标签: c malloc


【解决方案1】:

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

那么为什么不在分配内存后返回 8192 作为大小。

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

【讨论】:

  • 我明白了,所以实际上在我的系统中分配了 8192 个字节,但我正在打印不会通过代码更改的字符的大小。谢谢。
  • @Tolga 如果malloc 返回非NULL 结果,则至少分配8192 个字节。运行时可能会分配更多(但你不能依赖它)
  • @Mgetz 我明白了,谢谢。
  • 因为变量schar *类型的对象
  • @ryyker 我想你的意思是malloc(1024 * sizeof(s));,而不是malloc(1024 * sizeof(*s));
【解决方案2】:

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

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

一些评论。

sizeof 给出size_t 类型。

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

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

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

【讨论】:

  • @ryyker 如何与我的回答相矛盾。您的程序是 32 位的,它提供 4 个字节。
【解决方案3】:

我总是发现图片在这种情况下很有帮助。

声明

char *s;

创建char * 类型的单个对象:

char *
+---+
|   | s
+---+

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

声明

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

为内存中的 1024 个char 对象其他地方分配空间,并将该空间中第一个对象的地址分配给s

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

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

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

sizeof(s) 为您提供指针变量本身的大小,而不是它指向的对象的大小。你想把调用写成

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

s类型char *,在任何现实世界的系统上都将大于 1(4 或 8,具体取决于)。 表达式*s的类型是char,这就是你要在这里使用的。

当我将字符添加到 s 时,为什么不变成 4 ?

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

s[1026] = some_value;

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

另外,

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

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

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

就像我上面说的,如果你以后需要扩展那个空间,你需要使用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 无法成功扩展缓冲区,它将返回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++ 中是正确的,malloccallocrealloc 仍需要强制转换,但如果您正在编写 C++,则不应该使用 C 风格的内存首先是管理。

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

sizeof x+y

被解析为

(sizeof x) + y

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

sizeof (x+y)

【讨论】:

  • 那是非常全面的答案。非常感谢,它涵盖了我的大部分观点。
猜你喜欢
  • 2020-01-29
  • 2012-07-18
  • 2010-09-27
  • 2010-11-07
  • 2015-09-21
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 2023-03-31
相关资源
最近更新 更多