指针与数组--动态数组(1)[1、C程序的内存映像 2、动态内存分配]

目录

一、C程序的内存映像

二、动态内存分配

        1、malloc()函数

        2、calloc()函数

        3、free()函数

        4、realloc()函数


一、C程序的内存映像

        一个编译后的C程序 获得并使用4块在逻辑上不同且用于不同目的的内存储区,如下图所示。

        从内存的低端开始,第一块内存为只读存储区,存放程序的机器码和字符串字面量等制度数据。

        第二块为静态存储区 ,用于存放程序中的全局变量和静态变量等。

        第三部分和第四部分称为堆(heap)和栈(stack),为动态存储区。

其中,堆(heap)用于保存函数调用时的返回地址、函数的形参、局部变量即cpu的当前状态等程序的运行信息。堆是一个自由存储区,程序可利用C的动态内存分配函数来使用它。

        虽然这4块区域的实际物理布局随CPU的类型和编译程序的实现而异。

C语言程序中变量的内存分配方式有以下三种:

(1)从静态存储区分配

        程序的全局变量和静态变量都在静态存储区上分配,且在程序编译时就已经分配好了,在程序运行期间时钟占据这些内存,仅在程序终止前,才被操作系统收回。

(2)在栈上分配

        在执行函数调用时,系统在栈上为函数内的局部变量及形参分配内存,函数执行结束时,自动释放这些内存。栈内存分配运算内置于处理器的指令集中,效率很高,但是容量有限。如果往栈中压入的数据超出预先给栈分配的容量,那么就会出现栈溢出,从而使程序运行失败。

(3)从堆上分配

        在程序运行期间,用动态内存分配函数来申请的内存都是从堆上分配的。

        动态内存的生存期是由程序员自己来决定的,使用非常灵活,但也最易出现内存泄漏等问题。为防止内存泄漏的发生,程序员必须及时调用free()释放已不再使用的内存。

二、动态内存分配函数

在C语言中,指针之所以重要,原因有以下4点:

(1)指针为函数提供修改变量值的手段;

(2)指针为C的动态内存分配系统提供支持;

(3)指针为动态数据结构(如链表、队列、二叉树等)提供支持;

(4)指针可以改善某些子程序的效率。

        在前面文章中,我们已经了解到指针的一个重要应用是用指针作函数参数,为函数提供了一种修改变量的手段。当用指针作函数形参时,须将函数外的某个变量的地址传给函数形参列表中相应的指针变量,以便函数内的代码通过指针变量来改变函数外的这个变量的值。

        此外,因指针的增1和减1运算速度很快,所以用指针变量来寻址数组元素可提高程序的执行效率。

        指针的另一个重要应用是把指针与动态内存分配函数联用,它使得实现动态数组(Dynamically Allocated Array)称为可能。

        动态内存分配(Dynamic Memory Allocation)是指在程序运行时为变量分配内存的一种方法。

        全局变量是编译时分配的,非静态的局部变量使用栈空间,因此两者在程序运行时既不能添加,也不能减少。而实际应用中,有时在程序运行中需要数量可变的内存空间,即在运行时才能确定要用多少个字节的内存来存放数据。(c99可以支持动态数组定义方式,但是c89就不支持,必须使用宏常量。)定义方式如下:

int  m,n;

int  a[m][n];

        能否在程序运行的过程中根据用户的需求生成可变长度的动态数组呢?

        这就要用动态内存分配函数来实现。C的动态内存分配函数从堆上分配内存。使用这些函数时只要在开头将头文件<stdlib.h>包含到源程序中即可。

1、malloc()函数

        函数malloc()用于分配若干字节的内存空间,返回一个指向该内存首地址的指针。若系统不能提供足够的内存单元,函数将返回空指针NULL。

函数malloc()的原型为:

        void *malloc(unsigned int size); 

其中,size表示向系统申请空间的大小,函数调用成功将返回一个指向void类型的指针。

        void * 指针式ANSI  C新标准中增加的一种指针类型,具有一般性,通常称为通用指针(Generic Pointer)者无类性的指针(Typeless Pointer),常用来说明其基类型未知的指针,即声明了一个指针变量,但未指定它可以指向哪一种基类型的数据。因此,若将函数调用的返回值赋予某个指针,则应先根据该指针的基类型,用强转的方法将返回的指针值强转为所需要的类型,然后在进行赋值操作。

例如:  int  *pi  =  NULL;    pi = (int *)malloc(2);

其中,malloc(2)表示申请一个大小为2个字节的内存,将malloc(2)返回值的 void *类型强转为int * 类型后在赋值给int型指针变量pi,即用int型指针变量pi指向这段存储空间的首地址。            若不能确定某种类型所占内存的字节数,则须使用sizeof()计算系统中该类型所占内存的字节数,然后再用malloc()向系统申请相应字节数的存储空间。

例如:pi = (int *)malloc(sizeof(int));///这种方法有利于提高程序的可移植性。

2、calloc()函数

        函数calloc()用于给若干同一类型的数据项分配连续的存储空间并赋值为0,其函数原型为:        void * alloc(unsigned int num,unsigned int size);

它相当于一个声明了一个一维数组。其中,第一个参数num表示向系统申请的内存空间量,决定了一维数组的大小,第二个参数size表示申请的每个空间的字节数,确定了数组元素的类型。而函数的返回值就是数组的首地址。

        若函数调用成功,则返回一个指向void类型的连续存储空间的首地址,否则返回空指针NULL。若要将函数的返回地址赋值给某个指针变量,则应先根据该指针的基类型,将其强转为与指针类型相同的数据类型,然后在进行赋值操作。

例如:float *pf  =  NULL;pf  =  (float*)calloc(10,sizeof(float));

表示向系统申请了10个连续的float型存储单元,并用指针pf指向该连续内存的首地址,系统申请的总的内存字节数为10×sizeof(float),相当于使用下面的语句:

pf  =  (float*)malloc(10*sizeof(float));

但从安全角度考虑,使用calloc()更加明智,因为与malloc()相比,calloc()能将自动分配的内存初始化为0。

3、free()函数

        函数free()的功能是释放向系统动态申请的由指针p指向的存储空间,其原型为:

void   free (void *p);

该函数无返回值。唯一的形参p只能由malloc()和calloc()申请内存是返回的地址。

该函数执行后,将以前分配的由指针p指向的内存返回给系统,以便由系统重新支配。

4、realloc()函数

        函数realloc()用于改变原来分配的存储空间的大小,其原型为:

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

该函数的功能是将指针p所指向的存储空间的大小改为size个字节,函数返回值是新分配的存储空间的首地址,与原来分配的首地址不一定相同。

        由于动态内存分配的存储单元是无名的,只能通过指针变量来引用它们,所以一旦改变了指针的指向,原来分配的内存即数据也就随之丢失。因此不要轻易改变该指针的变量值。 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值