动态内存分配与指向它的指针变量

目录

全局变量和局部变量

什么是内存的动态分配

怎样建立内存的动态分配

1、用malloc函数开辟动态存储区

2、用calloc函数开辟动态存储区

3、用recalloc函数重新分配动态存储区

4、用free函数释放动态存储区

 void指针类型


全局变量和局部变量

不要大量的使用全局变量

使用过多的全局变量会是你的程序占用更多的内存,因为全局变量从被定义的时候开始,知道程序退出才释放。

污染命名空间,虽然局部变量会拼比全局变量,但这样一来也会降低程序的可读性,人们往往很难一下子判断出每个变量的含义和作用范围。

提高了程序的耦合性,牵一发而动全身,时间久了,代码长了,你都不知道全局变量被哪些函数修改过。

什么是内存的动态分配

全局变量是分配在内存中的静态存储区的,非静态的局部变量(包括形参)是分配在内存中的动态存储区的,这个存储区是一个称为的区域。除此以外,C语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放。这些数据是临时存放在一个特别的自由存储区,称为区。可以根据需要,向系统申请所需要大小的空间。由于未在声明部分定义它们为变量或数组,因此不能通过变量名或数组名区引用这些数据,只能通过指针来引用。

怎样建立内存的动态分配

对内存的动态分配是通过系统提供的库函数来实现的,主要有malloc,calloc,free,realloc 这四个函数。

1、用malloc函数开辟动态存储区

void *malloc(unsigned int size)

 其作用是在内存的动态存储区中分配一个长度为size的连续空间。形参size的类型定位无符号整型。此函数的值(即“返回值”)是所分配区域的第一个字节的地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的第一个字节。如:

malloc(100) ;        //开辟100字节的临时分配域,函数值为其第一个字节的地址

注意:指针的基类型为void,即不指向任何类型的数据,只提供一个纯地址。如果此函数未能成功地执行(例如内存空间不足),即返回空指针(NULL)。

2、用calloc函数开辟动态存储区

void *calloc(unsigned n,unsigned size)

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

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

下面两种写法是等价的:

// calloc()分配内存空间并初始化
int *ptr=(int *)calloc(8,sizeof(int));
// malloc()分配内存空间并用memset() 初始化
int *ptr =(int *)malloc(8 *sizeof(int));
memset(ptr,0,8*sizeof(int));

3、用recalloc函数重新分配动态存储区

void *realloc(void *p,unsigned int size);

如果已经通过malloc函数或calloc函数获得了动态空间,想改变其大小,可以用recalloc函数重新分配。

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

4、用free函数释放动态存储区

void free(void *p)

其作用是释放指针变量p所指向的动态空间,使这部分空间能重新被其他变量使用。p应该是最近一次调用malloc和calloc函数时得到的函数返回值。

free(p);               //释放指针p所指向的已分配的动态空间

free函数无返回值

以上四个函数声明在stdlib.h头文件里面。

 void指针类型

 指向void类型为指向空类型或不指向确定的类型

地址应该包含基类型的信息,即存放在此地址标志的存储单元的=中的数据的类型,否则无法实现对数据的存取。这种无指向的地址所标志的存储单元是不能存储任何数据的,也就是说,无法通过这种地址对内存存取数据。

在调用动态存储分配函数会出现这种地址。以前C版本,函数返回的地址一律指向字符型数据,即得到char*型指针。例如malloc函数的原型为:

char*malloc(unsigned int size);

但是开辟的动态存储区并不一定用来存放字符型数据,;比如想存放一批整型数据。为此,在向该存储区存放整型数据前就需要进行地址的类型转换,如:

pt=(int *)malloc(100);                    //假设已定义:int *pt;

