C语言指针04

本文详细介绍了C语言中的动态内存管理,包括malloc、calloc、realloc和free函数的使用,以及如何避免内存泄漏。同时,探讨了指针与数组的关系,特别是二级指针的概念及其在二维数组中的应用。
摘要由CSDN通过智能技术生成

二级指针

格式: **p

定义: 这是一个指针的指针,保存指针变量的地址,也称为二级指针;搭配指针数组使用。

动态内存分配

定义: 数组定义时,数组长度是预先定义好的,整个程序中固定不变。但实际编程中,往往需要根据实际情况申请空间。C语言提供了一些内存管理函数,可以通过需要动态分配内存空间,也可以把不再使用的空间回收。

静态分配

1.在编译或运行时,按事先规定的大小分配空间,比如int a[10],系统自动分配

2.必须事先指定所需空间大小

3.分配在栈区或全局变量区,一般以数组形式

4.按计划分配

动态分配:

1.在程序运行中,根据需要大小自由分配,需要程序员自己分配

2.分配在堆区,一般使用特定函数进行分配

3.按需分配

使用的函数:

1.malloc函数: 开辟出一片连续的内存空间,需要手动初始化

格式:指针变量 = malloc(元素类型字节大小*元素个数)

例子:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	int *p;
	p = (int *)malloc(sizeof(int)*10);  //用malloc申请一个存10个int型元素的数组
	if(p == NULL)
	{
		printf("error\n");
	} 
	memset(p, 0, 40); //memset函数对申请的空间初始化
	
	int i;
	for(i = 0; i < 10; i++)
	{
		p[i] = i;
		printf("%d\n",p[i]);
	} 
	
	free(p);       //如果没有释放申请的空间,会造成内存泄漏,内存泄漏就是只申请不释放 
	p = NULL;      //将p指向空,防止p成为野指针 
	return 0;
}

注:1.开辟一块内存空间,开辟的大小以字节为单位。位置在堆上

​ 2.使用sizeof()求出类型的大小*元素个数

​ 3.返回值是已开辟好空间的首地址,所以必须用同类型指针变量接受

​ 4.malloc开辟的内存是连续的

​ 5.多次调用malloc,开辟的空间不一定连续

2.free函数

​ 格式:free(指针变量)

3.calloc函数: 开辟一片连续的内存空间,自动初始化为0

​ 格式:指针变量 = calloc(元素个数,元素类型所占的字节数)

​ 例子:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	int *p;
	p = (int *)calloc(20,sizeof(int));//calloc()函数等价于malloc()和memset()
	if(p == NULL)
	{
		printf("error\n");	
	} 
	int i;
	for(i = 0; i < 20; i++)
	{
		printf("%d\n",p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

注:1.开辟一块内存空间,开辟的大小以字节为单位。位置在堆上

​ 2.第一个参数是元素的个数,第二个参数是元素所占字节数

​ 3.返回值是已开辟好空间的首地址,所以必须用同类型指针变量接受

​ 4.calloc开辟的内存是连续的

​ 5.多次调用malloc,开辟的空间不一定连续

4.realloc函数: 重新分配内存空间大小,主要是进行扩展内存空间

​ 格式:指针变量 = realloc(已分配内存指针变量,重新分配空间大小的字节数)

​ 例子:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	int *p;
	p = (int *)malloc(sizeof(int)*10);  //用malloc申请一个存10个int型元素的数组
	if(p == NULL)
	{
		printf("error\n");
	} 
	memset(p, 0, 40); //memset函数对申请的空间初始化
	
	int i;
	for(i = 0; i < 10; i++)
	{
		p[i] = i;
	} 
	
	p = realloc(p, 100);  //realloc用来对空间进行扩容,原来的数据保留,新增加的空间里面的值是随机的 
	if(p == NULL)
	{
		printf("error\n");
	}
	
	for(i = 0; i < 25; i++)
	{
		printf("%d\n",p[i]);
	}
	
	printf("**********\n");
	memset(p+10, 0, sizeof(int)*15);  //将扩容后的部分赋值为0 
	
	for(i = 0; i < 25; i++)
	{
		printf("%d\n",p[i]);
	}
	
	free(p);       //如果没有释放申请的空间,会造成内存泄漏,内存泄漏就是只申请不释放 
	p = NULL;      //将p指向空,防止p成为野指针 
	return 0;
}

注:1.存在bug,如果开辟失败,会导致指向位置丢失

​ 2.如果p指向的空间之后有足够的内存空间可以追加,则直接追加,返回p

​ 3.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区域,开辟一块

​ 满足需求的空间,并且把原来空间内存中的数据拷贝回来,释放旧的内存空间,并返回新开辟的内存空间

​ 的地址

​ 4.如果开辟失败,得用一个新的变量来接受realloc函数的返回值

内存泄漏

定义:

​ 1.只申请不释放

​ 2.申请的内存首地址丢了,找不到了,指向了其他的地址,再也没有办法使用,也没有办法释放。

指针与数组关系

a+1 => a是一维数组名的话,意味着向后移动一个元素

a+1 => a是二维数组名的话,意味着向后移动一行元素(每次移动一个一维数组)

&a+1 => a是二维数组名的话,意味着向后移动整个数组(每次移动一个二维数组)

a[i] => a是二维数组名的话,代表着二维数组中每个一维数组的首地址

&a[i] => a是二维数组名的话,代表着二维数组名a

a、a[0]、a[0] [0] => 在二维数组中,三者的地址相同。a可以看做是一个存储了一维数组首地址的指针

注:如果a是一维数组名,a为一级指针。如果a是二维数组名,a是二级指针。如果a是二维数组名,&a是三级指针。一级指针加一移动一个元素,二级指针加一移动一个一维数组,三级指针加一移动一个二维数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值