结构体类型 在程序设计中,有时需要将不同类型的数据组合成一个有机的整体,以便于引用。例如,学生的信息包括学号、姓名、性别、年龄和成绩。如果用独立的变量:学号(sno)、姓名(name)、性别(sex)、年龄(age)和成绩(score)来表示。如图所示,变量之间是孤立的,很难体现数据之间的内在联系。
使用结构体类型,可以把多个数据项合成一个整体。学生信息可用结构体类型来描述。
结构体类型声明 为描述学生信息,可声明一个结构体类型:
1 2 3 4 5 6 7 8 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; }
结构体类型 struct student ,包括 sno 、name 、 sex 、 age 和 score 共五个成员。struct student 是一个类型说明符,它和 int 、char 、 float 、 double 等一样,都可以用来指定变量的类型,只不过结构体类型 struct student 需要由程序员自行声明一样。
结构体类型声明的一般形式:
1 2 3 4 struct [标记名称]{ 成员列表 };
标记名称是一个标识符,也可以省略标记名称,表示匿名结构体类型。
结构体类型声明既可以放在函数之外,被其作用范围内的所有函数使用;也可以放在某个函数的函数体内,只能在该函数的函数体内使用。
如果 sizeof 运算符的运算对象是结构体类型,运算结果是所有成员占内存大小(按字节计算)再加上内部和尾部填充所占内存大小(按字节计算)的总和。
结构体类型的变量声明
先声明结构体类型再声明变量
1 2 3 4 5 struct 标记名称{ 成员列表 }; struct 标记名称 变量名1 [, 变量名2, 变量名3, …];
例如:
1 2 3 4 5 6 7 8 9 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; }; struct student s ;
struct student 才是类型说明符,以下两种声明变量的方法都是错误的。
1 2 struct s ; //错误student s ; //错误
在声明结构体类型的同时声明变量
1 2 3 4 struct 标记名称{ 成员列表 } 变量名1 [, 变量名2 , 变量名3 , …];
例如:
1 2 3 4 5 6 7 8 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; } s1, s2;
使用匿名结构体类型声明变量
1 2 3 4 struct { 成员列表 } 变量名1 [, 变量名2 , 变量名3 , …];
例如:
1 2 3 4 5 6 7 8 struct { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; } s1, s2;
结构体类型的成员,其类型也可以是结构体类型。例如,结构体类型 struct student 中的成员 age(年龄),由于年龄总是随着时间变化,比较好的方法是用生日代替年龄,生日是一个日期(由年、月、日组成),可以声明一个结构体类型来描述日期:
1 2 3 4 5 6 struct date { int year; int month; int day; };
于是,描述学生信息的结构体类型声明可改为:
1 2 3 4 5 6 7 8 struct student { char sno[8 ]; char name[20 ]; char sex; struct date birthday ; double score[3 ]; };
初始化结构体类型的变量 在结构体类型的变量声明时给变量赋值,称为初始化。例如:
1 2 3 4 5 6 7 8 9 10 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; }; struct student s = {"2015001" , "LiMing" , 'M' , 18 , {85.0 , 92.5 , 95.5 }};
在初始化结构体类型的变量时,大括号内的数据顺序必须与结构体类型中成员的声明顺序一致;否则,就会产生混乱。
如果某个成员的类型是结构体类型,其初始化方式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct date { int year; int month; int day; }; struct student { char sno[8 ]; char name[20 ]; char sex; struct date birthday ; double score[3 ]; }; struct student t = {"2015001" , "LiMing" , 'M' , {1997 , 11 , 18 }, {85.0 , 92.5 , 95.5 }};
引用结构体类型的变量
不能将结构体类型的变量作为一个整体进行输入或输出
1 2 3 4 5 6 7 8 9 10 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; }; struct student s = {"2015001" , "LiMing" , 'M' , 18 , {85.0 , 92.5 , 95.5 }};printf ("%s, %s, %c, %d, %f, %f, %f" , s);
引用结构体类型的变量中的成员要使用成员选择运算符 “ . ”,其一般形式:
例如:
1 2 3 s.age = 20 ; s.age++; sum = s.score[0 ] + s.score[1 ] + s.score[2 ];
如果成员本身又是一个结构体类型的变量,则要用若干成员运算符,一级一级地找到最低一级的成员
除了初始化,在其他位置只能用同类型的变量为结构体类型的变量赋值,或者为其成员赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; } s1, s2; strcpy (s1.sno, "2015001" );strcpy (s1.name, " LiMing" );s1.sex = 'M' ; s1.age = 18 ; s1.score[0 ] = 85.0 ; s1.score[1 ] = 92.5 ; s1.score[2 ] = 95.5 ; s2 = s1;
例题 1 初始化结构体类型的变量,然后输出该变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <stdio.h> int main (void ) { struct student { char sno[9 ]; char name[20 ]; char sex; int age; double score[3 ]; }; struct student s = {"2018001" , "QinHao" , 'M' , 21 , {100 , 95 , 98 }}; int i; printf ("sno: %s\n" , s.sno); printf ("name: %s\n" , s.name); printf ("sno: %c\n" , s.sex); printf ("sno: %d\n" , s.age); printf ("score: " ); for (i = 0 ;i < 3 ;i ++) { printf ("%5.lf" , s.score[i]); } printf ("\n" ); return 0 ; }
运行结果:
1 2 3 4 5 sno: 2018001 name: QinHao sno: M sno: 21 score: 100 95 98
结构体类型 struct student 的声明放在 main 函数的函数体内,只能在 main 函数的函数体内使用 struct student 。
例题 2 输入结构体类型的变量中各成员的值,为结构体类型的变量赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score[3 ]; }; int main (void ) { struct student s1 , s2 ; int i; printf ("Input the student's information: " ); scanf ("%c%s%s%d" , &s1.sex,s1.sno, s1.name, &s1.age); for (i = 0 ;i < 3 ;i ++) { scanf ("%lf" , &s1.score[i]); } s2 = s1; printf ("sno: %s\n" , s2.sno); printf ("name: %s\n" , s2.name); printf ("sex: %c\n" , s2.sex); printf ("age: %d\n" , s2.age); printf ("score: " ); for (i = 0 ;i < 3 ;i ++) { printf ("%6.1lf" , s2.score[i]); } printf ("\n" ); return 0 ; }
运行结果:
1 2 3 4 5 6 Input the student's information: M 2018001 QinHao 21 85.0 92.5 95.5 sno: 2018001 name: QinHao sex: M age: 21 score: 85.0 92.5 95.5
结构体函数 struct student 的声明放在 main 函数之前,struct student 可以被其作用范围内的所有函数使用。通常,将结构体、共同体或枚举类型的声明放在 main 函数之前。
指向结构体类型的指针变量 使用成员间接选择运算符“->”,可以直观、方便地通过指向结构体类型的指针变量访问该结构体类型变量的成员,其一般形式:
例题 3 使用指向结构体类型的指针变量访问该结构体类型变量的成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> #include <string.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; int main (void ) { struct student s ; struct student *p ; strcpy (s.sno, "2018001" ); strcpy (s.name, "QinHao" ); s.sex = 'M' ; s.age = 21 ; s.score = 92.5 ; puts ("s.sno\t\ts.name\t\ts.sex\t\ts.age\t\ts.score" ); printf ("%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n\n" , s.sno, s.name, s.sex, s.age, s.score); p = &s; puts ("(*p).sno\t(*p).name\t(*p).sex\t(*p).age\t(*p).score" ); printf ("%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n\n" , (*p).sno, (*p).name, (*p).sex, (*p).age, (*p).score); puts ("p->sno\t\tp->name\t\tp->sex\t\tp->age\t\tp->score" ); printf ("%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n" , p->sno, p->name, p->sex, p->age, p->score); return 0 ; }
运行结果:
1 2 3 4 5 6 7 8 s.sno s.name s.sex s.age s.score 2018001 QinHao M 21 92.5 (*p).sno (*p).name (*p).sex (*p).age (*p).score 2018001 QinHao M 21 92.5 p->sno p->name p->sex p->age p->score 2018001 QinHao M 21 92.5
编程练习 1 声明结构体类型 struct book,描述图书信息:书名(title)、作者(author)、出版社(press)、价格(price)、数量(amount)。输入一本图书的信息,采用例题 3 的三种方式输出图书的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> #include <string.h> struct book { char title[30 ]; char author[20 ]; char press[30 ]; double price; int amount; }; int main (void ) { struct book b ; struct book *p ; strcpy (b.title, "疯狂Java讲义" ); strcpy (b.author, "李刚" ); strcpy (b.press, "电子工业出版社" ); b.price = 79.0 ; b.amount = 100 ; puts ("b.title\t\t\tb.author\t\tb.press\t\t\tb.price\t\t\tb.amount" ); printf ("%s\t\t%s\t\t\t%s\t\t%.1lf%\t\t\t%d\n\n" , b.title, b.author, b.press, b.price, b.amount); p = &b; puts ("(*p).title\t\t(*p).author\t\t(*p).press\t\t(*p).price\t\t(*p).amount" ); printf ("%s\t\t%s\t\t\t%s\t\t%.1lf\t\t\t%d\n\n" , (*p).title, (*p).author, (*p).press, (*p).price, (*p).amount); puts ("(*p->title\t\t(*p->author\t\t(*p->press\t\t(*p->price\t\t(*p->amount" ); printf ("%s\t\t%s\t\t\t%s\t\t%.1lf\t\t\t%d\n" , p->title, p->author, p->press, p->price, p->amount); return 0 ; }
运行结果:
编程练习 2 声明结构体类型 struct date ,描述日期信息:年(year)、月(month)、日(day)。输入一个日期,计算并输出是这一年的第几天,注意判断是不是闰年。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <stdio.h> struct date { int year; int month; int day; }; int main (void ) { struct date d ; int sum = 0 , i; int leapyear[13 ] = {0 , 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }; int commonyear[13 ] = {0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }; printf ("请输入年:" ); scanf ("%d" , &d.year); printf ("请输入月:" ); scanf ("%d" , &d.month); printf ("请输入日:" ); scanf ("%d" , &d.day); if (d.year % 400 == 0 || (d.year % 4 == 0 && d.year % 100 != 0 )) { for (i = 0 ;i < d.month;i ++) { sum += leapyear[i]; } sum += d.day; } else { for (i = 0 ;i < d.month;i ++) { sum += commonyear[i]; } sum += d.day; } printf ("%d年%d月%d日是%d年的第%d天\n" , d.year, d.month, d.day, d.year, sum); return 0 ; }
运行结果:
1 2 3 4 请输入年:2020 请输入月:12 请输入日:31 2020年12月31日是2020年的第366天
1 2 3 4 请输入年:2021 请输入月:12 请输入日:31 2021年12月31日是2021年的第365天
结构体类型与数组 数组声明
先声明结构体类型再声明数组
1 2 3 4 5 6 7 8 9 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; struct student s [10];
在声明结构体类型的同时声明数组
1 2 3 4 5 6 7 8 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; } s[10 ];
使用匿名结构体类型声明数组
1 2 3 4 5 6 7 8 struct { char sno[8 ]; char name[20 ]; char sex; int age; double score; } s[10 ];
引用数组元素的成员 数组元素的类型是结构体类型,可使用成员选择运算符引用数组元素的成员。
初始化数组 例题 1 初始化数组,输出数组中的每一个数组元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; int main (void ) { struct student s [3] = { {"2018001" , "Zhangsan" , 'M' , 18 , 92.5 }, {"2018002" , "Lisi" , 'F' , 18 , 95.5 }, {"2018003" , "Wangwu" , 'M' , 19 , 85.0 } }; int i; puts (" sno name sex age score" ); for (i = 0 ;i < 3 ;i ++) { printf ("%s%20s%5c%8d%12.1lf\n" , s[i].sno, s[i].name, s[i].sex, s[i].age, s[i].score); } return 0 ; }
运行结果:
例题 2 输入三个学生的信息,输出成绩(score)高于平均成绩的学生信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; int main (void ) { struct student s [3]; int i; double sum = 0 , avg = 0.0 ; puts ("Input three students' information (sex, sno, name, age, score):" ); for (i = 0 ;i < 3 ;i ++) { scanf ("%c%s%s%d%lf" , &s[i].sex, &s[i].sno, &s[i].name, &s[i].age, &s[i].score); getchar(); sum += s[i].score; } avg = sum / 3.0 ; printf ("The average score is %4.1lf\n" , avg); puts (" sno name sex age score" ); for (i = 0 ;i < 3 ;i ++) { if (s[i].score > avg) { printf ("%s%20s%5c%5d%8.1lf\n" , s[i].sno, s[i].name, s[i].sex, s[i].age, s[i].score); } } return 0 ; }
运行结果:
编程练习 声明结构体类型 struct book,描述图书信息:书名(title)、作者(author)、出版社(press)、价格(price)、数量(amount)。输入五本图书的信息,按价格升序的方式对五本图书排序,输出排序后的图书信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <stdio.h> struct book { char title[40 ]; char author[20 ]; char press[40 ]; double price; int amount; }; int main (void ) { int i, j; struct book b [5], temp ; printf ("请输入5本书的资料(书名,作者,出版社,价格,数量):\n" ); for (i = 0 ;i < 5 ;i ++) { scanf ("%s%s%s%lf%d" , &b[i].title, &b[i].author, &b[i].press, &b[i].price, &b[i].amount); } for (i = 0 ;i < 5 ;i ++) { for (j = 0 ;j < 4 - i;j ++) { if (b[j].price > b[j + 1 ].price) { temp = b[j]; b[j] = b[j + 1 ]; b[j + 1 ] = temp; } } } for (i = 0 ;i < 5 ;i ++) { printf ("%s\t\t%s\t\t%s\t\t%.1lf\t\t%d\n" , b[i].title, b[i].author, b[i].press, b[i].price, b[i].amount); } return 0 ; }
运行结果:
结构体类型与函数 形参是结构体类型的变量 例题 1 输入两个学生中成绩(score)较高的学生信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; struct student max (struct student t1, struct student t2) ;int main (void ) { struct student s1 = {"2018001" , "Liming" , 'M' , 18 , 92.5 }; struct student s2 = {"2018002" , "Wangfang" , 'F' , 18 , 95.5 }; struct student s ; s = max(s1, s2); printf ("sno: %s\n" , s.sno); printf ("name: %s\n" , s.name); printf ("sex: %c\n" , s.sex); printf ("age: %d\n" , s.age); printf ("score: %.1lf\n" , s.score); return 0 ; } struct student max (struct student t1, struct student t2) { if (t1.score > t2.score) { return t1; } else { return t2; } }
运行结果:
1 2 3 4 5 sno: 2018002 name: Wangfang sex: F age: 18 score: 95.5
例题 2 修改学生的年龄。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; void change (struct student t) ;int main (void ) { struct student s = {"2015001" , "Liming" , 'M' , 18 , 92.5 }; puts ("\t\t\tsno\t\tname\t\tsex\t\tage\t\tscore" ); printf ("Before modifying\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n" , s.sno, s.name, s.sex, s.age, s.score); change(s); printf ("After modifying\t\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n" , s.sno, s.name, s.sex, s.age, s.score); return 0 ; } void change (struct student t) { t.age ++; }
运行结果
实参向形参的传递是单向的,在被调函数 change 中改变形参 t 的值并不影响实参 s 的值。因此,调用函数 change 后,学生的年龄依旧是 18 岁。
形参是指向结构体类型的指针变量 例题 1 输出两个学生中成绩(score)较高的学生信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; struct student *max (struct student *p1, struct student *p2) ;int main (void ) { struct student s1 = {"2015001" , "LiMing" , 'M' , 18 , 92.5 }; struct student s2 = {"2015002" , "WangFang" , 'F' , 18 , 95.5 }; struct student *q ; q = max(&s1, &s2); printf ("sno: %s\n" , q->sno); printf ("name: %s\n" , q->name); printf ("sex: %c\n" , q->sex); printf ("age: %d\n" , q->age); printf ("score: %.1lf\n" , q->score); return 0 ; } struct student *max (struct student *p1, struct student *p2) { if (p1->score > p2->score) { return p1; } else { return p2; } }
运行结果:
1 2 3 4 5 sno: 2015002 name: WangFang sex: F age: 18 score: 95.5
例题 2 修改学生的年龄。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; void change (struct student *p) ;int main (void ) { struct student s = {"2015001" , "LiMing" , 'M' , 18 , 92.5 }; struct student *q = &s; puts ("\t\t\tsno\t\tname\t\tsex\t\tage\t\tscore" ); printf ("Before modifying\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n" , s.sno, s.name, s.sex, s.age, s.score); change(q); printf ("After modifying\t\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n" , s.sno, s.name, s.sex, s.age, s.score); return 0 ; } void change (struct student *p) { p->age ++; }
运行结果:
形参是数组元素为结构体类型的数组 例题 1 输入三个学生的信息并输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <stdio.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; void input (int n, struct student t[ ]) ;void output (int n, struct student *t) ;int main (void ) { struct student s [3]; input(3 , s); output(3 , s); return 0 ; } void input (int n, struct student t[ ]) { int i; printf ("请输入%d位同学的信息(性别,学号,姓名,年龄,成绩)\n" , n); for (i = 0 ;i < n;i ++) { scanf ("%c%s%s%d%lf" , &t[i].sex, t[i].sno, t[i].name, &t[i].age, &t[i].score); getchar(); } } void output (int n, struct student *t) { int i; puts (" sno name sex age score" ); for (i = 0 ;i < n;i ++) { printf ("%s%20s%5c%5d%8.1lf\n" , t[i].sno, t[i].name, t[i].sex, t[i].age, t[i].score); } }
运行结果:
编程练习 1 声明结构体类型 struct book,描述图书信息:书名(title)、作者(author)、出版社(press)、价格(price)、数量(amount)。已知函数头及功能如下:
1 2 3 void input (int n, struct book t[ ]) ; void sort (int n, struct book t[ ]) ; void output (int n, struct book t[[ ]) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <stdio.h> struct book { char title[30 ]; char author[20 ]; char press[30 ]; double price; int amount; }; void input (int n, struct book t[ ]) ;void sort (int n, struct book t[ ]) ;void output (int n, struct book t[ ]) ;int main (void ) { struct book b [5]; input(5 , b); sort(5 , b); output(5 , b); } void input (int n, struct book t[ ]) { int i; printf ("请输入%d本图书的资料(书名,作者,出版社,价格,数量)\n" , n); for (i = 0 ;i < n;i ++) { scanf ("%s%s%s%lf%d" , t[i].title, t[i].author, t[i].press, &t[i].price, &t[i].amount); getchar(); } } void sort (int n, struct book t[ ]) { int i,j; struct book temp ; for (i = 0 ;i < n;i ++) { for (j = 0 ;j < (n - 1 ) - i;j ++) { if (t[j].price > t[j + 1 ].price) { temp = t[j]; t[j] = t[j + 1 ]; t[j + 1 ] = temp; } } } } void output (int n, struct book t[ ]) { int i; puts ("title\t\tauthor\t\tpress\t\tprice\t\tamount" ); for (i = 0 ;i < n;i ++) { printf ("%s\t\t%s\t\t%s\t\t%.1lf\t\t%d\n" , t[i].title, t[i].author, t[i].press, t[i].price, t[i].amount); } }
运行结果:
编程练习 2 struct mycomplex 是表示复数的结构体类型,成员 real 表示实部,成员 image 表示虚部。已知函数头及功能如下:
1 2 3 4 5 6 7 8 9 struct mycomplex { double real; double image; }; struct mycomplex input (void ) ; struct mycomplex add (struct mycomplex c1, struct mycomplex c2) ; struct mycomplex mul (struct mycomplex c1, struct mycomplex c2) ; void output (struct mycomplex c) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <stdio.h> struct mycomplex { double real; double image; }; struct mycomplex input (void ) ; struct mycomplex add (struct mycomplex c1, struct mycomplex c2) ; struct mycomplex mul (struct mycomplex c1, struct mycomplex c2) ; void output (struct mycomplex c) ; int main (void ) { struct mycomplex c1 , c2 , c3 , c4 ; c1 = input(); c2 = input(); c3 = add(c1, c2); c4 = mul(c1, c2); output(c3); output(c4); } struct mycomplex input (void ) { struct mycomplex c ; printf ("请输入复数的实部和虚部:" ); scanf ("%lf%lf" , &c.real, &c.image); return c; } struct mycomplex add (struct mycomplex c1, struct mycomplex c2) { int i, j; struct mycomplex c ; i = c1.real + c2.real; j = c1.image + c2.image; c.real = i; c.image = j; return c; } struct mycomplex mul (struct mycomplex c1, struct mycomplex c2) { struct mycomplex c ; int i, j; i = c1.real * c2.real - c1.image * c2.image; j = c1.image * c2.real + c1.real * c2.image; c.real = i; c.image = j; return c; } void output (struct mycomplex c) { printf ("%.lf + %.lfi\n" , c.real, c.image); }
运行结果:
1 2 3 4 请输入复数的实部和虚部:1 2 请输入复数的实部和虚部:3 4 4 + 6i -5 + 10i
单链表 单链表的元素称为结点,每个结点包括两个域:存储实际数据的域称为数据域;存储下一个结点地址的域称为指针域。
为了在编程时方便处理,往往在单链表的第一个结点之前附设一个结点,称为头结点
头结点的数据域不存储任何信息,头结点的指针域存储第一个结点的地址
动态存储库函数
库函数 malloc
所需包含的头文件:stdlib.h 。
函数原型:
1 void *malloc (unsigned int size) ;
功能:分配长度为 size 个字节的存储单元,当执行成功时,返回一个指向所分配存储单元起始地址的指针;否则,返回 NULL
库函数 free
所需包含的头文件:stdlib.h 。
函数原型:
功能:释放指针变量 ptr 指向的存储单元
例题 1 调用库函数 malloc 和 free ,分配 、释放存储单元。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <stdio.h> #include <stdlib.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; }; int main (void ) { struct student *p ; puts ("Input the students' information(sex, sno, name, age, score)" ); p = (struct student *)malloc (sizeof (struct student)); scanf ("%c%s%s%d%lf" , &p->sex, p->sno, p->name, &p->age, &p->score); printf ("sno: %s\n" , p->sno); printf ("name: %s\n" , p->name); printf ("sex: %c\n" , p->sex); printf ("age: %d\n" , p->age); printf ("score: %.1lf\n" , p->score); free (p); p = NULL ; return 0 ; }
运行结果:
1 2 3 4 5 6 7 Input the students' information(sex, sno, name, age, score) M 2015001 LiMing 18 92.5 sno: 2015001 name: LiMing sex: M age: 18 score: 92.5
单链表的基本操作 通常用结构体类型的变量来表示单链表中的结点,一个结构体类型的变量包含若干成员,用指针类型的成员存储下一个结点的地址 。
1 2 3 4 5 6 7 8 9 struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; struct student *next ; }
其中,成员 sno 、name 、sex 、age 和 score 一起作为数据域,存储实际数据;成员next 是指向结构体类型 struct student 的指针变量,将成员next 作为指针域,存储下一个节点的地址。
实例 1 建立一个学生信息的单链表,输出单链表中的学生信息,然后销毁单链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include <stdio.h> #include <stdlib.h> struct student { char sno[8 ]; char name[20 ]; char sex; int age; double score; struct student *next ; }; void insert_node (struct student *head, struct student *p) ;void traverse (struct student *head) ;void delete_node (struct student *head) ;int main (void ) { struct student *h , *q ; int i, n; printf ("Input the number of students:" ); scanf ("%d" , &n); getchar(); h = (struct student *)malloc (sizeof (struct student)); h -> next = NULL ; printf ("Input %d students' information(sex, sno, name, age, score):\n" , n); for (i = 0 ;i < n;i ++) { q = (struct student *)malloc (sizeof (struct student)); scanf ("%c%s%s%d%lf" , &q->sex, q->sno, q->name, &q->age, &q->score); getchar(); insert_node(h, q); } traverse(h); while (h->next) { delete_node(h); } free (h); h = NULL ; return 0 ; } void insert_node (struct student *head, struct student *p) { p -> next = head -> next; head -> next = p; } void traverse (struct student *head) { struct student *p ; puts (" sno name sex age score" ); p = head -> next; while (p) { printf ("%s%20s%5c%5d%8.1lf\n" , p->sno, p->name, p->sex, p->age, p->score); p = p -> next; } } void delete_node (struct student *head) { struct student *p ; p = head -> next; head -> next = p -> next; printf ("Deleting the student %s ...\n" , p->sno); free (p); p = NULL ; }
运行结果:
共同体声明 共同体类型声明 共同体声明的一般形式:
共同体类型的变量声明
先声明共同体类型再声明变量
1 2 3 4 5 union 标记名称{ 成员列表 }; union 标记名称 变量名1 [, 变量名2, 变量名3, ...];
例如:
1 2 3 4 5 6 7 union data { char ch; int i; double d; }; union data x ;
在声明共同体类型的同时声明变量
1 2 3 4 union 标记名称{ 成员列表 } 变量名1 [, 变量名2 , 变量名3 , ...];
例如:
1 2 3 4 5 6 union data { char ch; int i; double d; } x1, x2;
使用匿名共同体类型声明变量
1 2 3 4 union { 成员变量 } 变量名1 [, 变量名2 , 变量名3 , ...];
例如:
1 2 3 4 5 6 union { char ch; int i; double d; } x1, x2;
初始化共同体类型的变量 在共同体类型的变量声明时给变量赋值,称为初始化。只能对共同体类型变量的第一个成员赋值,不能像结构体类型的变量那样对所有的成员赋值。例如:
1 2 3 4 5 6 7 8 9 union data { char ch; int i; double d; }; union data x1 , x2 ;union data x1 = {'s' }; union data x2 = {'s' , 100 , 95.5 };
引用共同体类型的变量 引用共同体类型的变量应遵守以下规则:
不能将共同体类型的变量作为一个整体进行输入和输出。
除了初始化,在其他位置只能用同类型的变量为共同体类型的变量赋值,或者为其他成员赋值。
共同体类型的变量中起作用的成员是最后一次赋值的成员,在给一个成员赋值后原有的成员就会失去作用。
例题 建立如表所示的成绩单,输入各科成绩,然后再输出。
课程名
评分方式
分数
等级
C Language Programming
百分制
90
College Chinese
五级分制
excellent
Advanced Mathematics
百分制
88
Introduction to Computers
五级分制
good
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <stdio.h> #include <string.h> union method { int hundred; char five[10 ]; }; struct course { char name[30 ]; char mode; union method grade ; }; int main (void ) { struct course report [4]; int i; strcpy (report[0 ].name, "C Language Programming" ); strcpy (report[1 ].name, "College Chinese" ); strcpy (report[2 ].name, "Advanced Mathematics" ); strcpy (report[3 ].name, "Introduction to Computers" ); for (i = 0 ;i < 4 ;i ++) { printf ("Input the mode(h/f) of course \"%s\": " , report[i].name); scanf ("%c" , &report[i].mode); printf ("Examination Result: " ); if ('h' == report[i].mode) { scanf ("%d" , &report[i].grade.hundred); } else { scanf ("%s" , report[i].grade.five); } getchar(); } puts ("\nname mode grade" ); for (i = 0 ;i < 4 ;i ++) { printf ("%-30s%-16c" , report[i].name, report[i].mode); if ('h' == report[i].mode) { printf ("%d\n" , report[i].grade.hundred); } else { printf ("%s\n" , report[i].grade.five); } } return 0 ; }
运行结果:
枚举类型 所谓”枚举”,就是将变量的可取值一一列举出来,变量只能存、取其中的某个值,存、取其他值是错误的
枚举类型声明 枚举类型声明的一般形式:
1 enum [标记名称] { 枚举常量1 [, 枚举常量2 , 枚举常量3 , ...]};
标记名称是一个标识符,也可以省略标记名称,表示匿名枚举类型
枚举常量是类型为 int 的标识符
枚举类型声明既可以放在函数之外,被其作用范围内的所有函数使用;也可以放在某个函数的函数体内,只能在该函数的函数体内使用
**在枚举类型声明中,枚举常量的值从 0 开始,依次加 1 **
1 enum weekday { sun, mon, tue, wed, thu, fri, sat};
枚举常量
sun
mon
tue
wed
thu
fri
sat
枚举常量的值
0
1
2
3
4
5
6
例题 输出枚举常量的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> enum weekday { sun, mon, tue, wed, thu = 10 , fri, sat};int main (void ) { printf ("sun: %d\n" , sun); printf ("mon: %d\n" , mon); printf ("tue: %d\n" , tue); printf ("wed: %d\n" , wed); printf ("thu: %d\n" , thu); printf ("fri: %d\n" , fri); printf ("sat: %d\n" , sat); return 0 ; }
运行结果:
1 2 3 4 5 6 7 sun: 0 mon: 1 tue: 2 wed: 3 thu: 10 fri: 11 sat: 12
枚举类型的变量声明
先声明枚举类型再声明变量
1 2 enum 标记名称 { 枚举常量1 [, 枚举常量2 , 枚举常量3 , ...]};enum 标记名称 变量名1 [, 变量名2, 变量名3, ...];
在声明枚举类型的同时声明变量
1 enum 标记名称 { 枚举常量1 [, 枚举常量2 , ...]} 变量名1 [, 变量名2 , ...];
使用匿名枚举类型声明变量
1 enum { 枚举变量1 [, 枚举变量2 , ...]} 变量名1 [, 变量名2 , ...];
例题 1 枚举类型的变量。
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> enum weekday { sun, mon, tue, wed, thu, fri, sat};int main (void ) { enum weekday today , tomorrow ; today = mon; tomorrow = (enum weekday)(today + 1 ); printf ("today: %d\n" , today); printf ("tomorrow: %d\n" , tomorrow); return 0 ; }
运行结果:
例题 2 间接输入、输出枚举类型的变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> enum weekday { sun, mon, tue, wed, thu, fri, sat};int main (void ) { enum weekday today , tomorrow ; char *s[ ] = {"sun" , "mon" , "tue" , "wed" , "thu" , "fri" , "sat" }; int day; printf ("What day is today:\n" ); printf ("0--sun,1--mon,2--tue,3--wed,4--thu,5--fri,6--sat: " ); scanf ("%d" , &day); today = (enum weekday)day; if (sat == today) { tomorrow = sun; } else { tomorrow = (enum weekday)(today + 1 ); } printf ("Tomorrow is %s.\n" , s[tomorrow]); return 0 ; }
运行结果:
1 2 3 What day is today: 0--sun,1--mon,2--tue,3--wed,4--thu,5--fri,6--sat: 5 Tomorrow is sat.
编程练习 输入五个学生的信息到数组 s 中,查找并输出平均成绩最高的学生的信息。
1 2 3 4 5 6 7 8 9 struct student { char sno[8 ]; char name[20 ]; enum { male, female} sex; int age; double score[3 ]; }; struct student s [5];
typedef 声明
typedef 声明(typedef declaration)并没有引入新类型,只是为已有类型引入一个同义词
为已有类型引入一个同义词的方法:
1 2 3 4 ①声明变量 ②将变量名换成新类型名 ③在最前面加上typedef ④使用新类型名声明变量