第九章节 用户自己建立数据类型

第九章节 用户自己建立数据类型——选择题、填空、大题 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;
}

习题0304 //输入输出学生成绩
#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
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值