c语言数组指针和指针数组辨析,浅析内存泄漏

博客主页:https://blog.csdn.net/weixin_46094737?type=blog
欢迎评论⭐留言  如有错误敬请指正!
本文由小学生廉原创,首发于 CSDN🙉🙉🙉
未来很长,值得我们全力奔赴更美好的生活!💞💞💞

一、内存泄露

使用malloc()、calloc()、realloc()动态分配的内存,如果没有指针指向他,就无法进行任何操作,这段内存会一直被程序占用,知道程序运行结束由操作系统回收。

请看下面代码:

#include <stdio.h>
#include <stdlib.h>
int main(){
    char *p = (char*)malloc(100 * sizeof(char));
    p = (char*)malloc(50 * sizeof(char));
    free(p);
    p = NULL;
    return 0;
}

1、该程序中,第一次分配100字节的内存,并将p指向他;第二次分配50字节的内存,依然使用p指向他。

这就导致了一个问题,第一次分配的100字节的内存没有指针指向他了,而且我们也不知道这块内存的地址,所以就再也无法找回了,也没法释放了,这块内存就成了垃圾内存,虽然毫无用处,但依然占用资源,唯一的办法就是等程序运行结束后由操作系统回收。

这就是内存泄露,可以理解为程序和内存失去了联系,再也无法对他进行任何的操作。

内存泄露形象的比喻是“操作系统可提供给所有程序使用的内存空间正在被某个程序榨干”,最终结果是程序运行时间越长,占用内存空间越来越多,最终用尽全部内存空间,整个系统崩溃。

2、再来看一种内存泄露情况:

int *pOld = (int*) malloc( sizeof(int) );
int *pNew = (int*) malloc( sizeof(int) );

这两句代码分别创建了一块内存,并且将内存的地址传给了指针pOld和pNew。此时指针pOld和pNew分别指向这两块内存。

如果接下来进行这样的操作:

pOld = pNew;

pOld指针就指向了pNew指向的内存地址,这时候再进行释放内存的操作:

free(pOld);

此时释放的pOld所指向的内存空间就是原来pNew指向的,于是这块空间被释放掉了。但是pOld原来指向的那块内存空间还没有被释放,不过因为没有指针指向这块内存,所以这块内存就造成了丢失。

3、另外,你不应该进行类似下面这样的操作:

malloc( 100 * sizeof(int) );

这样的操作没有意义,因为没有指针指向分配的内存,无法使用,而且无法通过free()释放掉,造成了内存泄露。

总结
free()函数的用处在于实时的回收内存,如果程序简单,程序结束前也不会使用过多的内存,不会降低系统性能,那么也可以不写free()函数。当程序结束后,操作系统释放内存。

但是如果在开发大型程序时不写free()函数,后果是非常严重的。这是因为很可能在程序中要重复一万次分配10M的内存,如果每次进行分配后都使用free()函数释放用完的内存空间,那么整个程序只需要使用10MB内存就可以运行。但是如果不使用free()函数,那么程序就要使用100GB的内存!这其中包括绝大部分的虚拟内存,而由于虚拟内存的操作需要读写磁盘,因此,这样会极大的影响到系统的性能,系统因此可能崩溃。

因此,在程序中使用malloc()分配内存时都对应的写出一个free()函数是一个良好的编程习惯。这不但能体现在处理大型程序时的必要性,并能在一定程度上体现程序优美的风格和健壮性。

二、函数指针数组 

顾名思义,就是每个元素都是函数指针的数组,直接在函数指针名后面加上数组符号[ ]即可。

声明形式:type (*func[ ])(参数列表 )

C语言函数不可以定义为数组,只能通过函数指针来操作定义函数指针数组。

#include <stdio.h>

int add(int x,int y)//普通函数 
{
    return x+y;
}
int sub(int x,int y)//普通函数 
{
    return x-y;
}
int cheng(int x,int y)//普通函数 
{
    return x*y;
}
int chu(int x,int y)//普通函数 
{
    return x/y;
}

int (*fun[4])(int,int)={add,sub,cheng,chu};//函数指针数组,将函数功能模块封装起来,由一个函数指针数组(*fun[n])统一管理 

int main ()
{
	int x,y;
	char ch; 
	printf("请输入运算符:\n");
	ch=getchar();
	switch(ch)
	{
		case '+':
			printf("请输入两个整数(以空格分隔,回车结束):\n");
			scanf("%d %d",&x,&y);
			printf("%d+%d=%d",x,y,fun[0](x,y));
			break;
		case '-':
			printf("请输入两个整数(以空格分隔,回车结束):\n");
			scanf("%d %d",&x,&y);
			printf("%d-%d=%d",x,y,fun[1](x,y));
			break;
		case '*':
			printf("请输入两个整数(以空格分隔,回车结束):\n");
			scanf("%d %d",&x,&y);
			printf("%d*%d=%d",x,y,fun[2](x,y));
			break;
		case '/':
			printf("请输入两个整数(以空格分隔,回车结束):\n");
			scanf("%d %d",&x,&y);
			printf("%d/%d=%d",x,y,fun[3](x,y));
			break;
		default:
			break;
	}
//	fun = &add;
//	printf("10加上5等于%d\n",fun(10,5));
//	fun = &sub;
//	printf("10减去5等于%d\n",fun(10,5));
//	fun = &cheng;
//	printf("10乘以5等于%d\n",fun(10,5));
//	fun = &chu;
//	printf("10除5等于%d",fun(10,5));
	
	return 0;
}

 运行结果:

 使用条件限制一:

在子函数中,需要限制两个整型形参变量。

使用条件限制二:

子函数的返回值需要是一个整型变量。

数组指针和指针数组 

1.数组指针:定义 int (*p)[n];
由于()的优先级高,首先说明p是一个int类型指针,它是指向一个整型(int)的一维数组,这个一维数组的长度是n,也可以说是总共有n个格子。数组指针也称指向一维数组的指针,亦称行指针。
数组指针也可以称为“数组的指针”,首先这个变量是一个指针,其次,”数组”修饰这个指针,意思是说这个指针存放着一个数组的首地址,或者说这个指针指向一个数组的首地址。

2.指针数组:定义 int *p[n];
指针数组可以说成是”指针的数组”,由于*p没有括号,首先这个变量是一个数组,其次,”指针p”修饰这个数组,意思是说这个数组的所有元素都是指针类型,而指针所占的字节数和其类型无关,只与系统有关,在32位系统下,任何类型的指针占据4个字节,在64位系统下,任何类型的指针占据8个字节。

示例

使用一个二维数组指针,遍历打印一个二维数组

#include <stdio.h>
int main()
{
	int i,j;
	int arr[2][2]={{20,30},{40,50,}};
	int (*p)[2];//定义一个二维数组指针 
	p=arr;//指针指向数组首地址
	for(i=0;i<2;i++)
	{
		for(j=0;j<2;j++)
			printf("arr[%d][%d]=%d ",i,j,*(*(p+i)+j));//遍历打印数组所有元素 
		printf("\n"); 
	}
	
	return 0;
} 

运行结果:

使用一个指针数组,打印一串字符

#include <stdio.h>

int main()
{
	int a=100;
	printf("a的地址为:%#p\n",&a);
	char *name[2]={"hello","nihao"};//指针的数组,数组名字name 
	int i;
	for(i=0;i<2;i++)
		printf("%s ",name[i]);
	printf("\n"); 
	int *arr01[1]={&a};
	printf("指针数组首地址为:%#p\n",*arr01);
	printf("指针数组首地址元素的值为:%d",*arr01[0]);
	return 0;
 } 

运行结果:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不掉头发的程序猿_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值