详解C++中的指针结构体数组以及指向结构体变量的指针

C++结构体数组
一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组的不同之处在于:每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员项。

定义结构体数组和定义结构体变量的方法相仿,定义结构体数组时只需声明其为数组即可。如:

struct Student //声明结构体类型Student
{
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
};
Student stu[3]; //定义Student类型的数组stu

也可以直接定义一个结构体数组,如:

struct Student
{
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
}stu[3];

struct
{
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
}stu[3];

结构体数组的初始化与其他类型的数组一样,对结构体数组可以初始化。如:

struct Student
{
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
}stu[3]={
  {10101,″Li Lin″,  ′M′, 18,87.5, ″103 Beijing Road″},
  {10102,″Zhang Fun″,′M′,19,99,  ″130 Shanghai Road″},
  {10104,″Wang Min″,′F′,  20,78.5, ″1010 Zhongshan Road″}
};

定义数组stu时,也可以不指定元素个数,即写成以下形式:

  stu[ ]={{…},{…},{…}};

编译时,系统会根据给出初值的结构体常量的个数来确定数组元素的个数。一个结构体常量应包括结构体中全部成员的值。

当然,数组的初始化也可以用以下形式:

  Student stu[ ]={{…},{…},{…}}; //已事先声明了结构体类型Student

由上可以看到,结构体数组初始化的一般形式是在所定义的数组名的后面加上 ={初值表列};
结构体数组应用举例

下面举一个简单的例子来说明结构体数组的定义和引用。

【例】对候选人得票的统计程序。设有3个候选人,最终只能有1人当选为领导。今有10个人参加投票,从键盘先后输入这10个人所投的候选人的名字,要求最后输出这3个候选人的得票结果。

可以定义一个候选人结构体数组,包括3个元素,在每个元素中存放有关的数据。程序如下:

#include <iostream>
using namespace std;
struct Person //声明结构体类型Person
{
  char name[20];
  int count;
};
int main( )
{
  //定义Person类型的数组,内容为3个候选人的姓名和当前的得票数
  Person leader[3]={"Li",0,"Zhang",0,"Fun",0};
  int i,j;
  char leader_name[20]; //leader_name为投票人所选的人的姓名
  for(i=0;i<10;i++)
  {
   cin>>leader_name; //先后输入10张票上所写的姓名
   for(j=0;j<3;j++) //将票上姓名与3个候选人的姓名比较
     //如果与某一候选人的姓名相同,就给他加一票
     if(strcmp(leader_name,leader[j].name)==0) leader[j].count++;
  }
  cout<<endl;
  for(i=0;i<3;i++) //输出3个候选人的姓名与最后得票数
  {
   cout<<leader[i].name<<":"<<leader[i].count<<endl;
  }
  return 0;
}

运行情况如下:

Zhang (每次输入一个候选人的姓名)
Li
Fun
Li
Zhang
Li
Zhang
Li
Fun
Wang
Li:4 (输出3个候选人的姓名与最后得票数)
Zhang:3
Fun:2

程序定义一个全局的结构体数组leader,它有3个元素,每一元素包含两个成员,即name(姓名)和count(得票数)。在定义数组时使之初始化,使3位候选人的票数都先置零。

在这个例子中,也可以不用字符数组而用string方法的字符串变量来存放姓名数据,程序可修改如下:

#include <iostream>
#include <string>
using namespace std;
struct Person
{
string name;//成员name为字符串变量
int count;
};
int main( )
{
Person leader[3]={"Li",0,"Zhang",0,"Fun",0};
int i,j;
string leader_name;// leader_name为字符串变量
for(i=0;i<10;i++)
{
cin>>leader_name;
for(j=0;j<3;j++)
if(leader_name==leader[j].name) leader[j].count++//用“==”进行比较
}
cout<<endl;
for(i=0;i<3;i++)
{
cout<<leader[i].name<<":"<<leader[i].count<<endl;
}
return 0;
}

运行情况与前相同。显然后一个程序节省内存空间,使用更方便,易读性更好。但是 有些C++系统不能对包含string成员的结构体变量初始化,需要作一些修改才能运行, 读者可上机试一下。

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

下面通过一个简单例子来说明指向结构体变量的指针变量的应用。

【例】指向结构体变量的指针的应用。

#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,然后再使用它。

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

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

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

可以看到链表中各元素在内存中的存储单元可以是不连续的。要找某一元素,可以先找到上一个元素,根据它提供的下一元素地址找到下一个元素。

可以看到,这种链表的数据结构,必须利用结构体变量和指针才能实现。

可以声明一个结构体类型,包含两种成员,一种是用户需要用的实际数据,另一种是用来存放下一结点地址的指针变量。

例如,可以设计这样一个结构体类型:

struct Student
{
  int num;
  float score;
  Student *next; //next指向Student结构体变量
};

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

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

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

【例】建立一个如图所示的简单链表,它由3个学生数据的结点组成。输出各结点中的数据。

#define NULL 0
#include <iostream>
using namespace std;
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;
}

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

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

建立动态链表,要用到后面介绍的动态分配内存的运算符new和动态撤销内存的运算符delete。

(0)

