C程序设计 谭浩强 第九章
结构体
注:结构体类型的名字是由一个关键字struct和结构体名组合而成的(例如struct Student)。结构体名是由用户指定的,又称“结构体标记”,以区别于其他结构体类型。上面的结构体声明中Student就是结构体名(结构体标记)
说明
struct 结构体名
{成员列表}
类型名 成员名;
“成员列表”也称为“域表”
struct Student
{int num;char name[20];char sex;int age;float score;
}
注:
- 如果成员本身又属于一个结构体类型,则要用若干成员运算符,一级一级找到最低级的成员。只能对最低级的成员进行赋值或存取以及运算。
- 同类的结构体变量可以相互赋值
student1 = student2
- 可以引用结构体变量成员的地址,也可以引用结构体变量的地址
scanf("%d",&student1.num);
printf("%o",&student1);
声明和定义结构体类型变量
1. 声明和定义分开
声明结构体类型
sturct Student student1,student2;
定义结构体
student1.num = 10001;
student1.name = "zhangxin"; //此处如此赋值是不正确的,请自行百度如何正确赋值char数组。
student1.sex = "M";
student1.age = 19;
student1.score = 90.5; student2.num = 10002;
student2.name = "wangli"; //此处如此赋值是不正确的,请自行百度如何正确赋值char数组。
student2.sex = "F";
student2.age = 20;
student2.score = 98;
2. 声明和定义同时进行
struct Student
{int num;char name[20];char sex;int age;float score;
}student1,student2;
注:该定义方法的一般形式为
struct 结构体名
{成员列表
}变量名列表;
3. 不指定类型名而直接定义
struct
{成员表列
}变量名表列;
说明:
- 只能对结构体变量赋值而不能对结构体类型赋值。在编译时,结构体类是不分配空间的,只对变量分配空间。
- 结构体类型中的成员可以与程序中的变量名相同,但二者不代表同一对象。例如,程序中可以另定义一个变量num,它与struct Student中的num是两回事,相互不干扰。
结构体变量的初始化和引用
【例9.1】把一个学生的信息(包括学号、姓名、性别)放到同一个结构体变量中,并输出这个学生的信息
#include<stdio.h>
int main()
{struct Student{int num;char name[20];char sex;int age;// float score;}a={10101,"Li Lin",'M'};printf("学号:%d,姓名:%d,性别:%d。\n",a.num,a.name,a.sex,a.age);return 0;
}
定义结构体数组
- sturct 结构体名
{成员列表} 数组名【数组长度】;struct Person {char name[20];int count; }leader[3];
- 结构体类型 数组名【数组长度】;
struct Person leader[3];
定义结构体数组
【例9.3】有三个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先输入被选人的名字,最后输出各人得票结果。
#include<string.h>
#include<stdio.h>
struct Person()
{char name[30];int count;
}leader[3]={"Li",0,"zhang",0,"sun",0};int main()
{int i,j;char leader_name[20];for(i=1;i<=10;i++){scanf("%s",leader_name);for(j=0;j<3;j++){if(strcmp(leader_name,leader[j].name==0))leader[j].count++;}}printf("\nResult:\n");for(i=0;i<3;i++)printf("%5s:%d\n",leader[i].name,leader[i].count);return 0;
}
指向结构体变量的指针
struct Student *pt
【例9.5】通过指向结构体变量的指针变量输出结构体变量中的成员信息
#include<stdio.h>
#include<string.h>
int main()
{struct Student{long num;char name[20];char sex;float score;};struct Student stu_1;return 0;
}
注:以下三种等价
- stu成员名(如stu.num)
- (*p).成员名(如( *p).num)
- p->成员名(如p->num)
指向结构体的指针
【例9.6】有3个学生的信息,放在结构体数组中,要求输出全部学生的信息
#include<stdio.h>
struct Student
{int num;char name[20];char sex;int age;
};
struct Student stu[3]={{10101,"Li",'M',18},
{10102,"zhangfang",'M',19},{10104,"wangmin",'F',20}};
int main()
{struct Student *p;printf("No. Name sex age\n");for(p=stu;p<stu+3;p++>){printf("%5d %-20s %2c %4d\n",p->num,p->name,p->sex,p->age);}return 0;
}
注:
- 如果p的初值为stu,即指向stu的序号为0的元素,p加1后,p就指向下一个元素。例如:
(++p)->num //先使p自加1,然后得到p指向的元素中num成员值(即10102)
(p++)->num//先求得p->num的值(即10101),然后再使得p自加1,指向stu[] - p指针用来指向一个struct Student类型对象,不应用指向stu数组元素中的某一成员。
p = stu[1].name;//不合法,stu[1].name是stu[1]元素中成员name首字符的地址。编译时将会给出“警告”信息,表示地址的类型不匹配。
- 如果将某一个成员地址赋值给p,例如
p = (struct Student*) stu[0].name;
此时,p的值是stu[0].name成员的起始地址。但是p仍然保留原来的类型。如果执行printf("%s",p+1);,则会输出stu[1]中name的值。执行p++时,p的值的增量是结构体struct Student的长度。
用结构体变量和结构体变量的指针做函数参数
struct Student
{int num;char name[20];float score[3];float aver;
}
1. 结构体变量做函数参数
void input(struct Student stu);
2. 结构体变量的指针/数组做函数参数
void input(struct Student stu[]);
指针处理链表
注:C程序设计 谭浩强版此处有9.4节“用指针处理链表”本人将其归类到了第八章指针中
共用体
格式:
union 共用体名
{成员表列}变量表列;
例如
union Data
{int i;char ch;float f;
}a,b,c;
注:结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。而共用体变量所占的内存长度等于最长成员的长度。
引用共用体变量
a.i
a.ch
a.f
特点
-
同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一个成员,而不是同时存放几个。
union Date {int i;char ch;float f; }a; a.i = 97; printf("%d",a.i); //输出97 printf("%c",a.ch); //输出a printf("%f",a.f); //输出实数0.00000
注:整型无法用浮点型的格式输出,故
printf("%f",a.f);
输出为0 -
对共用体量化,但是初始化表只能有一个常量
union Date{int i;char ch;float f;}a = {1,‘a’,1.5}; //此处错误
-
共用体变量中起作用的成员是最后一次被赋值的成员,在对共用体变量中的一个成员赋值后,原有的变量存储单元中的值就被取代了。
-
共用体变量的地址和它的成员的地址是相同的。
-
不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。
a = 1; m = a;
-
C99之前不允许共用体变量作为函数参数,只能通过指针的形式做函数参数,C99之后允许了。
注:共用体类型一般用在两个组数据的成员大部分相同的情况之下。例如,有学生和老师两组数据,学生的成员包括:姓名、号码、性别、职业、班级。教师的成员包括:姓名、号码、性别、职业、职务。这两组数据只有班级和职务不同,因此可以定义成如下的共用体:
struct
{char name[20];char sex;char job;union{int class;char position[10];}category;
}person[2];
枚举类型
注:枚举类型放在了第3章“顺序程序设计”
typedef声明新类型名
注:typedef声明新类型名放在了第3章“顺序程序设计”
习题
1.定义一个结构体变量(包括年、月、日)。计算该日在本年中是第几天,注意闰年问题。
代码思路:
闰年:
①:可以被4整除但是不能被100整除
②:可以被400整除
#include <stdio.h>int main() {int year, month, day, d;int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};printf("请输入年、月和日:");fflush(stdout);scanf("%d %d %d", &year, &month, &day);d = 0;for (int i = 1; i < month; ++i) {d += months[i];}d += day;int flag = (year%4 == 0 && year%100 != 0) || (year%400 == 0);if(flag && month>= 3) {d++;}printf("这是%d年的第%d天\n", year, d);return 0;
}
2.写一个函数days,实现第1 题的计算。由主函数将年、月、日传递给days函数,计算后将日子数传回主函数输出。
#include <stdio.h>int main() {int days(int, int, int);int year, month, day;printf("请输入年、月和日:");fflush(stdout);scanf("%d %d %d", &year, &month, &day);printf("这是%d年的第%d天\n", year, days(year, month, day));return 0;
}int days(int year, int month, int day) {int d;int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};d = 0;for (int i = 1; i < month; ++i) {d += months[i];}d += day;int flag = (year%4 == 0 && year%100 != 0) || (year%400 == 0);if(flag && month>= 3) {d++;}return d;
}
3.编写一个函数print,打印一个学生的成绩数组,该数组中有5个学生的数据记录,每个记录包括num,name,score[3],用主函数输人这些记录,用print函数输出这些记录。
#include <stdio.h>typedef struct Student {int num;char name[30];float score[3];
}Student;int main() {void print(Student *stu);Student stu[5];printf("请输入5组学生的数据\n");fflush(stdout);for (int i = 0; i < 5; ++i) {printf("请输入编号:");fflush(stdout);scanf("%d", &stu[i].num);printf("请输入名字:");fflush(stdout);scanf("%s", stu[i].name);printf("请输入分数:");fflush(stdout);for (int j = 0; j < 3; ++j) {scanf("%f", &stu[i].score[j]);}fflush(stdin);}print(&stu);return 0;
}void print(Student *stu) {for (int i = 0; i < 5; ++i) {printf("编号:%d,姓名:%s,分数1:%f,分数2:%f,分数3:%f\n", (stu+i)->num, (stu+i)->name, (stu+i)->score[0], (stu+i)->score[1], (stu+i)->score[2]);}
}
4.在第3题的基础上,编写一个函数input,用来输人5个学生的数据记录。
#include <stdio.h>typedef struct Student {int num;char name[30];float score[3];
}Student;int main() {void print(Student *stu);void input(Student *stu);Student stu[5];input(&stu);print(&stu);return 0;
}void input(Student *stu) {printf("请输入5组学生的数据\n");fflush(stdout);for (int i = 0; i < 5; ++i) {printf("请输入编号:");fflush(stdout);scanf("%d", &stu[i].num);printf("请输入名字:");fflush(stdout);scanf("%s", stu[i].name);printf("请输入分数:");fflush(stdout);for (int j = 0; j < 3; ++j) {scanf("%f", &stu[i].score[j]);}fflush(stdin);}
}void print(Student *stu) {for (int i = 0; i < 5; ++i) {printf("编号:%d,姓名:%s,分数1:%f,分数2:%f,分数3:%f\n", (stu+i)->num, (stu+i)->name, (stu+i)->score[0], (stu+i)->score[1], (stu+i)->score[2]);}
}
5.有10个学生,每个学生的数据包括学号、姓名、3门课程的成绩,从键盘输人10个学生数据,要求输出3门课程总平均成绩,以及最高分的学生的数据(包括学号、姓名、3门课程成绩、平均分数)。
6.13个人围成一圈,从第1个人开始顺序报号1,2,3。凡报到3者退出圈子。找出最后留在圈子中的人原来的序号。要求用链表实现。
7.在第9章例9.9和例9.10的基础上,写一个函数del,用来删除动态链表中指定的节点
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
}Student, *SPoint;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。SPoint createStuList(SPoint stu, int n);void printStuList(SPoint stu);int deleteStu(SPoint sp, int num);SPoint stu;int n;printf("请输入需要创建的学生数量 n = 3\n");fflush(stdout);stu = createStuList(stu, n);
// printStuList(stu);int num;printf("请输入想要删除的编号:");fflush(stdout);scanf("%d", &num);int result = deleteStu(stu, num);if (result == 1) printf("删除成功\n");else printf("未找到相关的编号\n");printf("=====================\n");printStuList(stu);return 0;
}SPoint createStuList(SPoint stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < 3; ++i) {Student *s = (Student *) malloc(sizeof(Student));s->num = i + 1;printf("请输入编号:%d,", s->num);fflush(stdout);s->score = 90 - 10 * i;printf("请输入分数:%f\n", s->score);fflush(stdout);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(SPoint stu) {SPoint p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}int deleteStu(SPoint sp, int num) {//找到并删除成功返回1,未找到返回0;Student *p, *pre;p = sp->next;pre = sp;while (p) {if(p->num == num) {pre->next = p->next;free(p);return 1;}p = p->next;pre = pre->next;}return 0;
}
8.写一个函数insert,用来向一个动态链表插入结点
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *SPoint;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。SPoint createStuList(SPoint stu, int n);void printStuList(SPoint stu);int deleteStu(SPoint sp, int num);void insertStu(SPoint sp, Student *s);SPoint stu;int n;printf("请输入需要创建的学生数量 n = 3\n");fflush(stdout);stu = createStuList(stu, n);printf("=====================\n");Student newStu;printf("请输入一个新的num: ");fflush(stdout);scanf("%d", &newStu.num);printf("请输入学生的分数:");fflush(stdout);scanf("%f", &newStu.score);insertStu(stu, &newStu);printStuList(stu);return 0;
}SPoint createStuList(SPoint stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < 3; ++i) {Student *s = (Student *) malloc(sizeof(Student));s->num = i + 1;printf("请输入编号:%d,", s->num);fflush(stdout);s->score = 90 - 10 * i;printf("请输入分数:%f\n", s->score);fflush(stdout);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(SPoint stu) {SPoint p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}int deleteStu(SPoint sp, int num) {//找到并删除成功返回1,未找到返回0;Student *p, *pre;p = sp->next;pre = sp;while (p) {if (p->num == num) {pre->next = p->next;free(p);return 1;}p = p->next;pre = pre->next;}return 0;
}void insertStu(SPoint sp, Student *s) {Student *pre, *p;pre = sp;p = sp->next;while (p != NULL && s->num >= p->num) {p = p->next;pre = pre->next;}s->next = p;pre->next = s;
}
9.综合本章例9.9(建立链表的函数creat)、例9.10(输出链表的函数print)和本章习题第7题(删除链表中结点的函数del)、第8题(插入结点的函数insert),再编写一个主函数,先后调用这些函数。用以上5个函数组成一个程序,实现链表的建立、输出、删除和插入,在主函数中指定需要删除和插人的结点的数据。
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *SPoint;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。SPoint createStuList(SPoint stu, int n);void printStuList(SPoint stu);int deleteStu(SPoint sp, int num);void insertStu(SPoint sp, Student *s);SPoint stu;int n;printf("请输入需要创建的学生数量 n = 3\n");fflush(stdout);stu = createStuList(stu, n);printf("=====================\n");Student newStu;printf("请输入一个新的num: ");fflush(stdout);scanf("%d", &newStu.num);printf("请输入学生的分数:");fflush(stdout);scanf("%f", &newStu.score);insertStu(stu, &newStu);printStuList(stu);return 0;
}SPoint createStuList(SPoint stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < 3; ++i) {Student *s = (Student *) malloc(sizeof(Student));s->num = i + 1;printf("请输入编号:%d,", s->num);fflush(stdout);s->score = 90 - 10 * i;printf("请输入分数:%f\n", s->score);fflush(stdout);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(SPoint stu) {SPoint p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}int deleteStu(SPoint sp, int num) {//找到并删除成功返回1,未找到返回0;Student *p, *pre;p = sp->next;pre = sp;while (p) {if (p->num == num) {pre->next = p->next;free(p);return 1;}p = p->next;pre = pre->next;}return 0;
}void insertStu(SPoint sp, Student *s) {Student *pre, *p;pre = sp;p = sp->next;while (p != NULL && s->num >= p->num) {p = p->next;pre = pre->next;}s->next = p;pre->next = s;
}
10.已有a,b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并, 按学号升序排列。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *StudentList;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。StudentList createStuList(StudentList stu, int n);void printStuList(StudentList stu);void mergeList(StudentList Sa, StudentList Sb);void sortList(StudentList S);StudentList Sa, Sb;int na, nb;printf("请输入需要创建的学生数量 na和nb: ");fflush(stdout);scanf("%d,%d", &na, &nb);fflush(stdin);Sa = createStuList(Sa, na);Sb = createStuList(Sb, nb);printStuList(Sa);printf("*****************\n");printStuList(Sb);printf("=====================\n");// 对每个链表排序sortList(Sa);sortList(Sb);printStuList(Sa);printf("*****************\n");printStuList(Sb);printf("=====================\n");mergeList(Sa, Sb);printStuList(Sa);return 0;
}StudentList createStuList(StudentList stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;unsigned int second = time(NULL);srand(second);// 延迟函数while (1) {unsigned int nextSecond = time(NULL);if(second + 2 >= nextSecond) break;}for (int i = 0; i < n; ++i) {Student *s = (Student *) malloc(sizeof(Student));printf("请输入编号:");fflush(stdout);scanf("%d", &s->num);printf("请输入分数:");fflush(stdout);scanf("%f", &s->score);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(StudentList stu) {StudentList p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}void mergeList(StudentList Sa, StudentList Sb) {Student *head, *ph, *pa, *pb;head = Sa;ph = Sa;pa = Sa->next;pb = Sb->next;while (pa && pb) {if(pa->num <= pb->num) {ph->next = pa;ph = pa;pa = pa->next;}else {ph->next = pb;ph = pb;pb = pb->next;}}if (pa) {ph->next = pa;}if (pb) {ph->next = pb;}
}void sortList(StudentList S) {int compare(const void*, const void*);int size = 0;Student *hp, *sp;hp = S->next;while (hp) {hp = hp->next;size++;}hp = S->next;sp = (Student*) malloc(sizeof(Student)*size);for (int i = 0; i < size; ++i) {*(sp + i) = *hp;hp = hp->next;}hp = S->next;qsort(sp, size, sizeof(Student), compare);for (int i = 0; i < size; ++i) {*hp = *(sp +i);hp = hp->next;}
}int compare(const void *a, const void *b) {Student sa = *(Student*)a;Student sb = *(Student*)b;return (sa.num - sb.num);
}
11.有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同学号的那些结点。
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *StudentList;int StudentSize(StudentList S); // 求列表的元素int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。StudentList createStuList(StudentList stu, int n);void printStuList(StudentList stu);void sortList(StudentList S);void deleteSameElem(StudentList Sa, StudentList Sb);StudentList Sa, Sb;int na, nb;printf("请输入需要创建的学生数量 na和nb: ");fflush(stdout);scanf("%d,%d", &na, &nb);fflush(stdin);Sa = createStuList(Sa, na);Sb = createStuList(Sb, nb);deleteSameElem(Sa,Sb);printStuList(Sa);return 0;
}StudentList createStuList(StudentList stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < n; ++i) {Student *s = (Student *) malloc(sizeof(Student));printf("请输入编号:");fflush(stdout);scanf("%d", &s->num);printf("请输入分数:");fflush(stdout);scanf("%f", &s->score);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(StudentList stu) {StudentList p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}void sortList(StudentList S) {int compare(const void*, const void*);int size = StudentSize(S); //链表长度Student *hp, *sp;hp = S->next;sp = (Student *) malloc(sizeof(Student)*size); //sp指向链表S的数组形式for (int i = 0; i < size; ++i) {*(sp + i) = *hp;hp = hp->next;}hp = S->next;qsort(sp, size, sizeof(Student), compare);for (int i = 0; i < size; ++i) {hp->num = (sp +i)->num;hp->score = (sp +i)->score;hp = hp->next;}
}int compare(const void *a, const void *b) {Student sa = *(Student*)a;Student sb = *(Student*)b;return (sa.num - sb.num);
}void deleteSameElem(StudentList Sa, StudentList Sb) {
// 两个链表必须是排序过的int sizeA, sizeB, indexA;Student *pa, *pb, *pre;pa = Sa->next;pb = Sb->next;sizeA = StudentSize(Sa);sizeB = StudentSize(Sb);Student *arrA = (Student*) malloc(sizeof(sizeA));Student *arrB = (Student*) malloc(sizeof(sizeB));for (int i = 0; i < sizeB; ++i) {*(arrB + i) = *pb;pb = pb->next;}// 删除B链表中num相同的结构pre = Sa;pa = Sa->next;while (pa) {for (int i = 0; i < sizeB; ++i) {if(pa->num == (arrB+i)->num) {pre->next = pa->next;pa = pa->next;}else {pre = pre->next;pa = pa->next;}}}
}int StudentSize(StudentList S) {int size = 0;Student *p = S->next;while (p) {p = p->next;size++;}return size;
}
12.建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去。
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int no;char name[30];char sex; //年龄男性为M,女性为Wint age;struct Student *next;
} Student, *StudentList;// 求列表的元素
int StudentSize(StudentList S) {int size = 0;Student *p = S->next;while (p) {p = p->next;size++;}return size;
}int main() {
// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。StudentList createStudentList(StudentList stuHead, int n);
// 如果年龄相同,则把这个元素在链表中删除void deleteStudent(StudentList stuHead, int age);
// 打印链表void printStudentList(StudentList stu);int n, age;Student *stuHead;// 创建一组链表printf("请输入个数,这个数将用来创建一组链表。\n");printf("n = ");fflush(stdout);scanf("%d", &n);stuHead = createStudentList(stuHead, n);// 如果链表中有值和输入的年龄相同则把链表中删除的元素删去。printf("请输入一个年龄\n");printf("age = ");fflush(stdout);scanf("%d", &age);deleteStudent(stuHead, age);printStudentList(stuHead);return 0;
}StudentList createStudentList(StudentList stuHead, int n) {Student *r;stuHead = (Student *) malloc(sizeof(Student));stuHead->next = NULL; // 记得跟上NULLr = stuHead;for (int i = 0; i < n; ++i) {Student *s = (Student *) malloc(sizeof(Student));printf("请输入学号:");fflush(stdout);scanf("%d", &s->no);printf("请输入姓名:");fflush(stdout);scanf("%s", s->name);fflush(stdin);printf("请输入性别:");fflush(stdout);scanf("%c", &s->sex);printf("请输入年龄:");fflush(stdout);scanf("%d", &s->age);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stuHead;
}void deleteStudent(StudentList stuHead, int age) {Student *sp, *pre, *m;pre = stuHead;sp = stuHead->next;while (sp) {if(sp->age == age) {pre->next = sp->next;m = sp;sp = sp->next;free(m);}else {pre = pre->next;sp = sp->next;}}
}void printStudentList(StudentList stuHead) {StudentList p;p = stuHead->next;while (p) {printf("学号:%d,姓名:%s,性别:%c,年龄:%d\n", p->no, p->name, p->sex, p->age);p = p->next;}
}
C程序设计 谭浩强 第九章
结构体
注:结构体类型的名字是由一个关键字struct和结构体名组合而成的(例如struct Student)。结构体名是由用户指定的,又称“结构体标记”,以区别于其他结构体类型。上面的结构体声明中Student就是结构体名(结构体标记)
说明
struct 结构体名
{成员列表}
类型名 成员名;
“成员列表”也称为“域表”
struct Student
{int num;char name[20];char sex;int age;float score;
}
注:
- 如果成员本身又属于一个结构体类型,则要用若干成员运算符,一级一级找到最低级的成员。只能对最低级的成员进行赋值或存取以及运算。
- 同类的结构体变量可以相互赋值
student1 = student2
- 可以引用结构体变量成员的地址,也可以引用结构体变量的地址
scanf("%d",&student1.num);
printf("%o",&student1);
声明和定义结构体类型变量
1. 声明和定义分开
声明结构体类型
sturct Student student1,student2;
定义结构体
student1.num = 10001;
student1.name = "zhangxin"; //此处如此赋值是不正确的,请自行百度如何正确赋值char数组。
student1.sex = "M";
student1.age = 19;
student1.score = 90.5; student2.num = 10002;
student2.name = "wangli"; //此处如此赋值是不正确的,请自行百度如何正确赋值char数组。
student2.sex = "F";
student2.age = 20;
student2.score = 98;
2. 声明和定义同时进行
struct Student
{int num;char name[20];char sex;int age;float score;
}student1,student2;
注:该定义方法的一般形式为
struct 结构体名
{成员列表
}变量名列表;
3. 不指定类型名而直接定义
struct
{成员表列
}变量名表列;
说明:
- 只能对结构体变量赋值而不能对结构体类型赋值。在编译时,结构体类是不分配空间的,只对变量分配空间。
- 结构体类型中的成员可以与程序中的变量名相同,但二者不代表同一对象。例如,程序中可以另定义一个变量num,它与struct Student中的num是两回事,相互不干扰。
结构体变量的初始化和引用
【例9.1】把一个学生的信息(包括学号、姓名、性别)放到同一个结构体变量中,并输出这个学生的信息
#include<stdio.h>
int main()
{struct Student{int num;char name[20];char sex;int age;// float score;}a={10101,"Li Lin",'M'};printf("学号:%d,姓名:%d,性别:%d。\n",a.num,a.name,a.sex,a.age);return 0;
}
定义结构体数组
- sturct 结构体名
{成员列表} 数组名【数组长度】;struct Person {char name[20];int count; }leader[3];
- 结构体类型 数组名【数组长度】;
struct Person leader[3];
定义结构体数组
【例9.3】有三个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先输入被选人的名字,最后输出各人得票结果。
#include<string.h>
#include<stdio.h>
struct Person()
{char name[30];int count;
}leader[3]={"Li",0,"zhang",0,"sun",0};int main()
{int i,j;char leader_name[20];for(i=1;i<=10;i++){scanf("%s",leader_name);for(j=0;j<3;j++){if(strcmp(leader_name,leader[j].name==0))leader[j].count++;}}printf("\nResult:\n");for(i=0;i<3;i++)printf("%5s:%d\n",leader[i].name,leader[i].count);return 0;
}
指向结构体变量的指针
struct Student *pt
【例9.5】通过指向结构体变量的指针变量输出结构体变量中的成员信息
#include<stdio.h>
#include<string.h>
int main()
{struct Student{long num;char name[20];char sex;float score;};struct Student stu_1;return 0;
}
注:以下三种等价
- stu成员名(如stu.num)
- (*p).成员名(如( *p).num)
- p->成员名(如p->num)
指向结构体的指针
【例9.6】有3个学生的信息,放在结构体数组中,要求输出全部学生的信息
#include<stdio.h>
struct Student
{int num;char name[20];char sex;int age;
};
struct Student stu[3]={{10101,"Li",'M',18},
{10102,"zhangfang",'M',19},{10104,"wangmin",'F',20}};
int main()
{struct Student *p;printf("No. Name sex age\n");for(p=stu;p<stu+3;p++>){printf("%5d %-20s %2c %4d\n",p->num,p->name,p->sex,p->age);}return 0;
}
注:
- 如果p的初值为stu,即指向stu的序号为0的元素,p加1后,p就指向下一个元素。例如:
(++p)->num //先使p自加1,然后得到p指向的元素中num成员值(即10102)
(p++)->num//先求得p->num的值(即10101),然后再使得p自加1,指向stu[] - p指针用来指向一个struct Student类型对象,不应用指向stu数组元素中的某一成员。
p = stu[1].name;//不合法,stu[1].name是stu[1]元素中成员name首字符的地址。编译时将会给出“警告”信息,表示地址的类型不匹配。
- 如果将某一个成员地址赋值给p,例如
p = (struct Student*) stu[0].name;
此时,p的值是stu[0].name成员的起始地址。但是p仍然保留原来的类型。如果执行printf("%s",p+1);,则会输出stu[1]中name的值。执行p++时,p的值的增量是结构体struct Student的长度。
用结构体变量和结构体变量的指针做函数参数
struct Student
{int num;char name[20];float score[3];float aver;
}
1. 结构体变量做函数参数
void input(struct Student stu);
2. 结构体变量的指针/数组做函数参数
void input(struct Student stu[]);
指针处理链表
注:C程序设计 谭浩强版此处有9.4节“用指针处理链表”本人将其归类到了第八章指针中
共用体
格式:
union 共用体名
{成员表列}变量表列;
例如
union Data
{int i;char ch;float f;
}a,b,c;
注:结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。而共用体变量所占的内存长度等于最长成员的长度。
引用共用体变量
a.i
a.ch
a.f
特点
-
同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一个成员,而不是同时存放几个。
union Date {int i;char ch;float f; }a; a.i = 97; printf("%d",a.i); //输出97 printf("%c",a.ch); //输出a printf("%f",a.f); //输出实数0.00000
注:整型无法用浮点型的格式输出,故
printf("%f",a.f);
输出为0 -
对共用体量化,但是初始化表只能有一个常量
union Date{int i;char ch;float f;}a = {1,‘a’,1.5}; //此处错误
-
共用体变量中起作用的成员是最后一次被赋值的成员,在对共用体变量中的一个成员赋值后,原有的变量存储单元中的值就被取代了。
-
共用体变量的地址和它的成员的地址是相同的。
-
不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。
a = 1; m = a;
-
C99之前不允许共用体变量作为函数参数,只能通过指针的形式做函数参数,C99之后允许了。
注:共用体类型一般用在两个组数据的成员大部分相同的情况之下。例如,有学生和老师两组数据,学生的成员包括:姓名、号码、性别、职业、班级。教师的成员包括:姓名、号码、性别、职业、职务。这两组数据只有班级和职务不同,因此可以定义成如下的共用体:
struct
{char name[20];char sex;char job;union{int class;char position[10];}category;
}person[2];
枚举类型
注:枚举类型放在了第3章“顺序程序设计”
typedef声明新类型名
注:typedef声明新类型名放在了第3章“顺序程序设计”
习题
1.定义一个结构体变量(包括年、月、日)。计算该日在本年中是第几天,注意闰年问题。
代码思路:
闰年:
①:可以被4整除但是不能被100整除
②:可以被400整除
#include <stdio.h>int main() {int year, month, day, d;int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};printf("请输入年、月和日:");fflush(stdout);scanf("%d %d %d", &year, &month, &day);d = 0;for (int i = 1; i < month; ++i) {d += months[i];}d += day;int flag = (year%4 == 0 && year%100 != 0) || (year%400 == 0);if(flag && month>= 3) {d++;}printf("这是%d年的第%d天\n", year, d);return 0;
}
2.写一个函数days,实现第1 题的计算。由主函数将年、月、日传递给days函数,计算后将日子数传回主函数输出。
#include <stdio.h>int main() {int days(int, int, int);int year, month, day;printf("请输入年、月和日:");fflush(stdout);scanf("%d %d %d", &year, &month, &day);printf("这是%d年的第%d天\n", year, days(year, month, day));return 0;
}int days(int year, int month, int day) {int d;int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};d = 0;for (int i = 1; i < month; ++i) {d += months[i];}d += day;int flag = (year%4 == 0 && year%100 != 0) || (year%400 == 0);if(flag && month>= 3) {d++;}return d;
}
3.编写一个函数print,打印一个学生的成绩数组,该数组中有5个学生的数据记录,每个记录包括num,name,score[3],用主函数输人这些记录,用print函数输出这些记录。
#include <stdio.h>typedef struct Student {int num;char name[30];float score[3];
}Student;int main() {void print(Student *stu);Student stu[5];printf("请输入5组学生的数据\n");fflush(stdout);for (int i = 0; i < 5; ++i) {printf("请输入编号:");fflush(stdout);scanf("%d", &stu[i].num);printf("请输入名字:");fflush(stdout);scanf("%s", stu[i].name);printf("请输入分数:");fflush(stdout);for (int j = 0; j < 3; ++j) {scanf("%f", &stu[i].score[j]);}fflush(stdin);}print(&stu);return 0;
}void print(Student *stu) {for (int i = 0; i < 5; ++i) {printf("编号:%d,姓名:%s,分数1:%f,分数2:%f,分数3:%f\n", (stu+i)->num, (stu+i)->name, (stu+i)->score[0], (stu+i)->score[1], (stu+i)->score[2]);}
}
4.在第3题的基础上,编写一个函数input,用来输人5个学生的数据记录。
#include <stdio.h>typedef struct Student {int num;char name[30];float score[3];
}Student;int main() {void print(Student *stu);void input(Student *stu);Student stu[5];input(&stu);print(&stu);return 0;
}void input(Student *stu) {printf("请输入5组学生的数据\n");fflush(stdout);for (int i = 0; i < 5; ++i) {printf("请输入编号:");fflush(stdout);scanf("%d", &stu[i].num);printf("请输入名字:");fflush(stdout);scanf("%s", stu[i].name);printf("请输入分数:");fflush(stdout);for (int j = 0; j < 3; ++j) {scanf("%f", &stu[i].score[j]);}fflush(stdin);}
}void print(Student *stu) {for (int i = 0; i < 5; ++i) {printf("编号:%d,姓名:%s,分数1:%f,分数2:%f,分数3:%f\n", (stu+i)->num, (stu+i)->name, (stu+i)->score[0], (stu+i)->score[1], (stu+i)->score[2]);}
}
5.有10个学生,每个学生的数据包括学号、姓名、3门课程的成绩,从键盘输人10个学生数据,要求输出3门课程总平均成绩,以及最高分的学生的数据(包括学号、姓名、3门课程成绩、平均分数)。
6.13个人围成一圈,从第1个人开始顺序报号1,2,3。凡报到3者退出圈子。找出最后留在圈子中的人原来的序号。要求用链表实现。
7.在第9章例9.9和例9.10的基础上,写一个函数del,用来删除动态链表中指定的节点
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
}Student, *SPoint;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。SPoint createStuList(SPoint stu, int n);void printStuList(SPoint stu);int deleteStu(SPoint sp, int num);SPoint stu;int n;printf("请输入需要创建的学生数量 n = 3\n");fflush(stdout);stu = createStuList(stu, n);
// printStuList(stu);int num;printf("请输入想要删除的编号:");fflush(stdout);scanf("%d", &num);int result = deleteStu(stu, num);if (result == 1) printf("删除成功\n");else printf("未找到相关的编号\n");printf("=====================\n");printStuList(stu);return 0;
}SPoint createStuList(SPoint stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < 3; ++i) {Student *s = (Student *) malloc(sizeof(Student));s->num = i + 1;printf("请输入编号:%d,", s->num);fflush(stdout);s->score = 90 - 10 * i;printf("请输入分数:%f\n", s->score);fflush(stdout);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(SPoint stu) {SPoint p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}int deleteStu(SPoint sp, int num) {//找到并删除成功返回1,未找到返回0;Student *p, *pre;p = sp->next;pre = sp;while (p) {if(p->num == num) {pre->next = p->next;free(p);return 1;}p = p->next;pre = pre->next;}return 0;
}
8.写一个函数insert,用来向一个动态链表插入结点
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *SPoint;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。SPoint createStuList(SPoint stu, int n);void printStuList(SPoint stu);int deleteStu(SPoint sp, int num);void insertStu(SPoint sp, Student *s);SPoint stu;int n;printf("请输入需要创建的学生数量 n = 3\n");fflush(stdout);stu = createStuList(stu, n);printf("=====================\n");Student newStu;printf("请输入一个新的num: ");fflush(stdout);scanf("%d", &newStu.num);printf("请输入学生的分数:");fflush(stdout);scanf("%f", &newStu.score);insertStu(stu, &newStu);printStuList(stu);return 0;
}SPoint createStuList(SPoint stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < 3; ++i) {Student *s = (Student *) malloc(sizeof(Student));s->num = i + 1;printf("请输入编号:%d,", s->num);fflush(stdout);s->score = 90 - 10 * i;printf("请输入分数:%f\n", s->score);fflush(stdout);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(SPoint stu) {SPoint p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}int deleteStu(SPoint sp, int num) {//找到并删除成功返回1,未找到返回0;Student *p, *pre;p = sp->next;pre = sp;while (p) {if (p->num == num) {pre->next = p->next;free(p);return 1;}p = p->next;pre = pre->next;}return 0;
}void insertStu(SPoint sp, Student *s) {Student *pre, *p;pre = sp;p = sp->next;while (p != NULL && s->num >= p->num) {p = p->next;pre = pre->next;}s->next = p;pre->next = s;
}
9.综合本章例9.9(建立链表的函数creat)、例9.10(输出链表的函数print)和本章习题第7题(删除链表中结点的函数del)、第8题(插入结点的函数insert),再编写一个主函数,先后调用这些函数。用以上5个函数组成一个程序,实现链表的建立、输出、删除和插入,在主函数中指定需要删除和插人的结点的数据。
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *SPoint;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。SPoint createStuList(SPoint stu, int n);void printStuList(SPoint stu);int deleteStu(SPoint sp, int num);void insertStu(SPoint sp, Student *s);SPoint stu;int n;printf("请输入需要创建的学生数量 n = 3\n");fflush(stdout);stu = createStuList(stu, n);printf("=====================\n");Student newStu;printf("请输入一个新的num: ");fflush(stdout);scanf("%d", &newStu.num);printf("请输入学生的分数:");fflush(stdout);scanf("%f", &newStu.score);insertStu(stu, &newStu);printStuList(stu);return 0;
}SPoint createStuList(SPoint stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < 3; ++i) {Student *s = (Student *) malloc(sizeof(Student));s->num = i + 1;printf("请输入编号:%d,", s->num);fflush(stdout);s->score = 90 - 10 * i;printf("请输入分数:%f\n", s->score);fflush(stdout);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(SPoint stu) {SPoint p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}int deleteStu(SPoint sp, int num) {//找到并删除成功返回1,未找到返回0;Student *p, *pre;p = sp->next;pre = sp;while (p) {if (p->num == num) {pre->next = p->next;free(p);return 1;}p = p->next;pre = pre->next;}return 0;
}void insertStu(SPoint sp, Student *s) {Student *pre, *p;pre = sp;p = sp->next;while (p != NULL && s->num >= p->num) {p = p->next;pre = pre->next;}s->next = p;pre->next = s;
}
10.已有a,b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并, 按学号升序排列。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *StudentList;int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。StudentList createStuList(StudentList stu, int n);void printStuList(StudentList stu);void mergeList(StudentList Sa, StudentList Sb);void sortList(StudentList S);StudentList Sa, Sb;int na, nb;printf("请输入需要创建的学生数量 na和nb: ");fflush(stdout);scanf("%d,%d", &na, &nb);fflush(stdin);Sa = createStuList(Sa, na);Sb = createStuList(Sb, nb);printStuList(Sa);printf("*****************\n");printStuList(Sb);printf("=====================\n");// 对每个链表排序sortList(Sa);sortList(Sb);printStuList(Sa);printf("*****************\n");printStuList(Sb);printf("=====================\n");mergeList(Sa, Sb);printStuList(Sa);return 0;
}StudentList createStuList(StudentList stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;unsigned int second = time(NULL);srand(second);// 延迟函数while (1) {unsigned int nextSecond = time(NULL);if(second + 2 >= nextSecond) break;}for (int i = 0; i < n; ++i) {Student *s = (Student *) malloc(sizeof(Student));printf("请输入编号:");fflush(stdout);scanf("%d", &s->num);printf("请输入分数:");fflush(stdout);scanf("%f", &s->score);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(StudentList stu) {StudentList p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}void mergeList(StudentList Sa, StudentList Sb) {Student *head, *ph, *pa, *pb;head = Sa;ph = Sa;pa = Sa->next;pb = Sb->next;while (pa && pb) {if(pa->num <= pb->num) {ph->next = pa;ph = pa;pa = pa->next;}else {ph->next = pb;ph = pb;pb = pb->next;}}if (pa) {ph->next = pa;}if (pb) {ph->next = pb;}
}void sortList(StudentList S) {int compare(const void*, const void*);int size = 0;Student *hp, *sp;hp = S->next;while (hp) {hp = hp->next;size++;}hp = S->next;sp = (Student*) malloc(sizeof(Student)*size);for (int i = 0; i < size; ++i) {*(sp + i) = *hp;hp = hp->next;}hp = S->next;qsort(sp, size, sizeof(Student), compare);for (int i = 0; i < size; ++i) {*hp = *(sp +i);hp = hp->next;}
}int compare(const void *a, const void *b) {Student sa = *(Student*)a;Student sb = *(Student*)b;return (sa.num - sb.num);
}
11.有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同学号的那些结点。
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int num;float score;struct Student *next;
} Student, *StudentList;int StudentSize(StudentList S); // 求列表的元素int main() {// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。StudentList createStuList(StudentList stu, int n);void printStuList(StudentList stu);void sortList(StudentList S);void deleteSameElem(StudentList Sa, StudentList Sb);StudentList Sa, Sb;int na, nb;printf("请输入需要创建的学生数量 na和nb: ");fflush(stdout);scanf("%d,%d", &na, &nb);fflush(stdin);Sa = createStuList(Sa, na);Sb = createStuList(Sb, nb);deleteSameElem(Sa,Sb);printStuList(Sa);return 0;
}StudentList createStuList(StudentList stu, int n) {Student *r;stu = (Student *) malloc(sizeof(Student));stu->next = NULL; // 记得跟上NULLr = stu;for (int i = 0; i < n; ++i) {Student *s = (Student *) malloc(sizeof(Student));printf("请输入编号:");fflush(stdout);scanf("%d", &s->num);printf("请输入分数:");fflush(stdout);scanf("%f", &s->score);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stu;
}void printStuList(StudentList stu) {StudentList p;p = stu->next;while (p) {printf("编号:%d,成绩:%f\n", p->num, p->score);p = p->next;}
}void sortList(StudentList S) {int compare(const void*, const void*);int size = StudentSize(S); //链表长度Student *hp, *sp;hp = S->next;sp = (Student *) malloc(sizeof(Student)*size); //sp指向链表S的数组形式for (int i = 0; i < size; ++i) {*(sp + i) = *hp;hp = hp->next;}hp = S->next;qsort(sp, size, sizeof(Student), compare);for (int i = 0; i < size; ++i) {hp->num = (sp +i)->num;hp->score = (sp +i)->score;hp = hp->next;}
}int compare(const void *a, const void *b) {Student sa = *(Student*)a;Student sb = *(Student*)b;return (sa.num - sb.num);
}void deleteSameElem(StudentList Sa, StudentList Sb) {
// 两个链表必须是排序过的int sizeA, sizeB, indexA;Student *pa, *pb, *pre;pa = Sa->next;pb = Sb->next;sizeA = StudentSize(Sa);sizeB = StudentSize(Sb);Student *arrA = (Student*) malloc(sizeof(sizeA));Student *arrB = (Student*) malloc(sizeof(sizeB));for (int i = 0; i < sizeB; ++i) {*(arrB + i) = *pb;pb = pb->next;}// 删除B链表中num相同的结构pre = Sa;pa = Sa->next;while (pa) {for (int i = 0; i < sizeB; ++i) {if(pa->num == (arrB+i)->num) {pre->next = pa->next;pa = pa->next;}else {pre = pre->next;pa = pa->next;}}}
}int StudentSize(StudentList S) {int size = 0;Student *p = S->next;while (p) {p = p->next;size++;}return size;
}
12.建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去。
#include <stdio.h>
#include <stdlib.h>typedef struct Student {int no;char name[30];char sex; //年龄男性为M,女性为Wint age;struct Student *next;
} Student, *StudentList;// 求列表的元素
int StudentSize(StudentList S) {int size = 0;Student *p = S->next;while (p) {p = p->next;size++;}return size;
}int main() {
// 一定要有返回!!!stu传入函数后,在函数内分配的地址会被回收。StudentList createStudentList(StudentList stuHead, int n);
// 如果年龄相同,则把这个元素在链表中删除void deleteStudent(StudentList stuHead, int age);
// 打印链表void printStudentList(StudentList stu);int n, age;Student *stuHead;// 创建一组链表printf("请输入个数,这个数将用来创建一组链表。\n");printf("n = ");fflush(stdout);scanf("%d", &n);stuHead = createStudentList(stuHead, n);// 如果链表中有值和输入的年龄相同则把链表中删除的元素删去。printf("请输入一个年龄\n");printf("age = ");fflush(stdout);scanf("%d", &age);deleteStudent(stuHead, age);printStudentList(stuHead);return 0;
}StudentList createStudentList(StudentList stuHead, int n) {Student *r;stuHead = (Student *) malloc(sizeof(Student));stuHead->next = NULL; // 记得跟上NULLr = stuHead;for (int i = 0; i < n; ++i) {Student *s = (Student *) malloc(sizeof(Student));printf("请输入学号:");fflush(stdout);scanf("%d", &s->no);printf("请输入姓名:");fflush(stdout);scanf("%s", s->name);fflush(stdin);printf("请输入性别:");fflush(stdout);scanf("%c", &s->sex);printf("请输入年龄:");fflush(stdout);scanf("%d", &s->age);r->next = s;r = s; // 这边不要写成了s = r;}r->next = NULL;return stuHead;
}void deleteStudent(StudentList stuHead, int age) {Student *sp, *pre, *m;pre = stuHead;sp = stuHead->next;while (sp) {if(sp->age == age) {pre->next = sp->next;m = sp;sp = sp->next;free(m);}else {pre = pre->next;sp = sp->next;}}
}void printStudentList(StudentList stuHead) {StudentList p;p = stuHead->next;while (p) {printf("学号:%d,姓名:%s,性别:%c,年龄:%d\n", p->no, p->name, p->sex, p->age);p = p->next;}
}