如果要存储多个学生的数据,但又不知道有多少个学生,怎么存储呢?可以定义一个很大的结构体数组,但浪费存储空间。一种较好的方法是结合指针和结构体来实现:对输入的每一个同学的数据,动态申请一个结构体变量存储他的数据;并“设法”将存储这些学生数据的结构体变量“串接”起来,如下图所示。这样的好处是既节省存储空间;又能访问每个学生的数据因为它们已经“串接”成一个整体了
怎样将相同类型的结构体变量“串接”起来呢?我们知道指针的作用是用来指向某个变量。如果在结构体中包含一个基类型为同种结构体类型的指针成员,那就可以实现“串接”。例如,我们可以在前面引入的student结构体中增加一个指针成员。此处的next指针需要指向下一个学生的数据,所以基类型必须是student类型
struct student
{
char name[20];
int age;
double score;
student *next; //改成“int *p;”更利于理解
};
在C语言中,动态申请存储空间要用malloc函数实现,释放存储空间要用free函数实现。在C++语言中,动态申请存储空间和释放存储空间分别是用new和delete运算符实现的。以下只介绍new、delete运算符
(1)申请单个变量所占存储空间的形式为:
指针变量名 = new 类型名(初值); //初值是可选的
例如:
int *p1, *p2, *p3;
p1 = new int; //申请一个存放整数的存储空间(没有名称),返回给指针p1
p2 = new int(100); //申请一个存放整数的空间,初值为100
(2)申请数组存储空间的形式为:
指针变量名 = new 类型名[表达式];
其中表达式为数组长度,可以包含变量。例如:
int n = 5;
p3 = new int[n]; //申请一个存放5个元素的空间,将存储空间首地址赋给p3
(3)释放单个变量所占存储空间的形式为:
delete 指针变量名;
(4)释放数组存储空间的形式为:
delete [ ]指针变量名;
例如:
delete p1; //释放由p1所指向的单个变量所占的存储空间
delete [ ]p3; //释放由p3所指向的数组存储空间
注意,如果释放数组存储空间时,忘了写[ ],那么只能释放第0个元素所占存储空间,其他元素所占存储空间未能释放
释放存储空间后,又可以重新申请新的存储空间。例如:
n = 10;
p3 = new int[n]; //申请一个存放10个元素的空间,将存储空间首地址赋给p3
在student结构体中增加next指针成员后,就可以实现简单链表了
例1:输入每个学生的数据(包括姓名、年龄、分数),当输入“END”时代表输入结束。对输入的每个学生的数据,动态申请存储空间来存储,并将每个学生的数据构造链表。输出每个学生的姓名。最后释放链表中的结点
#include<bits/stdc++.h>
using namespace student
struct student
{
char name[20];
int age;
float score;
student *next; //指向下一个结构体变量的指针成员
};(
int main()
{
char name1[30];
student *head = NULL; //指向第一个结点的指针
student *p = NULL; //用来动态申请存储空间
int first = 1; //是否是第一个学生的标志
while(1){ //用针循环
cin getline(name1, 20); //输入学生姓名,允许有空格
if(strcmp(name1,"END")==0) break; //输入END代表输入结束
pt = new student; //动态申请可以储存一个student数据的存储空间
strcpy(py->name, name1);
cin >> pt -> age; //输入年龄
cin >> pt -> score; //输入成绩
pt->next = NULL;
//以下构造链表
if(first){ //第一个结点
first = 0; head = p = pt;
}
else{ //在链表末尾插入结点
p->next = pt; p = p->next;
}
getchar(); //跳过末尾的回车键,否则下一次getline()函数读入该回车键
}
pt = head;
while(pt){ //等价于pt!=NULL
cout << pt -> name << endl; //输出所有学生的姓名
pt = pt -> next; //pt指向下一个学生
}
p = head; head = NULL;
while(p){ //等价于p!=NULL
pt = p;
p = p->next;
delete pt; //释放所有结点所占存储空间
}
return 0;
}
该程序包含两个重要的过程:
构造链表、释放链表
三个指针的作用:
①head指针:指向头结点(即第个结点);
②p指针:指向当前结点(即当前最后一个结点);
③pt指针:指向新申请的结点
if(first){ //第一个结点
first 0; head = p = pt;
else{ //在链表末尾插入结点
p->next pt; p = p->next;
}
释放链表过程中两个指针的作用为:
①p指针:指向剩余链表中的第一个结点
②pt指针:指向将被释放的结点
p = head; head = NULL;
while(p){ //等价于p!=NULL
pt = p;
p = p->next;
delete pt; //释放所有结点所占存储空间
}
return 0;
}