C语言中的指针-建立动态内存分配和 void 指针-学习笔记-42

什么是内存的动态分配

还记得我们之前讲过的全局变量和局部变量吗?全局变量是分配在内存中的静态存储区的,非静态的局部变量(包括形参)都是分配在内存的动态存储区的。我们称上面的存储区为 栈 (stack)
除此之外,C 语言还允许建立内存动态分配区域,存放一些临时用的数据,这些数据:

  1. 不必在程序的声明部分定义;
  2. 不必等到函数结束时才释放;
  3. 需要时开辟,不需要时随时释放;

这些数据是临时存放在一个特别的自由存储区,称之为堆 ( haap)

我们可以根据需要,随时向系统申请所需大小的空间,但是我们没有声明他们是变量还是数组,也没有名字,所以我们只能通过指针来引用这些数据

建立内存的动态分配

清楚了什么是动态分配之后呢,我们来看看如何建立这么一个叫做的区域。
我们对内存的动态分配,主要是通过系统功能提供的库函数来实现的,主要有malloc , calloc , free , realloc 这4个。

malloc 函数

函数原型:

void * malloc( unsigned int size);

malloc 的作用是在内存的动态存储区域分配一个长度为 size 的连续空间
形参 size 表示为无符号整型(unsigned),即不能为负数
此函数的返回值是所分配区域的第一个字节的地址
因为此函数是一个指针型函数,返回的是一组地址,地址是该分配区域的开头位置。

1
malloc (100); //分配一个100字节长度的连续空间,函数值为该空间第1个字节的地址

这个指针的基类型是 void,即这个指针不指向任何类型的数据,只提供一个地址。如果执行失败(内存空间不足)则返回空指针。

注意
这里的函数是一个基类型为 void 的指针函数,void 的意思是这个指针函数的指针不指向任何数值,只返回一个地址。
这里的 void 不是函数返回值的类型,是只该指针函数的指针指向的数据的类型。切记!

calloc 函数

函数原型:

void * calloc(unsigned n , unsigned size);

calloc 的作用是在内存的动态存储区域中分配 n 个长度为 size 的连续空间,这个空间一般比较大,足以保存一个数组。

用 calloc 函数可以为一维数组开辟动态存储空间,n 为数组元素个数,每个元素长度为size。这就是动态数组。

这个指针的基类型是 void,即这个指针不指向任何类型的数据,只提供一个地址。如果执行失败(内存空间不足)则返回空指针。

1
p=calloc(50,4); //开辟一个50X4个字节的临时分配域,把起始地址赋给指针变量 p。

free 函数

其函数原型为:

void free (void *p);

free 的作用是释放指针变量 p 所指向的动态空间,使这部分空间能重新被其它变量使用。

1
free(p); //p 应该是最近一次调用calloc 或 malloc 函数时得到的函数返回值

free 无返回值。

realloc 函数

函数原型:

void realloc (void p, unsigned int size);

realloc 函数的作用是,如果通过 malloc 或者 calloc 函数获得了动态空间,想改变其大小,可以用 realloc 重新分配

1
realloc(p,50);  //重新将指针 p 所指向的已分配的动态空间改为50字节

注意
以上的 4 个库函数在 stdlib.h 头文件中,需要使用时,需要使用 #include <stdlib.h> 引入到程序中。

Void 指针类型

上面我们操作内存动态分配的函数,都是基类型为 void 的指针。即我们可以定义一个基类型为 void 的指针变量,它不指向任何类型的数据

请注意,不要把 void 理解为可以指向任何类型的数据,void 表示的是不指向任何类型的数据

举一些例子

1
2
3
4
5
6
7
8
9
int a=3;  // 定义了一个整型变量a,并赋值为3
int *p1=&a; //将变量 a 的地址赋值给指针变量 p1
char *p2; //定义了一个指向字符型数据的指针 p2
void *p3; // 定义了一个不指向任何数据的指针 p3
p3= (void *)p1; //将 p1 的值转换为 void * 并传递给 p3
//也就是说,只要 p1 里面存储的地址,并不指向 a,知识记住了地址
p2=(char *)p3; //这里把 p3的值转换为 char * 并传递给 p2
//p2 是 char 型,所以要先把 p3 的地址,转换为 char*型
printf("%d",*p3); //这是错误的,虽然 p3 存储着 a 的地址,但并不指向a,所以无法输出。

如果吧:

1
void *p3=&a;  //这里p3会获得 a 的纯地址,但并不指向a

综合例子

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 check(int *p);
int *p; //定义了一个整型指针变量 p
p=(int *)malloc(3*sizeof(int)); //定义了3个整型字节的动态存储空间,并且转换成了int * 型
printf("请输入三个成绩:\n");
for(int i=0;i<3;i++){
scanf("%d",p+i);
}
check(p);
return 0;
}

void check(int *p){
int i;
printf("这些成绩不及格:\n");
for(i=0;i<3;i++){
if(p[i]<60){
printf("%d\t",p[i]);
}
}
}

声明空间并转换称为指定类型空间。

1
p=(int *)malloc(3*sizeof(int));

因为我们声明的这些空间是要存放 int 型数据的
所以,我们使用 sizeof(int) 先获取了一下系统中整数的字节数,因为是 3 个学生的成绩,所以乘以了3。
我们知道 malloc 获取的空间是没有指向任何类型的,所以我们要把这段空间转换为 int 型,就在前面加一个 (int ) 表示转换指针类型为 int 型。

可以这么理解,要把指针转换成什么类型,就:
(类型名 *) 指针名

尾巴

这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。


-------------The End-------------
欢迎请我喝咖啡哦~!