10.3 关于动态存储的函数
众所周知,构成链表结构的每一个节点,是在需要时由系统自动分配存储的,即在需要时才开辟一个节点的存储单元。C语言编译系统是如何动态地开辟和释放存储单元的呢?在C语言的库函数中有以下有关函数。
考点4 malloc()函数
真考链接
考点4 偏难,属于重点理解内容。在选择题中考核概率为40%。在操作题中,主要以修改题的形式进行考查,考核概率为10%。
ANSIC标准规定 malloc()函数返回值的类型为 void*。
函数的调用形式为:
malloc(size)
其中,size的类型为unsigned int。
功能:malloc()函数用来分配size个字节的存储区,返回一个指向存储区首地址的基类型为void的地址。若没有足够的内存单元供分配,则函数返回空(NULL)。
在ANSIC中,malloc()函数返回的地址为void*(无值型),所以在调用函数时,必须利用强制类型转换将其转换成所需的类型。此处括号中的*号不可少。
由动态分配得到的存储单元没有名字,只能靠指针变量来引用它。一旦指针改变指向,原存储单元及所存数据都将无法再引用。通过调用malloc()函数所分配的动态存储单元中没有确定的初值。
一般情况下,若不能确定数据类型所占字节数,可以使用sizeof运算符来求得。这是一种常用的形式,它由系统来计算指定类型的字节数。
真题精选
【例1】有以下程序:
#include<stdio.h>
#include<stdlib.h>
int fun(int n)
{ int *p;
p =(int *)malloc(sizeof(int));
*p = n;
return *p;
}
main()
{ int a;
a = fun(10);
printf("% d\n",a + fun(a));
}
程序的运行结果是( )。
A.0 B.10 C.20 D.出错
【答案】C
【解析】分配内存空间函数malloc()的调用形式:(类型说明符*)malloc(size)。其功能是在内存的动态存储区中分配一块长度为“size”字节的连续区域,函数的返回值为该区域的首地址。“类型说明符”表示把该区域用于何种数据类型。
【例2】下列给定程序中已建立一个带头节点的单向链表,链表中的各节点按节点数据域中的数据递增有序链接。函数fun()的功能是:把形参 x的值放入一个新节点并插入链表中,使插入后各节点数据域中的数据仍保持递增有序。
请在标号处填入正确的内容,使程序得出正确的结果。
注意:部分源程序给出如下。不得增行或删行,也不得更改程序的结构。
试题程序
#include <stdio.h>
#include <stdlib.h>
#define N 8
typedef struct list
{ int data;
struct list *next;
}SLIST;
void fun(SLIST *h,int x)
{ SLIST *p,*q,*s;
s=(SLIST *)malloc(sizeof(SLIST));
s->data=【1】;
q=h;
p=h->next;
while(p!=NULL && x>p->data){
q=【2】;
p=p->next;
}
s->next=p;
q->next=【3】;
}
SLIST *creatlist(int *a)
{ SLIST *h,*p,*q;int i;
h = p =(SLIST *)malloc(sizeof (SLIST));
for(i=0;i<N;i++)
{ q =(SLIST *)malloc(sizeof (SLIST));
q->data=a[i];p->next=q;p=q;
}
p->next=NULL;
return h;
}
void outlist(SLIST *h)
{ SLIST *p;
p=h->next;
if(p==NULL)
printf("\nThe list is NULL!\n");
else
{ printf("\nHead");
do {printf("->% d",p->data);
p=p->next;}while(p!=NULL);
printf("->End\n");
}
}
main()
{ SLIST *head;int x;
int a[N] ={11,12,15,18,19,22,25,29};
head=creatlist(a);
printf("\nThe list before inserting:\n");
outlist(head);
printf("\nEnter a number:");
scanf("% d",&x);
fun(head,x);
printf("\nThe list after inserting:\n");
outlist(head);
}
【答案】【1】x 【2】p 【3】s
【解析】本题考查:malloc()函数;链表的基本操作。了解链表的基本思想和相关算法,理解有关链表插入及删除时指针移动的先后顺序问题,注意指针的保存和归位。
标号【1】:将形参x赋值给节点的数据域。
标号【2】和标号【3】:将新的节点和原有链表中的节点进行比较。
考点5 free()函数
真考链接
考点5 偏难,属于重点理解内容。考核概率为 10%。在操作题中,主要以修改题的形式进行考查,考核概率为10%。
函数原型为:
void free(void *p);
该函数的功能是释放由 p所指向的那段内存空间,使这段存储空间能为他用。p是最近一次调用malloc()或calloc()函数时返回的值。
注意:free()函数无返回值。
常见问题
为什么对于曾经使用动态存储来进行分配的指针变量,要在程序结束前,全部用free()函数释放?
因为在程序结束前,全部用free()函数释放可以节约内存,同时要保证内存的安全管理。
真题精选
以下程序的输出结果是( )。
#include <stdio.h>
void fut(int **s,int p[2][3])
{**s=p[1][1];}
main()
{ int a[2][3] ={1,3,5,7,9,11 },*p;
p=(int *)malloc(sizeof(int));
fut(&p,a);
printf("% d\n",*p);
free(p);
}
A.1 B.7 C.9 D.11
【答案】C
【解析】函数fut()中,形参s是一个指向指针的指针,它接受一个基类型为int的指针的地址;p是一个行指针,它可以指向一个二维数组的起始行,此二维数组每行只能有3个元素。在fut()函数的语句"**s=p[1][1];"中,可知p [1][1]的值为9。在主函数中,定义p是一个基类型为int的指针,通过调用malloc()函数,在内存中分配了一个int类型的存储单元,并把其地址赋给了p,使它指向此存储单元。调用语句"fut(&p,a);",把指针p的地址传给了形参s,使s指向了指针p。在fut()函数中,语句"**s=p[1][1];"赋值号的左边,s中放的是主函数中指针p的地址,**s则代表主函数中指针p所指动态分配的存储单元;"**s=p[1][1];"就是把9赋给此动态存储单元。主函数中printf中的输出项是*p,即输出p所指动态存储单元中的值。输出结果为9。总结:malloc()函数是在程序运行、调用该函数时,在内存开辟指定字节的存储单元。malloc()函数返回一个void类型的地址值,因此,若要把此地址赋给基类型为int的指针pi就必须进行强制类型转换,如pi=(int*)malloc(sizeof(int)),而不能直接写成pi=malloc(sizeof(int))。同理,若要把此地址赋给基类型为double的指针pd,就应当写成pd=(double*)malloc(sizeof(double))。强制类型转换时不能把*号丢掉,如把调用语句写成(int)malloc(sizeof (int)),以至要求把指针类型转换为整型,这是不允许的。