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



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

我的代码如下。

#include <stdio.h>
#include <stdlib.h>
int main(){
char *s;
printf("Size before malloc: %dn", sizeof(s));
s = (char*)malloc(1024 * sizeof(char));
printf("Size after malloc: %dn", sizeof(s));

printf("Size actual: %dn", 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呢?

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

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

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

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));

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

宣言

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: %dn", sizeof *s * 1024);

s类型char *,它在任何现实世界的系统(取决于4或8)上都将大于1。表达式*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++中不是为真,并且在malloc,callocrealloc上仍然需要强制转换,但是如果你正在编写c++,你首先不应该使用C风格的内存管理。

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

解析为

(sizeof x) + y

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

sizeof (x+y)

最新更新