使用 malloc() 函数和指针理解代码

Understanding code with use of the malloc() function and pointers

我正在尝试记录一些代码以提高我对指针的了解和一般的 ANSI C 能力。

 ...
 int static_store = 30;
 const char * pcg = "String Literal";
 int main()
 {
     int auto_store = 40;
     char auto_string[] = "Auto char Array";
     int * pi;
     char * pcl;
     pi = (int *) malloc(sizeof(int));
     *pi = 35;
     pcl = (char *) malloc(strlen("Dynamic String") + 1);
     strcpy(pcl, "Dynamic String");
 ...

乍一看,初始化了两个指针,pi和pcl,分别是int和char类型。

但是后面的几行让我很困惑,我不明白发生了什么。我可以看到正在调用 malloc 来分配 int (40) 大小的内存。是给变量pi和pcl分配内存吗?

2 个指针被 delcaredpipcl)。在声明时,它们 初始化。
pi 然后指向一个堆分配的内存块,该内存块可以容纳 1 个 int(其大小取决于平台,但通常为 4 个字节)分配有函数 maloc。在某处必须使用函数 free 显式释放此内存 - 不这样做将导致内存泄漏。
然后将 int 值 35 存储在该内存位置。 *pi 可以读作 "what the pointer pi points to" 它实际上与 pi[0].
相同 pcl 然后使用函数 malloc 指向一个堆分配的内存块,该内存块大到足以容纳 14 个字符加上一个 '\0' 字符(即 15 个字节)(如上所示,在某些时候这个必须释放内存)。
然后使用函数 strcpy.

将 15 个字符 "Dynamic String[=31=]" 放入该内存中

Is it assigning memory to the variables pi and pcl?

是的malloc分配内存给这些指针。

pi 分配的内存等于 sizeof(int)(可能会有所不同),pcl 分配的内存等于 length of string plus 1([=15= 加 1) ]).

From first looks, two pointers are initialised, pi and pcl, of type int and char respectively

它们已声明未初始化。

注- Please don't cast return of malloc

行: pi = (int *) malloc(sizeof(int)) 实际上为一个 int 变量分配内存。之后的行将值 35 放入该变量。

行: pcl = (char *) malloc(strlen("Dynamic String") + 1) 创建一个动态分配的 char 数组(相当于一个字符串)。该数组的大小是字符串的长度 ("Dynamic String") 加一。下一行将字符串:"Dynamic String" 复制到分配的数组中。加一是必需的,因为 c 中的每个字符串都以字符 '[=13=]' 结尾,这是字符串结尾的标志。

malloc函数在heap(动态内存池)中保留一块内存,returns指向第一个元素的指针那块内存。该内存将保留,直到您调用 free,或程序退出。

通话中

pi = (int *) malloc(sizeof(int));

malloc 保留一块足够大的内存来存储单个 int 值,并且指向该内存块的指针被分配给 pi。您不需要转换 malloc1 的结果,这实际上被认为是不好的做法 2。更好的写法是

pi = malloc( sizeof *pi );

表达式 *pi 的类型为 int,因此 sizeof *pi 等价于 sizeof (int)3。使用 sizeof *pi 而不是 sizeof (int) 的优点(以及放弃强制转换)是,如果您更改 pi 的类型(从 int *long * ,例如),您不必在 malloc 调用中更改任何内容;无论 pi 的类型如何,它总是会分配正确数量的内存。少了一个令人头疼的维护问题。

同样,调用

pcl = (char *) malloc(strlen("Dynamic String") + 1);

保留足够的内存来保存 "Dynamic String" 的内容(+1 是字符串终止符所必需的)并将指向该内存的指针分配给 pcl。同样,最好写成

pcl = malloc( strlen("Dynamic String") + 1 ); // no cast

sizeof (char) 根据定义为 1,因此您不需要在上面的调用中显式 sizeof *pcl;但是,如果您决定将 pcl 的类型从 char * 更改为 wchar_t *,最好保留它,尽管您仍然需要更改字符串文字并更改计算长度的方式,因此它不是免维护的。

malloc调用的一般形式是

T *p = malloc( num_elements * sizeof *p ); // where num_elements > 1

T *p;
...
p = malloc( num_elements * sizeof *p );

有一个名为 calloc 的类似函数,它会将分配的内存块清零:

T *p = calloc( num_elements, sizeof *p );

T *p;
...
p = calloc( num_elements, sizeof *p );


1。无论如何,在 C 中; C++ 需要强制转换,因为 C++ 不允许 void * 和其他指针类型之间的隐式转换。但是无论如何,您不应该在 C++ 代码中使用 malloc

那么,为什么人们仍然将 malloc 的结果转换为 C 语言呢?这在很大程度上是 ANSI 之前的日子(超过四分之一个世纪前)的遗留物,当时 malloc 返回 char *,如果不强制转换就不能分配给不同的指针类型。 1989 标准引入了 void * 类型,它本质上是一个 "generic" 指针,无需显式转换即可分配给其他指针类型。

2. 在 C89 标准下,如果编译器看到一个函数调用而没有看到该函数的声明,它将假定函数 returns int。因此,如果您忘记包含 stdlib.h 或在范围内没有 malloc 的声明,编译器将假定它是 returns 一个 int 值并生成机器相应的调用代码。但是,int 和指针类型 不兼容 ,如果您尝试将一个分配给另一个,编译器通常会发出诊断。但是,通过使用强制转换,您可以抑制该诊断,并且稍后您可能 运行 陷入 运行 时间问题。

1999 年的标准取消了函数的隐式 int 类型,因此这不再是真正的问题,但转换仍然是不必要的,并且会导致维护问题。

3、sizeof是一个运算符,不是函数;仅当操作数是类型名称如 intdoublestruct blah.
时才需要括号