当前位置:主页   - 电脑 - 程序设计 - C/C++
C语言学习教程第七章-结构与联合(5)
来源:网络   作者:    更新时间:2010-09-26
收藏此页】    【字号    】    【打印】    【关闭

topoic=动态存储分配

在数组一章中,曾介绍过数组的长度是预先定义好的, 在整个程序中固定不变。C语言中不允许动态数组类型。例如: int n;scanf("%d",&n);int a[n]; 用变量表示长度,想对数组的大小作动态说明, 这是错误的。但是在实际的编程中,往往会发生这种情况, 即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题, 用数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间, 也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。 常用的内存管理函数有以下三个:

1.分配内存空间函数malloc
调用形式: (类型说明符*) malloc (size) 功能:在内存的动态存储区中分配一块长度为"size" 字节的连续区域。函数的返回值为该区域的首地址。 “类型说明符”表示把该区域用于何种数据类型。(类型说明符*)表示把返回值强制转换为该类型指针。“size”是一个无符号数。例如: pc=(char *) malloc (100); 表示分配100个字节的内存空间,并强制转换为字符数组类型, 函数的返回值为指向该字符数组的指针, 把该指针赋予指针变量pc。

2.分配内存空间函数 calloc
calloc 也用于分配内存空间。调用形式: (类型说明符*)calloc(n,size) 功能:在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。(类型说明符*)用于强制类型转换。calloc函数与malloc 函数的区别仅在于一次可以分配n块区域。例如: ps=(struet stu*) calloc(2,sizeof (struct stu)); 其中的sizeof(struct stu)是求stu的结构长度。因此该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。

3.释放内存空间函数free
调用形式: free(void*ptr); 功能:释放ptr所指向的一块内存空间,ptr 是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或calloc函数所分配的区域:[例7.9]分配一块区域,输入一个学生数据。
main()
{
struct stu
{
int num;
char *name;
char sex;
float score;
} *ps;
ps=(struct stu*)malloc(sizeof(struct stu));
ps->num=102;
ps->name="Zhang ping";
ps->sex='M';
ps->score=62.5;
printf("Number=%d\nName=%s\n",ps->num,ps->name);
printf("Sex=%c\nScore=%f\n",ps->sex,ps->score);
free(ps);
}
本例中,定义了结构stu,定义了stu类型指针变量ps。 然后分配一块stu大内存区,并把首地址赋予ps,使ps指向该区域。再以ps为指向结构的指针变量对各成员赋值,并用printf 输出各成员值。最后用free函数释放ps指向的内存空间。 整个程序包含了申请内存空间、使用内存空间、释放内存空间三个步骤, 实现存储空间的动态分配。链表的概念在例7.9中采用了动态分配的办法为一个结构分配内存空间。每一次分配一块空间可用来存放一个学生的数据, 我们可称之为一个结点。有多少个学生就应该申请分配多少块内存空间, 也就是说要建立多少个结点。当然用结构数组也可以完成上述工作, 但如果预先不能准确把握学生人数,也就无法确定数组大小。 而且当学生留级、退学之后也不能把该元素占用的空间从数组中释放出来。 用动态存储的方法可以很好地解决这些问题。 有一个学生就分配一个结点,无须预先确定学生的准确人数,某学生退学, 可删去该结点,并释放该结点占用的存储空间。从而节约了宝贵的内存资源。 另一方面,用数组的方法必须占用一块连续的内存区域。 而使用动态分配时,每个结点之间可以是不连续的(结点内是连续的)。 结点之间的联系可以用指针实现。 即在结点结构中定义一个成员项用来存放下一结点的首地址,这个用于存放地址的成员,常把它称为指针域。可在第一个结点的指针域内存入第二个结点的首地址, 在第二个结点的指针域内又存放第三个结点的首地址, 如此串连下去直到最后一个结点。最后一个结点因无后续结点连接,其指针域可赋为0。这样一种连接方式,在数据结构中称为“链表”。图7.3为链表的示意图。

在图7.3中,第0个结点称为头结点, 它存放有第一个结点的首地址,它没有数据,只是一个指针变量。 以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号num,姓名name,性别sex和成绩score等。另一个域为指针域, 存放下一结点的首地址。链表中的每一个结点都是同一种结构类型。例如, 一个存放学生学号和成绩的结点应为以下结构:
struct stu
{ int num;
int score;
struct stu *next;
}
前两个成员项组成数据域,后一个成员项next构成指针域, 它是一个指向stu类型结构的指针变量。链表的基本操作对t表的主要操作有以下几种:
1.建立链表;
2.结构的查 与输出;
3.插入一个结点;
4.删除一个结点;
下面通过例题来说明这些操作。
[例7.10]建立一个三个结点的链表,存放学生数据。 为简单起见, 我们假定学生数据结构中只有学号和年龄两项。
可编写一个建立链表的函数creat。程序如下:
#define NULL 0
#define TYPE struct stu
#define LEN sizeof (struct stu)
struct stu
{
int num;
int age;
struct stu *next;
};
TYPE *creat(int n)
{
struct stu *head,*pf,*pb;
int i;
for(i=0;i<n;i++)
{
pb=(TYPE*) malloc(LEN);
printf("input Number and Age\n");
scanf("%d%d",&pb->num,&pb->age);
if(i==0)
pf=head=pb;
else pf->next=pb;
pb->next=NULL;
pf=pb;
}
return(head);
}
在函数外首先用宏定义对三个符号常量作了定义。这里用TYPE表示struct stu,用LEN表示sizeof(struct stu)主要的目的是为了在以下程序内减少书写并使阅读更加方便。结构stu定义为外部类型,程序中的各个函数均可使用该定义。

其它资源
来源声明

版权与免责声明
1、本站所发布的文章仅供技术交流参考,本站不主张将其做为决策的依据,浏览者可自愿选择采信与否,本站不对因采信这些信息所产生的任何问题负责。
2、本站部分文章来源于网络,其版权为原权利人所有。由于来源之故,有的文章未能获得作者姓名,署“未知”或“佚名”。对于这些文章,有知悉作者姓名的请告知本站,以便及时署名。如果作者要求删除,我们将予以删除。除此之外本站不再承担其它责任。
3、本站部分文章来源于本站原创,本站拥有所有权利。
4、如对本站发布的信息有异议,请联系我们,经本站确认后,将在三个工作日内做出修改或删除处理。
请参阅权责声明