5.4.2 结构指针的初始化
确切知道一个指针的指向是十分必要的,因此,在声明结构指针后,必须有意识地对其进行初始化,除了前面介绍的用取结构变量地址的方法对结构指针初始化外,再介绍两种其他方式的初始化。
1.指针间的相互赋值
指针变量也可以指向一个结构数组,此时结构指针变量的值是整个结构数组的首地址,可以用数组名指针对结构指针赋值,仍以代码5.1中定义的student结构为例加以说明。
student sz[10]; student*p=sz;
上述代码声明了一个大小为10的student型结构数组sz,根据第4章的介绍,sz是数组名指针,代表整个结构数组的首地址,因此,可以用sz对结构指针p赋值。p便指向了结构数组sz,即指向了数组中下标为0的元素,可以用(p).name、(p).age和(p).weight对下标为0的元素进行访问,而p+1指向下标为1的元素,可用((p+1)).name、((p+1)).age和((p+1)).weight进行访问,依次类推,p+9指向下标为9的元素,应当注意的是C++仍旧不会对结构数组下标越界进行检查,*(p+10).name的用法在编译器看来并无不妥,但可能会给程序带来意想不到的错误。
注意
结构指针的算术运算遵循指针运算的一般规则。
2.动态分配内存
下列语句声明了一个指向student型的结构指针p,并用new命令动态申请了一块大小与student型变量相同的内存,将这块内存的首地址赋值给p。
student*p=new student;
这样,便可以通过(p).name、(p).age及(*p).weight对该内存区域进行访问。
可以一次性申请一片连续内存区域(足够容纳几个结构变量),如下所示。
student*p=new student[5];
上述代码动态申请了一片大小为5个student变量的连续内存,并将该内存的首地址赋值给结构指针p,我们可以通过(p).name、(p).age及(*p).weight对第一个student内存进行访问,p+1到p+4分别指向其他4个student型内存区域。
注意
对动态申请的连续内存,C++同样不进行越界检查。在本例中编译器并不会指出“(*(p+5)).name”这样的用法存在错误,但这样做确实存在很大隐患。
根据数组名指针的概念,这里的p实际上是一个大小为5的student数组的数组名,可以通过p[0]~p[4]对其中的各个元素进行访问,见代码5.6。
代码5.6 为结构指针动态分配内存StructAndNew
<———————————-文件名:example506.cpp———————————————-> 01 #include<iostream> 02 int main() 03 { 04 using namespace std; 05 struct student//定义结构student 06 { 07 char name[20]; 08 int age; 09 float weight; 10 }; 11 //使用new申请一块能存放5个student型变量的动态内存,并赋值给结构指针p 12 student*p=new student[5]; 13 cout<<"请依次输入第3名学生的姓名、年龄和体重"<<endl; 14 cin>>((p+2)). name>>((p+2)).age>>(*(p+2)).weight;//第3名学生的姓名、年龄和体重 15 cout<<"姓名:"<<p[2].name<<",年龄:"<<p[2].age<<",体重:"<<p[2].weight<<endl; 16 delete[]p;//释放动态内存p 17 return 0; 18 }
输出结果如下所示。
请依次输入第3名学生的姓名、年龄和体重 Ronaldo 30 75 姓名:Ronaldo,年龄:30,体重:75
【代码解析】代码第12行,就是为结构指针动态分配内存的示例,它是调用new操作符来申请一块能存放5个student型变量的动态内存,并赋值给结构指针p。
从代码5.6可以看出,(*(p+2))与p[2]是等价的。
注意
及时释放动态申请的内存是十分必要的,能有效防止内存泄露。