结构体变量的指针

一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。

1. 通过指向结构体变量的指针引用结构体变量中的成员
下面通过一个简单例子来说明指向结构体变量的指针变量的应用。例7.3 指向结构体变量的指针的应用。

#include <iostream>
#include <string>
using namespace std;
int main( )
{
   struct Student//声明结构体类型student
   {
      int num;
      string name;
      char sex;
      float score;
   };
   Student stu;//定义Student类型的变量stu
   Student *p=&stu;//定义p为指向Student类型数据的指针变量并指向stu
   stu.num=10301;//对stu中的成员赋值
   stu.name=″Wang Fun″;//对string变量可以直接赋值
   stu.sex=′f′;
   stu.score=89.5;
   cout<<stu. num<<″ ″<<stu.name<<″ ″<<stu.sex<<″ ″<<
   stu.score<<endl;
   cout<<p -> num<<″ ″<<(*p).name<<″ ″<<(*p).sex<<″ ″<<
   (*p).score<<endl;
   return 0;
}

程序运行结果如下:
10301 Wang Fun f 89.5 (通过结构体变量名引用成员)
10301 Wang Fun f 89.5 (通过指针引用结构体变量中的成员)
两个cout语句输出的结果是相同的。

为了使用方便和使之直观,C++提供了指向结构体变量的运算符->, 例如p->num表示指针p当前指向的结构体变量中的成员num。
    p->num 和(*p).num等价。
同样
    p->name等价于(*p).name。
也就是说,以下3种形式等价:
① 结构体变量.成员名。如stu.num。
② (*p).成员名。如(*p).num。
③ p->成员名。如p->num。

“->”称为指向运算符。
请分析以下几种运算:
p->n 得到p指向的结构体变量中的成员n的值。
p->n++ 得到p指向的结构体变量中的成员n的值,用完该值后使它加1。
++p->n 得到p指向的结构体变量中的成员n的值,并使之加1,然后再使用它。

2. 用结构体变量和指向结构体变量的指针构成链表

链表是一种常见的重要的数据结构。图7.8表示最简单的一种链表(单向链表)的结构。

图7.8
链表有一个“头指针”变量,图中以head表示,它存放一个地址。该地址指向一个元素。链表中的每一个元素称为“结点”,每个结点都应包括两个部分:
一是用户需要用的实际数据,
二是下一个结点的地址。

可以看到链表中各元素在内存中的存储单元可以是不连续的。要找某一元素,可以先找到上一个元素,根据它提供的下一元素地址找到下一个元素。
可以看到,这种链表的数据结构,必须利用结构体变量和指针才能实现。
可以声明一个结构体类型,包含两种成员,一种是用户需要用的实际数据,另一种是用来存放下一结点地址的指针变量。

例如,可以设计这样一个结构体类型:
struct Student
{
   int num;
   float score;
   Student *next;//next指向Student结构体变量
};

其中成员num和score是用户需要用到的数据,相当于图7.8结点中的A,B,C,D。next是指针类型的成员,它指向Student类型数据(就是next所在的结构体类型)。用这种方法就可以建立链表。见图7.9。

图7.9
图中每一个结点都属于Student类型,在它的成员next中存放下一个结点的地址,程序设计者不必知道各结点的具体地址,只要保证能将下一个结点的地址放到前一结点的成员next中即可。

下面通过一个例子来说明如何建立和输出一个简单链表。

例7.4 建立一个如图7.9所示的简单链表,它由3个学生数据的结点组成。输出各结点中的数据。
#define NULL 0
#include <iostream>
struct Student
{
   long num;
   float score;
   struct Student *next;
};

int main( )
{
   Student a,b,c,*head,*p;
   a. num=31001;
   a.score=89.5;//对结点a的num和score成员赋值
   b. num=31003;
   b.score=90;//对结点b的num和score成员赋值
   c. num=31007;
   c.score=85;//对结点c的num和score成员赋值
   head=&a;//将结点a的起始地址赋给头指针head
   a.next=&b; //将结点b的起始地址赋给a结点的next成员
   b.next=&c; //将结点c的起始地址赋给b结点的next成员
   c.next=NULL; //结点的next成员不存放其他结点地址
   p=head; //使p指针指向a结点
   do
   {
      cout<<p->num<<″ ″<<p->score<<endl; //输出p指向的结点的数据
      p=p->next; //使p指向下一个结点
   } while (p!=NULL); //输出完c结点后p的值为NULL
   return 0;
}
请读者考虑:
①各个结点是怎样构成链表的。
②p起什么作用?

本例是比较简单的,所有结点(结构体变量)都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为静态链表。对各结点既可以通过上一个结点的next指针去访问,也可以直接通过结构体变量名a,b,c去访问。

动态链表则是指各结点是可以随时插入和删除的,这些结点并没有变量名,只能先找到上一个结点,才能根据它提供的下一结点的地址找到下一个结点。只有提供第一个结点的地址,即头指针head,才能访问整个链表。如同一条铁链一样,一环扣一环,中间是不能断开的。

建立动态链表,要用到后面介绍的动态分配内存的运算符new和动态撤销内存的运算符delete。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值