动态内存的释放、内存泄漏、函数指针

1、

malloc:分配内存块

calloc:分配内存块,并且全部初始化为0

realloc:调用之前申请的内存块的大小,缩小内存块的时候,开头地址不变,其他不要的数据也不变,只是右边界线

       正常使用两个参数,第一个参数:之前开辟的内存块的开始地址,  第二个参数:新开辟的内存块的大小

注意:第一个参数,必须是开辟前的内存块的开始地址,不不能移动;

          如果将第一个参数传0,相当于一个malloc函数;

          如果将第二个参数传0,相当于一个free函数;

2、动态开辟空间:

(1)int *p6 = (int*)realloc(0, 10 * sizeof(int) * 4)=/int *p6 = (int*)malloc(10 * sizeof(int) * 4);相当于malloc,重新找了一块空间,并没有释放之前的空间。

(2)p = (int*)realloc(p, 10 * sizeof(int) * 4);//有可能在其后边续,也有可能重新开辟一块空间。

(3)一般用malloc加for循环代替calloc。

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>
int main()
int main()
{
	//动态开辟 10个空间 int
	int* p1 = (int*)malloc(10 * sizeof(int));
	assert(p1 != NULL);//断言
	if (p1 == NULL)
	{
		return 0;
	}
	//动态开辟 20个空间 short
	short* p2 = (short*)malloc(20 * sizeof(short));
	assert(p2 != NULL);//断言
	if (p2 == NULL)
	{
		return 0;
	}
	//动态开辟 100个空间 double
	double* p3 = (double*)malloc(100 * sizeof(double));
	assert(p3 != NULL);//断言
	if (p3 == NULL)
	{
		return 0;
	}
	//动态开辟 30个空间 int 初始化为0
	int* p4 = (int*)calloc(30, sizeof(int));
	assert(p4 != NULL);//断言
	if (p4 == NULL)
	{
		return 0;
	}
	//动态开辟 50个空间 char 初始化为'A'
	char* p5 = (char*)calloc(50, sizeof(char));
	assert(p5 != NULL);//断言
	if (p5 == NULL)
	{
		return 0;
	}
	for (int i = 0; i < 50; i++)
	{
		p5[i] = 'A';
	}
	//对p进行扩容,扩容为40个空间
	p1 = (int*)realloc(p1, 10 * sizeof(int) * 4);//有可能在其后边续,也有可能重新开辟一块空间
    //int *p1 = (int*)realloc(0, 10 * sizeof(int) * 4)=/int *p1 = (int*)malloc(10 * sizeof(int) * 4);//相当于malloc,重新找了一块空间,并没有释放之前的空间
	assert(p1 != NULL);//断言
	if (p1 == NULL)
	{
		return 0;
	}
    //对p1进行缩小,缩小为5个
	p1 = (int*)realloc(p1, 5 * sizeof(int));
	assert(p1 != NULL);//断言
	if (p1 == NULL)
	{
		return 0;
	}
	return 0;

}

3、free函数

(1)C语言中有两个危险的东西:

       (a)数组越界

       (b)内存泄漏

         内存泄漏或内存碎片怎么处理:可以进行重启

(2) void free(void *p),释放指针变量p所指向的动态内存;

(3)free函数的必要性:如果动态内存开辟,使用结束后没有释放,会导致申请的这块内存没有人可以使用,一般将这块没有人能使用的内存叫做垃圾,留着垃圾的函数会导致内存泄漏。

(4)使用malloc时,一个malloc搭配一个free

int main()
{
	/*
	int* p = (int*)malloc(10 * sizeof(int));//申请p
	int* q = (int*)malloc(10 * sizeof(int));//申请q
	p = q;//让其相等,p指向q,p原先的内存空间没有释放,其他人都不能访问,p也不能访问,造成内存泄漏
	*/
	//改正
	int* p = (int*)malloc(10 * sizeof(int));//申请p
	int* q = (int*)malloc(10 * sizeof(int));//申请q
	free(p);
	p = q;//让其相等,p指向q,p原先的内存空间没有释放,其他人都不能访问,p也不能访问,造成内存泄漏
	free(q);
}

(5)free函数报错的原因:

     (a)同一块内存连续释放;

     (b)free释放内存块A,但其参数并不是A的开始地址

int main()
{
	/*  报错,free释放内存块p,但其参数并不是p的开始地址
	int* p = (int*)malloc(10 * sizeof(int));//申请p
	printf("%p\n", p);
	p++;
	printf("%p\n", p);//p指向第二个地址
	free(p);
	*/
	//改正
	int* p = (int*)malloc(10 * sizeof(int));//申请p
	int* q =p;//备份,防止释放的不是p的开始地址
	printf("%p\n", p);
	p++;
	printf("%p\n", p);//p指向第二个地址
	free(q);
	free(p);
}

     (c)free释放后,会造成一个悬空指针

        悬空指针:野指针,会造成不可知的错误,一般来说

        空指针:指向0地址的指针,非NULL即真

       一般来说,free函数执行结束后会将其执行为NULL

int main()
{
	/*报错,连续释放p
	int* p = (int*)malloc(10 * sizeof(int));//申请p
	free(p);
	free(p);
	*/
	//改正
	int* p = (int*)malloc(10 * sizeof(int));//申请p
	free(p);
	p = NULL;//修改为空
	free(p);//free传入空指针直接退出
}

4、函数指针:本质是一个指针,只是指针指向一个函数,编译器在编译期间对函数开辟了一块空间,而这块空间的开始地址就是函数开始地址。

         C标准规定,函数名是其开始地址,所以用指针p获取函数地址  p = &Max    或    p = Max

函数指针p怎么调用:int tmp = (*p)(10, 20);//(*p)需要提高优先级
                                   tmp=p(10,20)也可以

int Max(int a, int b)
{
	return a > b ? a : b;
}
int main()
{
	int(*p)(int, int);
	p = &Max;//p = Max取地址和不去地址一样
	int tmp = (*p)(10, 20);//(*p)需要提高优先级
	//tmp=p(10,20)也可以
	printf("%d\n", tmp);
}

5、编写简单计算器利用函数指针

int Add(int a, int b)
{
	return a + b;
}
int Sub(int a, int b)
{
	return a-b;
}
int Mul(int a, int b)
{
	return a* b;
}
int Div(int a, int b)
{
	if (b == 0)
	{
		return -1;
	}
	else
	{
		return a / b;
	}
}
int Computer(int a, int b, int(*p)(int, int))
{
	return p(a, b);
}
int main()
{
	printf("a+b=%d\n", Computer(10, 20, Add));
	printf("a-b=%d\n", Computer(10, 20, Sub));
	printf("a*b=%d\n", Computer(10, 20, Mul));
	printf("a/b=%d\n", Computer(10, 20,Div));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值