系统会将指向字符数据的指针转换为指向整型数据的指针,然后赋给pt。这样pt就指向存储区的首字节,可以通过pt对该动态存储区进行存取操作。要说明的是:上面的类型,转换只是产生一个临时的中间值赋给了pt,但没有改变malloc 函数本身的类型。
可以看到:在上面的处理中,程序只利用了该函数带回来的纯地址,并没有用到指向字符型数据这一属性。既然用不到,又何必作此规定呢? C99对此作了修改,这些函数不是返回char*指针,而是使其“无指向”,函数返回void *指针。这种指针称为“空类型指针(typeless pointer)”,它不指向任一种具体的类型数据,只提供一个纯地址。这是C有关地址应用的一种特殊情况。

要注意的是:这种空类型指针在形式上和其他指针一样,遵循C语言对指针的有关规定,它也有基类型,只是它的基类型是void。可以这样定义:
void *p;                                       //定义P是void*型的指针变量
void*型指针代表"无指向的地址”,这种指针不指向任何类型的数据。不能企图通过它存取数据,在程序中它只是过渡性的,只有转换为有指向的地址,才能存取教据。
C99这样处理,更加规范,更容易理解,概念也更清晰。
现在所用的一些编译系统在进行地址赋值时,会自动进行类型转换。例如:
int *pt;
 pt=(int*)mcaloc(100);               //mcaloc(100)是 void*型,把它转换为int*型
可以简化为
pt =mcaloc(100);                       //自动进行类型转换
赋值时,系统会先把mealoc( 10)转换为的pt的类型,即(int *)型,然后赋给pt,这样pt北指向存储区的首字节,在其指向的存储单元中可以存放整型数据。

题目:建立动态数组,输入5个学生的成绩,另外用一个函数检查其中有无低于60分的,输出不合格的成绩。

解题思路:用malloc函数开辟一个动态自由区域,用来存5个同学的成绩,会得到这个动态域的第一个字节的地址,它的基类型是void型。用一个基类型为int的指针变量p来指向动态组的各元素,并输出他们得知。但必须先把malloc函数返回的void指针转换为整型指针,然后赋给p1。

#include<stdio.h>
#include<stdlib.h>
int main()
{
	void check(int *);                            //函数声明,这边p可以不写,但*不能丢
	int *p1,i;                                    //p1是int型指针
	p1=(int *)malloc(5*sizeof(int));
	//开辟动态内存区,将地址转换成int *型,然后放在p1中
	for(i=0;i<=4;i++)
		scanf("%d",p1+i);                         //输入5个学生成绩
	 check(p1);                                   //调用check函数
    system("pause");
    return 0;
}

void check(int *p)                                //定义check函数,形参是int*指针
{
   int i;
   printf("They are fail:");
   for(i=0;i<=4;i++)
	   if(p[i]<60)
		   printf("%d ",p[i]);                     //输出不合格者
   printf("\n");
}

程序分析:在程序中没有定义数组,而是开辟一段动态自由分配区,作为动态数组使用。在调用malloc函数时没有给出具体的数值,而是用5*sizeof(int),因为有5个学生的成绩,每个成绩是一个整数,但在不同的系统中存放一个 整数的字节数是不同的,为了使程序具有通用性,故用sizeof运算符测定在本系统中整数的字节数。调用malloc函数的返回值县void*型的,要把它赋给p1,应先进行类型转换,把该指针转换成int*型。用for循环输人5个学生的成绩,注意不是用数组名,而是按地址法计算出相应的存储单元的地址,然后分别赋值给动态数组的5个元素。开始时p1指向第1个整型数据,p1+1指向第2个整型数.....调用check函数时把p1的值传给形参p,因此形参p也指向动态区的第1个数据,可以认为形参数组与实参数组共享同一段动态分配区。都在check函数中,用下标形式使用指针变量p,逐个检查5个数据,输出不合格的成绩。最后用free函数释放动态分配区。
实际上,第6行可以直接写成
p1 = malloc(5 * sizeof(int));                             //pl为整型指针,自动转换
因为在进行编译时,系统可以自动进行隐式的转换,而不必人为地进行显式的强制类型转换。但是有的程序员仍然习惯于进行显式的强制转换(他们认为这样规范、清晰)。因此,读者应当知道转换的方法,能看懂别人的程序。内存的动态分配主要应用于建立程序中的动态数据结构(如链表)中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值