相关推荐

  • 实例讲解在C++的函数中变量参数及默认参数的使用

    包含变量参数列表的函数 如果函数声明中最后一个成员是省略号 (...),则函数声明可采用数量可变的参数.在这些情况下,C++ 只为显式声明的参数提供类型检查.即使参数的数量和类型是可变的,在需要使函数泛化时也可使用变量参数列表.函数的系列是一个使用变量参数列表的函数的示例.printfargument-declaration-list 包含变量参数的函数 若要访问声明后的参数,请使用包含在标准包含文件 STDARG.H 中的宏(如下所述). 采用数量可变的参数的函数声明至少需要一个占位符参数(即

  • C++编程中变量的声明和定义以及预处理命令解析

    关于C++变量的声明和定义 我们已经知道,一个函数一般由两部分组成:声明部分和执行语句. 声明部分的作用是对有关的标识符(如变量?函数?结构体?共用体等)的属性进行说明.对于函数,声明和定义的区别是明显的,前边已说明,函数的声明是函数的原型,而函数的定义是函数功能的确立.对函数的声明是可以放在声明部分中的,而函数的定义显然不在函数的声明部分范围内,它是一个文件中的独立模块. 对变量而言,声明与定义的关系稍微复杂一些.在声明部分出现的变量有两种情况:一种是需要建立存储空间的(如int a;):另一

  • 深入理解C++中变量的存储类别和属性

    C++变量的存储类别(动态存储.静态存储.自动变量.寄存器变量.外部变量) 动态存储方式与静态存储方式 我们已经了解了变量的作用域.作用域是从空间的角度来分析的,分为全局变量和局部变量. 变量还有另一种属性--存储期(storage duration,也称生命期).存储期是指变量在内存中的存在期间.这是从变量值存在的时间角度来分析的.存储期可以分为静态存储期(static storage duration)和动态存储期(dynamic storage duration).这是由变量的静态存储方式

  • C++静态成员变量和静态成员函数的使用方法总结

    一.静态成员变量: 类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员.和其他数据成员一样,静态数据成员也遵守public/protected/private访问规则.同时,静态数据成员还具有以下特点: 1.静态数据成员的定义. 静态数据成员实际上是类域中的全局变量.所以,静态数据成员的定义(初始化)不应该被放在头文件中. 其定义方式与全局变量相同.举例如下: xxx.h文件 class base{ private: static const int _i;//

  • 简单介绍C++中变量的引用

    什么是变量的引用 对一个数据可以使用"引用(reference)",这是C++对C的一个重要扩充,引用是一种新的变量类型,它的作用是为一个变量起一个别名.假如有一个变量a,想给它起一个别名b,可以这样写: int a; //定义a是整型变量 int &b=a; //声明b是a的引用 以上语句声明了b是a的引用,即b是a的别名.经过这样的声明后,a或b的作用相同,都代表同一变量. 注意: 在上述声明中,&是引用声明符,并不代表地址.不要理解为"把a的值赋给b的地

  • C++中结构体的类型定义和初始化以及变量引用

    C++结构体类型的定义和初始化 有时需要将不同类型的数据组合成一个有机的整体,以供用户方便地使用.这些组合在一个整体中的数据是互相联系的.例如,一个学生的学号.姓名.性别.年龄.成绩.家庭地址等项,都是这个学生的属性,见图 可以看到学号(num).姓名(name).性别(sex).年龄(age).成绩(score ).地址(addr)是与姓名为"Li Fun"的学生有关的.如果在程序中将num,name,sex,age,score,addr分别定义为互相独立的变量,就难以反映出它们之间

  • C++中的局部变量、全局变量、局部静态变量、全局静态变量的区别

    局部变量(Local variables)与 全局变量: 在子程序或代码块中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量. 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序或代码块. 当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用:在其它地方全局变量起作用. 全局变量在程序开始运行期间就已经在内存中开辟了内存空间,直到程序结束才会释放这块内存空间. 全局变量要在其他文件中使用,需显示的声明这个变量,使用extern关键字声明(extern int

  • 深入理解C++编程中的局部变量和全局变量

    局部变量 在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的.同样,在复合语句中定义的变量只在本复合语句范围内有效.这称为局部变量(local variable).如: 对局部变量的一些说明: 1) 主函数main中定义的变量(m, n)也只在主函数中有效,不会因为在主函数中定义而在整个文件或程序中有效.主函数也不能使用其他函数中定义的变量. 2) 不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰.例如,在f

  • 详解C++中变量的初始化规则

    前言 定义没有初始化式的变量时,系统有时候会帮我们初始化变量. 系统如何初始化取决于变量的类型以及变量定义的位置. 内置类型变量是否自动初始化取决于变量定义的位置. 函数体外定义的变量初始成0:函数体内定义的变量不进行自动初始化.除了用作赋值操作的左操作数,其他任何使用未初始化变量的行为都是未定义的,不要依赖未定义行为. 以int类型为例,一段简单的测试代码: #include <iostream> using namespace std; int a; int main() { int b;

  • 深入解读C++中的指针变量

    指针变量是一种特殊的变量,它和以前学过的其他类型的变量的不同之处是:用它来指向另一个变量.为了表示指针变量和它所指向的变量之间的联系,在C++中用"*"符号表示指向,例如,i_pointer是一个指针变量,而*i_pointer表示i_pointer所指向的变量. 下面两个语句作用相同: i=3; *i_pointer=3; 定义指针变量 C++规定所有变量在使用前必须先定义,即指定其类型.在编译时按变量类型分配存储空间.对指针变量必须将它定义为指针类型.先看一个具体例子: int i

随机推荐