12.20本周总结
结构和其他数据类型
建立结构声明
结构声明描述了一个结构的组织布局。声明类似如下;
struct book{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
该声明描述了一个由字符数组和一个float类型变量组成的结构。该变量只描述了该对象由什么组成。首先是关键字struct,它表明跟在其后的是一个结构,后面是一个可选的标记,稍后可在程序中使用该标记引用结构。所以,我们在后面的程序中可以这样声明:
struct book library;
这把library声明为一个 使用book结构布局的结构变量。
在结构声明中,用一对花括号括起来的是结构成员列表。每个成员都用自己的声明来描述。例如,title部分是一个内含MAXTITL个元素的char类型数组。成员可以是任意一种C的数据类型,甚至可以是其他 结构! 右花括号后面的分号是声明所必需的,表示结构布局定义结束。
定义结构变量
程序中创建 结构变量的一行是:
struct book 1 ibrary;
编译器执行这行代码便创建了一个结构变量library.编译器使用book模板为该变量分配空间:一 个内含MAXTITL个元素的char数组、一个内含MAXAUTL个元素的char数组和一个float类型的变量。 这些存储空间都与一个名称library结合在一起。
在结构变量的声明中,struct book 所起的作用相当于一般声明中的int或float。例如,可以定义两个struct book 类型的变量,或者甚至是指向struct book 类型结构的指针:
struct book doyle, panshin, * ptbook;
从本质上看,book结构声明创建了一个名为, book的新类型。
就计算机而言,下面的声明:
struct book library;
是以下声明的简化:
struct book {
char title [MAXTITL] ;
char author [AXAUTL] ;
float value;
} library; /* 声明的右右花括号后跟变量名*/
换言之,声明结构的过程和定义结构变量的过程可以组合成一个步骤。 如下所示,组合后的结构商时 和结构变量定义不需要使用结构标记:
struct { /*无结构标记*/
char title [MAXTITL] ;
char author [MAXAUTL] ;
float value;
} library;
然而,如果打算多次使用结构模板,就要使用带标记的形式:或者,使用本章后面介绍的typedef.
初始化结构
struct book library = {
"The Pious Pirate and the Devious Damsel",
"Renee Vivotte" ,
1.95
};
我们在使用一对花括号中括起来的初始化列表进行初始化,各初始化项用逗号分隔。因此,title成员可以被初始化为一个字符串,value成员可以被初始化为一个数字。
访问结构成
结构类似于一个“ 超级数组”, 这个超级数组中,可以是一个元素为char 类型,下一个元素为forat 型,下一个元素为int数组。可以通过数组下标单独访问数组中的各元素,使用结构成员运算符一点( . )访问结构中的成员。例如,library . value即访问library的value 部分。可以像使用任何float类型变量那样使用library.value.与此类似可以像使用字符数组那样 使用library.title。
本质上,.title、 .author和.value 的作用相当于book结构的下标。
注意: &library. float正好符合要求。. 比&的优先级高,因此这个表达式和& (library. float)-样。
结构的初始化器
只初始化book结构的value成员,可以这样做:
struct book surprise = { .value = 10.99};
可以按照任意顺序使用指定初始化器:
struct book gift = { .value = 25.99,
author = "James Broadfool" ,
title = "Rue for the Toad"} ;
与数组类似,在指定初始化器后面的普通初始化器,为指定成员后面的成员提供初始值。另外,对特 定成员的最后一次赋值才是它实际获得的值。例如,考虑下面的代码:
struct book gift = { .value = 18.90,
.author = "James Broadfool" ,
0.25 ;
赋给value的值最后是0.25。
声明结构数组
struct book library [MAXBKS];
以上代码把1bray声明为一个内含MAXBERS个元索的数组。数组的每个元素都是个数组。因此,1ibrary[0]是第1个book类型的结构变量,1ibrary[1]是第2个book类型的结构体 以此类推。数组名library 本身不是结构名,它是一个数组名, 该数组中的每个元素都是struct book类型的结构变量。
标识结构数组的成员
最后,总结一下: 1 ibrary //一个book结构的数组
1 ibrary[2 ]//一个数组元素,该元素是book结构
1 ibrary[2] . title//一个char数组( library[2]的title成员)
library[2] .title[4]//数组中library[2]元素的title成员的一个字符
结构指针
结构指针即指向结构的指针,为什么要使用结构指针,主要有一下三点原因:
①就像指向数组的指针比数组不本身更容易操作(例如在一个排序问题中)一样,指向结构的指针通常比结构本身更容易操作
②在一些早期的C实现中,结构不能作为参数被传递给函数,但指向结构的指针可以
③许多奇妙的数据表示都使用了不包含指向其他结构的指针的结构
介绍一个运算符(“->”),称为“间接成员运算符”
这个运算符与指向结构或联合的指针一起使用,用来指明结构或联合的成员。假设ptstru是一个指向结构的指针,member是由该结构模板指定的一个变量的成员,那么:ptstru ->member 就表示指向的结构的成员
声明和初始化结构指针
声明很简单,例如:
struct student *p
结构指针的初始化
结构指针本质是指针,既然是指针,那么传入的就应该是地址,所以初始化应该如下:
p = &stu //stu以struct student 为模板
向函数传递结构的信息
方法一:用结构体变量作实参
方法二:用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参
接下来分别举例解释这几种方法:我们首先定义一个student结构体如下:
struct student{
int num;
char name[20];
float score[3];
};
用结构体变量的成员作实参
这里写了一段代码来实现结构体的打印的功能,在print函数中传入了整个结构体变量。
#include<stdio.h> struct student{
int num;
char name[20];
float score[3]; };//定义结构体
struct student stu = { .num = 1702,
.name = "Linden",
.score = {99.7,99.2,98.9}
};//结构体变量初始化
void print(struct student);//声明print函数
void main() {
print(stu);//使用整个结构体变量作实参 }//主函数
void print(struct student stu) {
printf("%d\n",stu.num);
printf("%s\n",stu.name);
printf("%.2f\n",stu.score[0]);
printf("%.2f\n",stu.score[1]);
printf("%.2f\n",stu.score[2]); }//print函数,注意
struct student为变量类型,stu为形参
结果:
1702
Linden
99.70
99.20
98.90
联合声明
联合声明成员共享存储空间,而且在联合中同一时间内只能有一个成员。联合的长度取决于它最长成员的长度。
联合(union)外表与结构相似。但在内存布局上存在关键性的区别。在结构中每个成员依次存储,而在联合中,所有的成员都从偏移地址0开始存储。在某一时刻,只有一个成员真正存储于该位置。
类似于结构,联合的声明形式为:
union 结构标签(可选)
{
类型1 标识符1;
类型2 标识符2;
...
}
联合变量被初始化时,初始值必须是联合的第一个成员的类型,且必须位于一对花括号里,例如:
union
{
int a;
float b;
...
}x = {5};
把x.a初始化为5。不能把x初始化为一个浮点值。
enum和typedef
emum
开头不写Mon=1的话,Mon的默认值为0,然后从0开始增长。例如:
enum color {red,blue,green,yellow};
如果这样定义的话,red的值为0,blue的值为1,然后一次增长。
如果从中间开始赋值的话:
enum color {red,blue,green=5,yellow};
那么red到blue是按照默认的从0开始增长的,green就是定义的值5,然后green之后的值都是从5开始增长的。
typedef
1.常规变量类型定义
例如:typedef unsigned char uchar
描述:uchar等价于unsigned char类型定义
uchar c声明等于unsigned char c声明
2.数组类型定义
例如: typedef int array[2];
描述: array等价于 int [2]定义;
array a声明等价于int a[2]声明
扩展: typedef int array[M][N];
描述: array等价于 int [M][N]定义;
array a声明等价于int a[M][N]声明
3.指针类型定义
例如: typedef int *pointer;
描述: pointer等价于 int *定义;
pointer p声明等价于int *a声明
例如: typedef int *pointer[M];
描述: pointer等价于 int *[M]定义;
pointer p声明等价于int *a[M]声明明
4.函数地址说明
描述:C把函数名字当做函数的首地址来对待,我们可以使用最简单的方法得到函数地址
例如: 函数:int func(void);
unsigned long funcAddr=(unsigned long)func;
funcAddr的值是func函数的首地址