指向结构体变量的指针
一个结构体变量的指针:该变量所占据内存的起始位置。可以设置一个指针变量来指向一个结构体变量,此时指针变量的值就是该结构体变量的起始位置。
指针也可以用来指向结构体数组中的元素。
A 通过指向结构体变量的指针引用结构体成员
例子1:
结构体变量的指针变量的应用
#include <iostream>
#include <string>
using namespace std;
int main()
{
struct student
{
int num;
string name;
char sex;
float score;
};
student s;
student *p=&s;
s.num=91022333;
s.sex='f';
s.name="lihaozhe";
s.score=92.13;
cout<<s.num<<' '<<s.name<<' '<<s.sex<<' '<<s.score<<endl;
cout<<(*p).num<<' '<<(*p).name<<' '<<(*p).sex<<' '<<(*p).score<<endl;
return 0;
}
注:(*p)表示指针变量p指向的结构体变量。(*p).num是p指向的结构体变量中的成员num。等价于s.num
(*p).num中的括号不可省略,因为‘.’优先于'*'
为了更加方便直观,c++提供了指向结构体变量的成员运算符“->”。(指向运算符)形象地表示了“指向关系”。例如:p->num就表示指针p指向结构体的成员num。
一下三种表达等价:
1. 结构体变量.成员名;
2. (*p).变量名;
3. p->变量名;
B 用结构体变量和指向结构体变量的指针构成链表
链表是一种常见且重要的数据结构。
链表有一个“头指针”的变量,他存放一个地址,该地址指向链表第一个元素。
链表中的每一个元素称为“结点”,每一个结点都应包括两部分:1. 用户需要用的实际数据;2. 下一个节点的地址。
头指针->第一个元素->第二个元素->...->最后一个元素。
最后一个元素不再指向其他元素,称为表尾。它的地址部分放一个“NULL”(表示空地址),链表到此结束。
正因为它的这种特性,链表中各元素在内存中的存储单元可以是不连续的。要找某一元素,可以先找到上一个元素,根据他提供的下一个元素地址找到下一个元素。
这种链表的数据结构,必须要用结构体和指针才能实现。可以先声明一个结构体类型,包括两种成员:1. 用户所需要的实际数据;2. 用来存放下一节点地址的指针变量。
struct student
{
int num;
float score;
student *next;
}
在使用链表时,程序设计者不必知道具体各节点的具体地址,只要能保证将下一节点的地址放到前一节点的成员next中即可。
例子1:
如何建立和输出一个简单的链表。(由三个学生数据的结点组成,输出各节点中的数据)
#include <iostream>
#include <string>
using namespace std;
struct student
{
int num;
float score;
student *next;
};
int main()
{
student a,b,c,*head,*p;
a.num=222;a.score=77.7;
b.num=233;b.score=77.77;
c.num=666;c.score=92.13;
head=&a;
a.next=&b;
b.next=&c;
c.next=NULL;
p=head;
do
{
cout<<p->num<<' '<<p->score<<endl;
p=p->next;
}while(p!=NULL);
return 0;
}
注:1. 各个结点是如何构成链表的?开始时使head指向a结点,a.next指向b结点,b.next指向c结点,这就构成了链表关系。 c.next=NULL的作用是使c.next不指向任何有用的存储单元。
2. 指针变量p有什么作用?在输出链表时要借助指针变量p。“p=p->next;”是为输出下一个节点做准备。此时指针变量p的值已经 是下一个节点的地址(占据内存的起始位置)。
3. 本例子是比较简单的静态链表。所有节点都是在程序中定义的,不是临时开辟的,也不能用完后释放。对各个节点的访问既 可以通过上一结点的next指针访问,也可以通过结构体变量名a,b,c访问。
4. 动态链表:各节点可以随时插入和删除的,这些结点并没有变量名。只能先找到上一个结点才能根据他提供的下一结点的地址 找到下一结点。只有提供第一个结点的地址——头指针head,才能访问整个链表。(需要用到动态分配内存的运算符“new”和动态撤销 内存的运算符“delate”)
C 用new和delete运算符进行动态分配和撤销存储空间
在软件开发中常常需要动态的分配和撤销内存空间(例如,动态链表中结点的插入与删除)。作为运算符的new和delete,相比函数有更高的执行效率。
new int;//开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(指针)
new int(100);//开辟存放一个整数的空间,并制定该整书的数值为100,返回一个指向该存储空间的地址(指针)
new char[10];//开辟一个存放字符数组(包括10个元素)的空间,返回字符数组首元素的地址
new int[5][4];//开辟一个存放二位整形数组(大小为5*4)的空间,返回首元素的地址
float *p=new float(3.14159);//开辟一个存放单精度数的空间,并指定该数的初始值为3.14159,将返回的该空间的地址赋给指针变量p
注:new运算符使用的一般格式为:new 类型 (初值)
用new分配数组空间时,不能指定初值。
如果由于内存不足等原因而无法正常分配空间时,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否 成功。
delete运算符的使用格式:
delete 指针变量 (对变量)
delete[]指针变量 (对数组)
例子1:
临时开辟一个存储空间一存放一个结构体数据。
#include <iostream>
#include <string>
using namespace std;
struct student
{
string name;
int num;
char sex;
};
int main()
{
student *p;
p=new student;
p->name="li hao zhe";
p->num=666;
p->sex='m';
cout<<p->name<<' '<<p->num<<' '<<p->sex<<endl;
delete p;
return 0;
}
注:在main函数中并没有定义结构体变量,而是定义了一个基类型为student的指针变量p,并由new开辟一段空间以存放一个student类型的数据,空间的大小由系统根据student自动弹出,不必用户指定。
执行new得到i个指向student类型数据的指针(即所开辟的存储空间的起始地址),把他赋给p。就可以通过p来对这个无名的结构体变量进行操作。