(3)结构体类型说明中的“类型名1”~“类型名n”,不仅可以是简单数据类型,也可以是某种结构体类型。当结构体说明中又包含结构体时,称为结构体的嵌套。
(4)ANSI C标准规定结构体至多允许嵌套15层,并且允许内嵌结构体成员的名字与外层成员的名字相同。
考点3. 结构体类型变量的定义
前面只是指定了一个结构体类型,为了能在程序中使用结构体类型的数据,就需要定义结构体类型的变量,并在其中存放具体的数据。可以用如下方法定义结构体类型变量。 (一)先声明结构体类型再定义变量名
如上面已经定义了一个结构体类型struct time,可以如下定义: struct time time1,time2;
结构体类型名 结构体变量名;
time1和time2为struct time类型变量,即它们都具有struct time类型的结构。 (二)在声明类型的同时定义变量 其一般形式为:
struct 结构体名 { 成员表列 } 变量名表列; (三)直接定义结构体类型变量 其一般形式为:
struct { 成员表列 } 变量名表列; 即不出现结构体名。
类型与变量是两个不同的概念,使用时应注意区别。只能对变量赋值、存取或运算,而不能对一个类型进行赋值、存取或运算。可以单独使用结构体中的成员,它与普通变量的作用相同。
考点4. 结构体变量引用
结构体变量的引用
在定义了结构体变量以后,当然可以引用这个变量。但应注意:
(1)结构体变量不能作为一个整体而对其进行任何操作,只能对结构体变量中的各个成员分别进行输入和输出等操作。结构体变量中的成员用以下方式引用: 结构体变量名.成员名
(2)如果结构体的某个成员本身又是一个结构体类型,则可以使用若干个成员运算符“.888,一级一级地找到最低的一级成员,只能对最低一级的成员进行赋值或存取及运算。
(3)结构体变量的初始化,是指逐个对结构体变量的各个成员进行初始化的过程。
考点5. 结构体数组
和普通数组一样,结构体数组中的每个元素都属于同一数据类型(结构体类型),只不过各个元素本身又都包含多个成员项。例如,一个结构体变量中存放着一组数据(如某产品的名称、型号、尺寸、颜色等数据),现在如果有10个这样产品的数据需要参加运算,显然应当用到结构体数组。和定义结构体变量的方法相仿,只需说明其为数组即可。
其一般形式为:
struct 结构体变量名 { 成员表列} 数组名[常量表达式]; 结构体数组的初始化
结构体数组的初始值应顺序地放在一对花括号中,由于数组中的每一个元素都是一个结构体,因此通常将其成员的值依次放在一对花括号中,以便区分各个元素。
考点6. 指向结构体类型数据的指针
一个结构体变量的指针就是用来指向该结构体类型的存储单元,并指向结构体变量所占据的内存段的起始地址。
6.1 指向结构体变量的指针
看下面的例子: #include
struct objects {
char name[20]; int size;
char color[10]; float weight; float height; };
struct objects obj1; struct objects *p; p=&obj1;
strcpy(obj1.name,\ obj1.size=10;
strcpy(obj1.color,\ obj1.weight=50.5; obj1.height=18.5;
printf(\
height: %f\\n\
printf(\}
我们声明了一个struct objects类型,并且定义了一个该揉型的变量obj1,又定义了一个指向struct objects类型的数据的指针p,并且将p指向obj1,接下来是对各成员赋值。第一个printf语句用“.”的方式将obj1的成员的值输出。第二个printf语句用(*p)将obj1的成员的值输出,因为成员运算符“.”的优先级高于“*”运算符,所以(*p)的两侧的圆括号不能省略。以上两个printf函数语句的输出结果是相同的。
我们可用p->name来代替(*p).name,其中“->“称为指向运算符,它由两部分组成:“-”减号和“>”大于号,它们之间不能有空格,所以“结构体变量.成员名”、“(*结构体指针变量名).成员名“和“结构体指针变量名->成员名”这3种形式是等价的。
6.2 指向结构体数组的指针
结构体数组及其元素也可以用指针变量来指向。在使用指针变量指向结构体数组时,只要把该结构体数组中的每个元素当做普通的结构体变量使用就可以了,例如: #include
char name[20]; int size;
char color[10]; float weight; float height; };
struct objects obj[3]= {{\
{\{\
main() {
struct objects *p;
printf(\ for(p=obj;p printf(\} 这样就可以利用指针变量来逐个把结构体数组中的元素的各个域输出。 说明:如果p的初值为obj,即指向第一个元素,则p+1就指向下一个元素。 例如: (++p)->name;先使p自加1,然后得到它指向的元素中的name成员值。而 (p++)->name;先得到p->name的值,然后使p自加1,指向obj[1];。p只能指向一个struct objects类型的数据,不能指向obj数组元素中的某一成员(即p的地址不是成员的地址)。例如,p=&obj[1].name;是不对的。对结构体变量中的每个成员,都可以像普通变量一样,对它进行同类变量所允许的任何操作。 6.3 用结构体变量和指向结构体的指针作为函数参数 将一个结构体变量的值传递给另一个函数,有如下方法: (1)结构体变量的成员作为实参传递给主调函数。 (2)可以用结构体变量作为一个整体实参。 (3)C语言中,允许将结构体变量的地址作为实参传递,这时,对应的形参应该是一个基类型相同的结构体类型的指针。 考点7. 链表 7.1 链表的概念 链表是一种常见的重要的数据结构,它是动态地进行存储单元分配的一种结构。 链表中的各元素在内存中不一定是连续存放的。要找链表中某一元素,必须先找到上一个元素,根据该元素提供的下一元素的地址才能找到下一个元素。所以,如果没有头指针(head),则整个链表都无法访问。另外一点,这种链表的数据结构,必须利用指针变量才能实现。即一个节点中应包含一个指针变量,用它存放下一节点的地址。当然也可以不通过指针变量,用其他方式也可以构建简单链表,请参考有关数据结构的教材。 下面通过一个例子来说明如何建立和输出一个简单链表。 #include int data; struct node *next; }; typedef struct node NODETYPE; main() { NODETYPE s1,s2,s3,*begin,*p; s1.data=100;/*给变量中的data域赋值*/ s2.data=200; s3.data=300; begin=&s1; s1.next=&s2;/*使s1的域next指向s2*/ s2.next=&s3; s3.next='\\0'; p=begin;/*移动p,使之依次指向s1、s2、s3,输出它们data域中的值*/ while(p) { printf(\ p=p->next; /* p顺序后移 */ } printf(\} main()函数中定义的变量s1、s2、s3都是结构体变量,它们都含有data和next两个成员。变量begin和p是指向NODETYPE结构体类型的指针变量,它们与结构体变量s1、s2、s3中的成员变量next类型相同。执行赋值语句后,begin中存放s1变量的地址,变量s1的成员s1??next中存放变量s2的地址……最后一个变量s3的成员s3??next置成'\\0'(NULL),从而把同一类型的结构体变量s1、s2、s3“链接”到一起,形成“链表”。 在此例中,链接到一起的每个节点(结构体变量s1、s2、s3)都是通过定义,由系统在内存中开辟了固定的存储单元(不一定连续)。在程序执行的过程中,不可能人为地再产生新的存储单元,也不可能人为地使已开辟的存储单元消失。从这一角度出发,可称这种链表为“静态链表“。在实际中,使用更广泛的是一种“动态链表”。 7.2 . 建立动态链表(主要针对单向链表) 建立单向链表的主要步骤如下: (1)读取数据。 (2)生成新节点。 (3)将数据存入节点的成员变量中。 (4)将新节点插入到链表中,重复上述操作直至输入结束。 编写函数creatlist(),建立带有头节点的单向链表。节点数据域中的数值从键盘输入,以-1作为输入结束标志。链表的头节点的地址由函数值返回。 我们在函数中定义了一个名为begin的指针变量,用于存放头节点的地址,另外还定义了两个工作指针:current和end。其中指针current用来指向新生成的节点,指针end总是指向链表当前的尾节点。每当把current所指的新开辟的节点连接到表尾后,end便移向这一新的表尾节点。这时又可以用current去指向下一个新开辟的节点。链表最后一个节点的指针域中置'\\0'(NULL值)作为单向链表的结束标志。 链表建成后,头节点的地址由creatlist()返回,赋给main()函数中的指针变量head。函数如下: #include int data; struct node *next; }; typedef struct node NODETYPE; NODETYPE *creatlist() { int i; NODETYPE *begin,*end,*current; begin=(NODETYPE *)malloc(sizeof(NODETYPE));/*生成头节点*/ end=begin; scanf(\输入数据*/ while(i!=-1)/*未读到数据结束标志时进入循环*/ { current=(NODETYPE *)malloc(sizeof(NODETYPE));/*生成一个新节点*/