大学C语言程序设计
chapter 7 结构体
1. 结构体的认识
结构体概念:可以把各种类型的数据放在一起,形成新的数据类型。
如何定义:关键字 struct
格式:
struct 结构名{
数据类型 变量名1;
数据类型 变量名2;
};
如:定义一个学生,他有姓名,年龄,语文成绩,数学成绩,英语成绩
struct student{
char name[20];
int age;
int score1,score2,score3;
};
访问结构体中的信息,通过 ”.”来访问
student stu; //定义一个结构体变量 stu
strcpy(stu.name,"helloA"); //字符数组的特殊赋值方式
stu.age=13;
stu.score1=88;
stu.score2=99;
stu.score3=100;
printf("%s %d %d %d\n",stu.name,stu.age,stu.score1,stu.score2,stu.score3);//输出
结构体的定义形式
//方式 1
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu1,stu2;
//方式 2
student stu3,stu4;
结构体初始化赋值
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu={"helloB", 14,99,100,100};//初始化赋值
结构体数组
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[N];
或者:student stu[N];
结构体数组初始化赋值
方式一
#include<stdio.h>
#include<string.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[3]={
{"helloA",13,88,99,100},
{"helloB",14,90,99,100},
{"helloC",15,100,100,100}};
int main(){
for(int i=0; i<3; i++){
printf("%s %d %d %d\n",stu[i].name,stu[i].age,stu[i].score1,stu[i].score2,stu[i].score3);
}
return 0;
}
方式二
#include<stdio.h>
#include<string.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
};
struct student stu[3]={{"helloA",13,88,99,100},{"helloB",14,90,99,100},{"helloC",15,100,100,100}};
int main(){
for(int i=0; i<3; i++){
printf("%s %d %d %d\n",stu[i].name,stu[i].age,stu[i].score1,stu[i].score2,stu[i].score3);
}
return 0;
}
2. 结构体信息输入输出
单个结构体信息输入输出
#include<stdio.h>
#include<string.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu;
int main(){
char name[20];
scanf("%s %d%d%d%d", name, &stu.age, &stu.score1,&stu.score2,&stu.score3);
strcpy(stu.name, name);
printf("%s %d %d %d %d\n", stu.name,stu.age,stu.score1,stu.score2,stu.score3);
return 0;
}
多个结构体信息输入输出
#include<stdio.h>
#include<string.h>
#define N 1000
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[N];
int main(){
char name[20];
int n; scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%s %d%d%d%d", name, &stu[i].age, &stu[i].score1,&stu[i].score2,&stu[i].score3);
strcpy(stu[i].name, name);
}
for(int i=0; i<n; i++){
printf("%s %d %d %d %d\n", stu[i].name,stu[i].age,stu[i].score1,stu[i].score2,stu[i].score3);
}
return 0;
}
3. 结构体成员函数
注明:在C++中允许结构体包含函数成员,而标准C不支持。
struct student{
char name[20];
int age;
int score1,score2,score3;
int sum(){
return score1+score2+score3; //求得成绩总和
}
}stu[N];
printf("sum()=%d\n", stu[i].sum()); //使用方法
4. 结构体排序
【题目描述】
有 N (N<1000)个学生,有它的姓名,学号,以及嵌入式C,微积分,思想品德三门学科的成绩,现在想请你来给他们按照一定的规则进行排序。具体排序规则如下:
- 按照总分降序排序
- 如果总分相同,则依次按照嵌入式C,微积分,思想品德三门学科的成绩降序排序
- 如果总分以及嵌入式C,微积分,思想品德三门学科的成绩都相同,则按照学号升序排序。
输入格式:输入 N+1 行,第 1 行表示学生人数;
接下来 N 行,每行数据依次为学生姓名以及嵌入式C,微积分,思想品德三门学科的成绩,该生学号就是输入的第几名学生。
输出格式:输出 N 行,依次为排序后学生的学号,姓名,三门学科总分以及嵌入式C,微积分,思想品德三门学科的成绩
输入样例:
8
stu[1] 100 200 300
stu[2] 101 201 300
stu[3] 101 201 301
stu[4] 100 200 300
stu[5] 100 201 300
stu[6] 100 200 302
stu[7] 100 201 302
stu[8] 101 200 301
输出样例:
3 stu[3] 603 101 201 301
7 stu[7] 603 100 201 302
2 stu[2] 602 101 201 300
8 stu[8] 602 101 200 301
6 stu[6] 602 100 200 302
5 stu[5] 601 100 201 300
1 stu[1] 600 100 200 300
4 stu[4] 600 100 200 300
#include<stdio.h>
#define N 1000
struct student{
char name[20];
int id,score1,score2,score3,sum;//C语言中不支持成员函数的写法,故而定义sum
}stu[N];
void swap(student &a, student &b){
student temp=a; a=b; b=temp;
}
//使用选择排序对结构体按照总分,score1,score2,score3依次进行降序排序,id升序排序
void selectSort(student *arr, int l, int r){
for(int i=l; i<=r; i++){
int max_id=i;
for(int j=i+1; j<=r; j++){
if(arr[max_id].sum!=arr[j].sum){
if(arr[max_id].sum<arr[j].sum) max_id=j;
}else if(arr[max_id].score1!=arr[j].score1){
if(arr[max_id].score1<arr[j].score1) max_id=j;
}else if(arr[max_id].score2!=arr[j].score2){
if(arr[max_id].score2<arr[j].score2) max_id=j;
}else if(arr[max_id].score3!=arr[j].score3){
if(arr[max_id].score3<arr[j].score3) max_id=j;
}else{
if(arr[max_id].id>arr[j].id) max_id=j;
}
}
if(max_id!=i) swap(arr[max_id], arr[i]);
}
}
int main(){
freopen("data.in", "r", stdin);
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%s%d%d%d",&stu[i].name,&stu[i].score1,&stu[i].score2,&stu[i].score3);
stu[i].id=i, stu[i].sum=stu[i].score1+stu[i].score2+stu[i].score3;
}
selectSort(stu, 1, n);
for(int i=1; i<=n; i++){
printf("%d %s %d %d %d %d\n",stu[i].id, stu[i].name, stu[i].sum, stu[i].score1, stu[i].score2, stu[i].score3);
}
return 0;
}
5. 结构体指针
#include<stdio.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[3]={
{"helloA",13,88,99,100},
{"helloB",14,90,99,100},
{"helloC",15,100,100,100}};
int main(){
struct student *pre=stu;//指向首元素的地址,如果是单个变量,可写为:pre=&stu;
printf("%s %d %d %d %d\n\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
pre = &stu[1];
printf("%s %d %d %d %d\n\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
pre = stu+2;
printf("%s %d %d %d %d\n\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
for(struct student *pre=stu; pre<stu+3; pre++){
printf("%s %d %d %d %d\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
}
return 0;
}
6. 链表
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct student{
char name[20];
int age;
struct student *next;//指向结构体的指针变量
};
void main1(){//静态链表
struct student a,b,c, *head, *pre;
strcpy(a.name, "helloA"), a.age=13, a.next=&b;
strcpy(b.name, "helloB"), b.age=14, b.next=&c;
strcpy(c.name, "helloC"), c.age=15, c.next=NULL;
head=&a, pre=head;
do{
printf("%s %d\n", pre->name, pre->age);
pre=pre->next;
}while(pre!=NULL);
}
//动态链表
struct student *create(void){
struct student *head, *pre,*pre2;
head=pre=(struct student*)malloc(sizeof(struct student));
head->next=NULL, pre->next=NULL;
while(scanf("%s %d", &pre->name,&pre->age)==2){
pre2 = (struct student*)malloc(sizeof(struct student));
pre2->next = NULL;
pre->next = pre2;
pre=pre2;
}
return head;
}
int main(){
freopen("data.in", "r", stdin);
struct student *pre=create();
while(pre->next!=NULL){
printf("%s %d\n", pre->name,pre->age);
pre=pre->next;
}
return 0;
}
7. 共用体类型
1、什么是共用体类型
用同一段内存来存放不同类型的变量,后面的数据会覆盖之前的数据,使得不同的数据共享同一段内存的结构被称为共用体。
共用体中的所有成员共用同一段内存(所有成员的起始地址都是一样的)
共用体定义一般形式
union 共用体名{
成员列表;
}变量列表;
注:
(1)成员列表为定义该共用体的成员,成员定义与普通变量的方式一样。
(2)成员列表必须用一对花括号括起。
(3)共用体名可以省略
如:
union Data{ //声明共用体类型
int i;
char ch;
float f;
}a,b,c; //在声明类型的同时定义变量
或者:union Data a,b,c;
由于共用体类型变量的所有成员都共用一段内存,所以共用体类型变量所占的字节数等于该共用体类型中占用字节数最多的成员所占的字节数。
也就是说,对于上述共用体有:sizeof(a) <= sizeof(float);
2、共用体变量的引用
注:
(1)不能整体引用共用体变量,只能引用其成员。引用的格式:共用体变量名.成员名
printf("%d %c %f", a.i, a.ch, a.f); //每一瞬时只能存放一个成员
(2)可以对共用体变量初始化,但是初始化列表只能有一个常量。
union Data a = {1};//正确,对第一个成员初始化
union Data a = {.ch='j'};//正确,C99允许对指定成员初始化
(3)共用体中存放的是最后一次赋值的元素。
(4)共用体变量的地址和它 各个成员的地址都是同一地址。
(5)不能对共用体变量名赋值,C99允许同类型的共用体变量互相赋值。
(6) C99允许共用体变量作为函数参数,(以前只能使用指向共用体变量的指针作函数参数)。
(7)共用体可以出现在结构体类型定义中,也可以定义共用体数组。
反之结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
#include<stdio.h>
#define N 1000
struct {
char name[20];
char job;
union{
int clas;
char position[10];
}category;
}per[N];
int main(){
int n; scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%s %c", &per[i].name,&per[i].job);
if(per[i].job=='s'){
scanf("%d", &per[i].category.clas);//是学生,输入班级
}else if(per[i].job=='t'){
scanf("%s", &per[i].category.position);//是老师,输入职务
}
}
for(int i=0; i<n; i++){
printf("%s %c ", per[i].name, per[i].job);
if(per[i].job=='s'){
printf("%d\n", per[i].category.clas);//是学生,输入班级
}else if(per[i].job=='t'){
printf("%s\n", per[i].category.position);//是老师,输入职务
}
}
return 0;
}
8. 枚举类型
声明枚举类型的一般形式
enum 枚举名 {枚举元素列表};
//枚举类型 WeekDay的声明 ,{}中的为枚举元素或枚举常量
enum WeekDay {Sunday,Monday,Tuesday,Wendnesday,Thursday,Friday,Saturday};
//枚举变量的定义
enum WeekDay workday,weekend; //定义 workday,weekend为枚举变量
//也可以不声明枚举类型,直接定义枚举变量
enum {Sunday,Monday,Tuesday,Wendnesday,Thursday,Friday,Saturday} workday,weekend;
每一个枚举元素都代表一个整数,C语言编译按定义时的顺序默认他们的值为: 0,1,2,3,4,5...
如果有赋值语句:workday=mon; 相当于 workday=1;
但是不能对枚举元素进行赋值,除非是定义时的人为指定,如:
enum WeekDay {Sunday=7,Monday=1,Tuesday,Wendnesday,Thursday,Friday,Saturday};
指定枚举常量后,以后的顺序会依次+1,所以 Saturday=6
由于指定枚举类型变量的值是整数,所以C99把枚举类型也作为整型数据的一种,即用户自定义的整数类型。
9. typedef声明新类型名
C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,来替代系统默认的基本类型名称、数组类型名称、指针类型名称与用户自定义的结构型名称、共用型名称、枚举型名称等。一旦用户在程序中定义了自己的数据类型名称,就可以在该程序中用自己的数据类型名称来定义变量的类型、数组的类型、指针变量的类型与函数的类型等。
例如,C 语言在 C99 之前并未提供布尔类型,但我们可以使用 typedef 关键字来定义一个简单的布尔类型,如下面的代码所示:
// 取别名 bool , 其本质 int
typedef int bool;
// 宏定义,预编译指令
#define true 1
#define false 0
#define
是在预编译时处理的,它只能做简单的字符串替换。
typedef
是在编译阶段处理的,实际上是为特定的类型指定了一个同义字。
typedef
的作用
(1)为基本数据类型定义新的类型名
(2)为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称
(3)为数组定义简洁的类型名称
(4)为指针定义简洁的类型名称
#include<stdio.h>
#include<limits.h>
#define true 1
#define false 0
#define M 100 // 字符串替换,不开辟内存
const int N = 10; // C语言中表示修饰为只读变量 C++中表示常量
typedef int bool;
typedef long long ll;
typedef unsigned long long ull;
typedef struct student{
char name[20];
int age;
}Stu;
Stu stu[20]; // 使用新类型定义结构体
int main(){
bool f1=true, f2=false;
printf("%d %d\n", f1, f2);
ll a = LLONG_MAX, b=LLONG_MAX;
ull c = (ull)a+b;
printf("a = %lld\n", a);
printf("b = %lld\n", b);
printf("c = %llu\n", c);
return 0;
}