第九章节 用户自己建立数据类型——选择题、填空、大题 9.1-9.4、9.6、9.7是重点
9.1 定义和使用结构体变量
struct 结构体名
{ 成员列表 } 结构体变量1 ,结构体变量2;
例如:
struct Date{
int mouth;
int day;
int year;
}date1,date2;
9.2 使用结构体数组
9.2.1 定义结构体数组
例:
struct Person{
char name[20];
int count;
}leader[3]={“Li” , 0 , “Zhang” , 0 , ”Sun” , 0};
( 1 )定义结构体的一般形式:
struct 结构体名{
成员列表
}数组名[数组长度];
或者:
先声明一个结构体类型,然后再定义结构体数组如下:
结构体类型 数组名[数组长度]
如:struct Person leader[3];
( 2 ) 初始化结构体数组
struct Person leader[3]={“Li” , 0 , “Zhang” , 0 , ”Sun” , 0};
结构体应用举例:
//对学生分数排序
#include<stdio.h>
#define N 5
struct Student{
int num;
char name[20];
float score;
};
int main(){
int i , k , j ;
struct Student t;
struct Student stu[5] = {
{10101 , "dingxu" , 94.5},
{10132 , "zhouxuewen" , 91.3},
{10121 , "gelulu" , 93.1},
{10100 , "yujiaixng" , 92.4},
{10111 , "wangxingxing" , 94}};
for(i = 0 ; i < N - 1 ; i++){
k = i;
for(j = i + 1; j < N ; j++){
if(stu[k].score < stu[j].score ){
k = j;
}
}
if(k != i){
t = stu[k];
stu[k] = stu[i];
stu[i] = t;
}
}
for(i = 0 ; i < N ;i++){
printf("num = %d\tname = %s\tscore = %0.2lf\n" , stu[i].num , stu[i].name , stu[i].score );
}
}
9.3 结构体指针
通过例9.6来了解结构体指针
#include<stdio.h>
struct Student{
int num;
char name[20];
char sex;
int age;
};
//初始化
struct Student stu[3] = {
{10101 , "Li Lin" , 'M' , 21},
{10103 , "Ding Xu" , 'M' , 22},
{10104 , "Sun Jie" , 'M' , 23},
};
int main(){
struct Student *p;
for(p = stu ; p < stu + 3 ; p++){
printf("(*p).num = %d\t(*p).name = %s\t(*p).sex = %c\t(*p).age = %d\n"
, (*p).num , (*p).name , (*p).sex , (*p).age);
printf("p->num = %d\tp->name = %s\tp->sex = %c\tp->age = %d\n"
, p->num , p->name , p->sex , p->age);
}
}
9.3.3 用结构体变量和结构体变量的指针作为函数参数
一、用结构体变量的成员作参数。例如,stu[1].num ,从实参传到形参属于值传递
二、用结构体变量作实参。用结构体变量作实参时,采取的也是值传递 , 形参也必须是同类型的结构体变量。
三、用指向结构体的指针变量的指针作实参,将结构体变量的地址传递给形参。
9.4 用指针处理链表
9.4.1 什么是链表
链表有一个头指针变量,链表中每个元素成为“节点”,每个节点都包括两个部分:(1)用户需要的实际数据 (2)下一个节点的地址。
struct Student{
int num;
float score;
struct Student *next;
}
9.4.2 静态链表
所有节点都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为“静态链表”
9.4.3 动态链表
使用(malloc ,calloc , realloc ,free)
#include<stdio.h>
#include<stdlib.h>
#define LEN (struct Student)
struct Student{
long num;
float score;
struct Student *next;
};
int n;
struct Student *creat(void){
struct Student *head;
struct Student *p1 , *p2;
head = NULL;
n = 0;//节点的个数
p1 = p2 = (struct Student *)malloc(LEN);//开辟新的内存区域
p1 -> num = 10;//就当输入的值了
p1 -> score = 100;
while(n < 5){//5个节点
if( n == 1){
head = p1; //如果是第一个节点,给头节点
}else{
p2 -> next = p1; //p2经过下面的变换,变成了链表末尾的区域,所以将其的next指向新开辟的p1
}
n = n + 1;
p2 = p1;//p2变成末尾的区域
p1 = (struct Student *)malloc(LEN);//p1开辟新的空间
p1 -> num = p2 -> num + 1;//新的空间的值 + 1
p1 -> score = p2 -> score + 1;//同上
}
p2 -> next = NULL;//末尾指向NULL
return head;
}
int main(){
struct Student *p , *k;
p = creat();
for(k = p; k != NULL ; k = k ->next ){
printf(“%ld\t%lf\n” , k -> num , k -> score);
}
return 0;
}
9.6 枚举类型
enum 将可能的值列举出来,变量的值就在列举出来的范围内。
声明方法:
一:
enum Weekday{sun,mon,tue,wed,thu,fri,sat}; //声明枚举类型,不可赋值
//由编译器自动默认的值为 sun = 0 , mon = 1 , tue = 2 ……
//也可以手动赋值{sun = 7,mon,tue,wed,thu,fri,sat};
enum Weekday workday,weekend;//定义枚举变量
workday = mon;//枚举变量只能等于枚举类型中的常量之一
weekend = sun;
weekday = monday;//❌ monday不是指定的枚举常量
二:
enum {sun,mon,tue,wed,thu,fri,sat} workday , weekend;
为什么使用枚举类型?
为了便于理解,什么标识符代表什么含义完全由程序员决定,实现了“见名知意”,枚举元素有范围,如果出错便于检查。书上例题有具体实现。
9.7 typedef 声明新类型名
1、简单的用一个新的类型名代替原有的类型名
typedef int Integer; //指定Integer为类型名,作用与int相同
typedef float Real;
2、命名一个简单的类型名代替复杂的类型表示方法
(1)
typedef struct{
int month;
int day;
int year;
}Date;
Date birthday;
Date *p;//定义结构体指针变量p,指向此结构体类型数据
(2)
typedef int Num[100];
Num a; //定义a为整形数组名,指向此结构体类型数据
(3)
typedef char *String;
String p,s[10]; //定义a为整形数组名,指向此结构体类型数据
(4)
typedef int (*Pointer)();
Pointer p1,p2;
习题 01 02 15年真题最后一题编程//部分代码
//输入一个日期startdate(年 月 日)和天数days(>=1),
//输出自该输入日期days天后的日期enddate(即enddate=startdate+days。
//要求输入和输出的年份为四位整数,输入时要对输入数据的有效性进行检查,并确保得到有效的输入数据。
//同时需要考虑跨月、跨年和闰年等情况,闰年用自定义函数计算,日期用自定义结构体描述。
#include<stdio.h>
struct Date{
int day;
int month;
int year;
};
int main(){
int runnain(int year);
int panduan(struct Date date , int flag);
void jisuan(struct Date date , int flag , int days);
struct Date startdate;//一个开始日期
startdate.day = 11;//开始日期赋值
startdate.month = 1;
startdate.year = 2007;
int days = 30 , flag = 0;//输入days天
struct Date enddate;//结束日期 enddate = startdate + days
//判断是否是闰年
flag = runnain(startdate.year);
//判断输入值是否合法
if(!panduan(startdate , flag)){
return 0;
}else{
printf("startday:\nyear = %d\nmonth = %d\ndays = %d\nadd days = %d\n\n" , startdate.year, startdate.month, startdate.day , days);
}
//计算enddate
jisuan(startdate , flag , days);
return 0;
}
int runnain(int year){
int flag = 0;
if(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))flag = 1;
else flag = 0;
return flag;
}
int panduan(struct Date startdate , int flag){
if(startdate.year < 1000 && startdate.year > 9999){
printf("输入数据不合法");
return 0;
}
if(startdate.month >0 && startdate . month < 13){//检查输入日期的有效性
if(
startdate . month == 1 || startdate . month == 3 ||
startdate . month == 5 || startdate . month == 7 ||
startdate . month == 8 || startdate . month == 10||
startdate . month == 12){
if(!(startdate . day > 0 && startdate . day < 32)){
printf("输入数据不合法");return 0;
}
}else if(
startdate . month == 4 || startdate . month == 6 ||
startdate . month == 9 || startdate . month == 11){
if(!(startdate . day > 0 && startdate . day < 31)){
printf("输入数据不合法");return 0;
}
}else{
if(flag == 1){
if(!(startdate . day > 0 && startdate . day < 30)){
printf("输入数据不合法");return 0;
}
}else{
if(!(startdate . day > 0 && startdate . day < 29)){
printf("输入数据不合法");return 0;
}
}
}
}else{
printf("输入数据不合法");
return 0;
}
return 1;
}
习题03,04 //输入输出学生成绩
#include<stdio.h>
#include<string.h>
struct Student{
int num;
char name[50];
int score[3];
};
int main(){
void input(struct Student stu[]);
void print(struct Student stu[]);
struct Student stu[3];
input(stu);
print(stu);
return 0;
}
void input(struct Student stu[]){//输入
strcpy(stu[0].name,"dingxu1");
strcpy(stu[1].name,"dingxu2");
strcpy(stu[2].name,"dingxu3");
for(int i = 0; i < 3 ; i++ ){
stu[i].num = i + 1;
for(int j = 0 ; j < 3 ; j++){
stu[i].score[j] = i + 10;
}
}
}
void print(struct Student stu[]){
int i ,j;
for(i = 0; i < 3 ; i++ ){
printf("name = %s\t" , stu[i].name);
printf("num = %d\t" , stu[i].num);
for( j = 0 ;j < 3; j++){
printf("score = %d\t" , stu[i].score[j]);
}
printf("\n");
}
}
0906.13个人坐一圈,报到3退出
#include <stdio.h>
#include <stdlib.h>
struct Person{ //定义结构体
int num;
Person *next;
};
int main()
{
Person per[13]; //定义结构体变量数组
int i;
for (i=0; i<13; i++){ //此循环给13个人标注序号,1对应第一个人,以此类推,同时实现循环链表,当到达链表最后一个时,地址指向开头。
per[i].num=i+1;
if (i==12) per[i].next=&per[0];
else per[i].next=&per[i+1];
}
Person *p;
for (p=per, i=0; p->next!=p; p=p->next){ //循环报号,当每次报到第2个人时,next指针直接跳过下一个变量,指向下下个变量,当next指针指向自己时结束循环。
i++;
if (i%2==0){
p->next=p->next->next;
i=0;
}
}
for (p=per, i=0; p->next!=p; p=p->next){ //法二同上,此法便于理解
if ((i + 1)%2==0){
p->next=p->next->next;
}
i++;
}
//第三种方法,双指针,将中间节点删除
struct Person *p1,*p2;
for (p1=per ,p2 = per->next, i=0; p1->next!=p1;
p1=p1->next, p2=p2->next ){
if ((i + 1)%2==0){
p1->next=p2->next;
p2=p1->next;
}
i++;
}
//法四见第八章
printf("The number is %d\n", p->num); //输出结果
system("pause");
return 0;
}
习题9.9
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct Student)
struct Student {
int num;
float score;
struct Student* next;
};
int n;//n为节点个数
//动态创建一个节点
struct Student* creat() {
struct Student* p1, * p2;
struct Student* head;
head = NULL;
n = 0;
p1 = p2 = (struct Student*)malloc(LEN);
scanf("%d %f", &p1->num, &p1->score);
while (p1 -> num != 0)
{
n = n + 1;
if (n == 1) {
head = p1;
}
else {
p2->next = p1;
}
p2 = p1;
p1 = (struct Student*)malloc(LEN);
scanf("%d %f", &p1->num, &p1->score);
}
p2->next = NULL;
return head;
}
struct Student* del(struct Student* head , int delnum) {
struct Student* p1 , *p2;
p2 = p1 = head;
if (p1 != NULL) {
while (p1 ->num != delnum && p1 ->next != NULL) {//注意要判断下一个节点不是空节点
p2 = p1;
p1 = p1->next;
}
if (delnum == p1->num) {
if (p1 == head)head = p1->next;//如果是头节点,直接指向下一个节点
else {
p2->next = p1->next;
}
n = n - 1;
}
}
else
return NULL;
return head;
}
struct Student* insert(struct Student* head, int inum, float iscore) {
struct Student* p1, * p2 , *t;
p2 = p1 = head;
t = (struct Student*)malloc(LEN);//开辟一个新节点
t->num = inum;
t->score = iscore;
if (head != NULL) {
while (inum > p1 -> num && p1 -> next != NULL) {
p2 = p1;
p1 = p1->next;
}
if (inum <= p1->num) {
if (p1 == head) {
head = t;
}
else {
p2->next = t;
}
t->next = p1;
n = n + 1;
}
else {
p1->next = t;
t->next = NULL;
n = n + 1;
}
}
return head;
}
void print(struct Student *stu) {
struct Student* p;
for (p = stu; p != NULL; p = p->next) {
printf("%d %f\n", p->num, p->score);
}
}
int main() {
//动态创建一个链表
struct Student* creat();
//删除
struct Student* del(struct Student * head, int num);
//插入
struct Student* insert(struct Student* head, int num ,float score);
//输出
void print(struct Student *);
struct Student* head;//头节点
printf("**********************创建节点*******************\n");
head = creat();//创建节点
print(head);//输出各个节点
printf("**********************删除节点*******************\n");
int delnum = 0;
scanf("%d" , &delnum);
head = del(head , delnum);//删除节点
print(head);//输出各个节点
printf("**********************插入节点*******************\n");
int stu;
float score;
scanf("%d %f", &stu , &score);
head = insert(head, stu ,score);//删除节点
print(head);//输出各个节点
return 0;
}
真题知识点
D