malloc 的微浅理解

这段时间在学习数据结构。对数据结构中的 malloc 总是感到困惑,这几天查了资料,算是查清楚了 malloc 的用法,特此记录
在数据结构中,对结构体最开始分配空间的步骤是(以线性表为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct{
ElemType data[MaxSize];//`ElemType` 就是用来代替实际数据类型(如int)的一个占位符。
int length;
} SqList;

void CreateList(SqList *&L, ElemType a[], int n){
L = (SqList *)malloc(sizeof(SqList));
while(i<n){
L -> data[k]=a[i];
k++,i++;
}
L ->length = k;
}

在这段算法中,比较难理解的是这两行代码

1
2
3
SqList *&L;
//和
L = (SqList *)malloc(sizeof(SqList));

前者代表的是对指针的引用,允许函数内部修改函数外部传入的指针本身,而不仅仅是修改指针所指向的值。后者是对指针所指向的地址进行动态内存分配。

对于 SqList *&L
* 用于指针前面时,它表示解引用操作,即获取指针所指向的值。例如,int x = *ptr; 表示将指针 ptr 指向的整数值赋给变量 x
& 运算符:& 运算符用于取地址操作。当 & 用于变量前面时,它返回该变量的地址。例如,int x = 10; int *ptr = &x; 将变量 x 的地址赋给指针 ptr
*&:这个组合可以看作是将一个指针的引用。* 表示指针,而 & 表示引用。所以 *& 表示指针的引用。这在 C/C++ 中是合法的语法,允许在函数参数中传递指针的引用,以便在函数内部修改指针指向的地址。
因此,SqList *&L 声明了一个指针 L 的引用,它指向一个 SqList 类型的对象

我们在来讲讲 malloc。malloc 全称 memory allocation,在 cppference 中有写到 malloc 的功能。

Allocates size bytes of uninitialized storage.
分配 size 字节的未初始化存储。
If allocation succeeds, returns a pointer that is suitably aligned for any object type with fundamental alignment.
如果分配成功,则返回一个指针,该指针适合任何具有基本对齐方式的对象类型。
If size is zero, the behavior of malloc is implementation-defined. For example, a null pointer may be returned. Alternatively, a non-null pointer may be returned; but such a pointer should not be dereferenced, and should be passed to free to avoid memory leaks.
如果 size 为零,则 malloc 的行为是实现定义的。例如,可以返回空指针。或者,可以返回非空指针;但这样的指针不应该被取消引用,并且应该传递给 free 以避免内存泄漏。

以下是 malloc() 函数的声明。

1
void *malloc(size_t size)

其中,size_t 是一个无符号整数类型,通常用于表示内存块的大小
在不同的平台上,size_t 的大小可能会有所不同,但它通常被设计为足以容纳系统中最大可能的对象大小。

size_t can store the maximum size of a theoretically possible object of any type (including array).

void* 是一个指针类型,表示指向未知类型的指针。这种类型的指针可以指向任何类型的数据,但不能直接对其进行解引用操作。

所以我们需要将其转化,因此可以有

1
int* intPtr = (int*)malloc(sizeof(int));

或者说,可以使用隐式转化

1
int* intPtr = malloc(sizeof(int));

此刻,一个内存空间就创立好了,那么,发生了什么事情?

当执行 int* intPtr = malloc(sizeof(int)); 这行代码时,发生了以下几件事情:

  1. malloc 分配内存malloc(sizeof(int)) 这部分是一个函数调用,它调用了 malloc 函数来分配一块内存空间,大小为 sizeof(int) 字节,也就是一个整数大小的内存块。sizeof() 是一个运算符,用于计算指定类型的大小。

  2. 返回指针malloc 函数返回一个指向新分配的内存块起始地址的指针。这个指针的类型是 void*,即指向未知类型的指针,需要转化。

  3. 类型转换:在赋值语句 int* intPtr = ... 中,void* 类型的指针被隐式地转换为 int* 类型的指针。这是因为 int* 类型的指针可以指向整数类型的数据,而 malloc 返回的指针指向的是刚分配的内存块,大小为一个整数的大小。

  4. 赋值给指针变量:分配的内存块的起始地址被赋值给了 intPtr 指针变量,使得 intPtr 指向了这块新分配的内存空间。

因此,int* intPtr = malloc(sizeof(int)); 这行代码的作用是分配一块大小为一个整数大小的内存空间,并将其起始地址存储在 intPtr 指针变量中,以便后续使用。
当然,这个数字还可以通过 n 来拓展
cppference.com 也写出了关于它的用法和格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>   
#include <stdlib.h>
 
int main(void)
{
int *p1 = malloc(4*sizeof(int));
// allocates enough for an array of 4 int(为 4 个 int 的数组分配足够的空间)

int *p2 = malloc(sizeof(int[4]));//same, naming the type directly(一样,直接命名类型)

int *p3 = malloc(4*sizeof *p3);//same, without repeating the type name(相同,不重复类型名称)
 
if(p1) {
for(int n=0; n<4; ++n) // populate the array
p1[n] = n*n;
for(int n=0; n<4; ++n) // print it back out
printf("p1[%d] == %d\n", n, p1[n]);
}
 
free(p3);
free(p3);
free(p3);
}

如有错误,还请指出,愿我们共同成长。

参考资料: