第九章 使用结构体类型处理组合数据——用户自定义数据类型
定义和使用结构体变量
自己建立结构体类型
允许用户自己建立由不同类型数据组成的组合型的数据结构,称为结构体。
在其他一些高级语言中把这种形式的数据结构称为“记录”。
C语言允许用户在程序中自己建立所需的结构体类型。例如:
声明一个结构体类型的一般形式为:
-
成员可以是另一个结构体变量。例如
-
“结构体”这个词是根据英文单词structure译出的。
定义结构体类型变量
采取以下3种方法定义结构体类型变量:
-
先声明结构体类型,再定义该类型的变量
-
在声明类型的同时定义变量
这种形式的定义一般形式为:
-
不指定类型名而直接定义结构体类型变量
其一般形式为:
说明:
(1)结构体类型与结构体变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对一个类型赋值,存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。
(2)结构体类型中的成员名可以与程序中的变量名相同,但二者不代表同一对象。例如,程序中可以另外定义一个变量num,它与struct student 中的num是两回事,互不干扰。
(3)对结构体变量中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。
结构体变量的初始化和引用
#include<stdio.h>
int main() {
struct student
{
int num;
char name[30];
char sex;
char addr[30];
}student1 = {1,"Li Lin",'M',"123 Beijing Road"};
printf("No.:%d\nname:%s\nsex:%c\naddress:%s\n", student1.num, student1.name, student1.sex, student1.addr);
return 0;
}
引用结构体变量应遵守以下规则:
-
可以引用结构体变量中的成员的值,引用方式为:
-
如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。
-
对结构体变量的成员可以像普通变量一样进行各种运算。
-
同类的结构体变量可以互相赋值,如:
-
可以引用结构体变量成员的地址,也可以引用结构体变量的地址。例如:
结构体数组
一个结构体变量钟可以存放一组有关联的数据。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
struct person
{
char name[20];
int count;
}leader[3] = {"Li",0,"Zhang",0,"Fun",0};
int main() {
char leader_name[20];
for (int i = 0; i < 10; i++)
{
scanf("%s", leader_name);
for (int j = 0; j < 3; j++)
{
if (strcmp(leader_name,leader[j].name)==0)
{
leader[j].count++;
}
}
}
printf("\nResult:\n");
for (int i = 0; i < 3; i++)
{
printf("%5s:%d\n", leader[i].name, leader[i].count);
}
return 0;
}
说明:
-
定义结构体数组一般形式是:
- struct 结构体名
- struct 结构体名
-
也可以先声明一个结构体类型,然后再用此类型定义结构体数组:
结构体指针
所谓结构体指针就是指向结构体数据的指针,一个结构体变量的起始地址就是这个结构体变量的指针。例如:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct student
{
int num;
char name[20];
char sex;
int age;
};
struct student stu[3] = { {1,"Li Lin",'M',18},{2,"Zhang Fun",'M',19},{3,"Wang Min",'F',20} };
int main() {
struct student* p;
printf("No. Name sex age\n");
for (p = stu; p < stu+3; p++)
{
printf("%d %-20s %2c %4d\n", p->num, p->name, p->sex, p->age);
}
return 0;
}
如果p指向一个结构体变量,以下3种形式等价:
- 结构体变量.成员名
- (*p).成员名
- p->成员名
注意:
用结构体变量和结构体变量的指针作函数参数
将一个结构体变量的值传递给另一个函数,有3个方法:
- 用结构体变量的成员作参数。如,用stu[1].num作函数的实参
- 用结构体变量作实参。
- 用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。
用指针处理链表
什么是线性链表
线性链表就是动态地进行存储分配的一种数据结构。
- 链表中的各元素称为结点。
每个结点都应包括两个部分:用户需要用的实际数据和下一个结点的地址。
在一个结点中包含两个部分:
- 数据部分
- 一个指针变量(该指针变量存放下一结点的起始地址)
建立简单的静态链表
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define NULL 0
struct student
{
int num;
float score;
struct student* next;
};
int main() {
struct student a, b, c, * head, * p;
a.num = 1; a.score = 89.5;
b.num = 2; b.score = 90;
c.num = 3; c.score = 85;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
do
{
printf("%1d %5.1f\n", p->num, p->score);
p = p->next;
} while (p != NULL);
return 0;
}
建立动态链表
所谓建立动态链表是在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各节点数据,并建立起前后相连的关系。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct student
{
int num;
float score;
struct student* next;
};
int main() {
struct student* head, * p;
head = p = (struct student * )malloc(sizeof(struct student));
scanf("%d,%f", &p->num, &p->score);
p = (struct student * )malloc(sizeof(struct student));
scanf("%d,%f", &p->num, &p->score);
head->next = p;
p->next = NULL;
p = head;
printf("\n结点1:%d,%6.2f\n", p->num, p->score);
p = p->next;
printf("\n结点2:%d,%6.2f\n", p->num, p->score);
return 0;
}
提高部分
用户除了可以自己建立结构体类型外,还可以建立共同体类型和枚举类型。
共用体类型
将几个不同的变量共占同一段内存的结构,称为共同体类型的结构。
定义共同体类型变量的一般形式为:
枚举类型
如果一个变量只有几种可能的值,则课堂定义为枚举类型。
小结