前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >开讲啦:Chap 09 用户自己建立数据类型

开讲啦:Chap 09 用户自己建立数据类型

作者头像
石璞东
发布2021-10-13 11:56:49
3850
发布2021-10-13 11:56:49
举报
文章被收录于专栏:石璞东 | haha石璞东 | haha

关注hahaCoder 获取最新资讯”

前言

C语言允许用户根据需要自己建立数据类型,用它来定义变量。

9.1 定义和使用结构体变量

9.1.1 自己建立结构体类型

C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体。

代码语言:javascript
复制
struct Student{
    int num;
    char name[20];
    char sex;
    int  age;
    float score;
    char addr[30];
};

声明一个结构体的一般形式为:

代码语言:javascript
复制
struct 结构体名{
    成员列表;
}
  • 成员可以属于另一个结构体类型。
代码语言:javascript
复制
struct Date{
    int month;
    int year;
    int day;
};
struct Student{
    int num;
    char name[20];
    chat sex;
    int age;
    struct Date birthday;
    char addr[30];
};

9.1.2 定义结构体类型变量

  • 先声明结构体类型,再定义该类型的变量
代码语言:javascript
复制
struct Student{
    int num;
    char name[20];
    char sex;
    int  age;
    float score;
    char addr[30];
};
struct Student student1,student2;

int a,b;类似,定义完成后,student1student2即为struct Student类型的变量。

  • 在声明类型的同时定义变量
代码语言:javascript
复制
struct Student{
    int num;
    char name[20];
    char sex;
    int  age;
    float score;
    char addr[30];
} student1,student2;

其一般形式为:

代码语言:javascript
复制
struct 结构体名{
	// 成员列表
}变量名列表;
  • 不指定类型名而直接定义结构体类型变量
代码语言:javascript
复制
struct{
	//成员列表
}变量名列表;

9.1.3 结构体变量的初始化和引用

例9.1 把一个学生的学号、姓名、性别、住址放在一个结构体变量中,然后输出这个学生的信息。

代码语言:javascript
复制
#include<stdio.h>
int main(){
    struct Student{
        int num;
        char name[20];
        char sex;
        char addr[20];
    }student = {100001,"shipudong",'M',"China Xi'an"};
    printf("学号:%d\n姓名:%s\n性别:%c\n地址:%s\n",student.num,student.name,student.sex,student.addr);
    return 0;
}
  • C99标准允许对某一成员初始化,其他未被指定初始化的数值型成员被系统初始化为0,字符型成员被系统初始化为\0,指针型成员被系统初始化为NULL
代码语言:javascript
复制
#include<stdio.h>
int main(){
    struct Student{
        int num;
        char name[20];
        char sex;
        char addr[20];
    }student = {100001,"shipudong",'M',"China Xi'an"};
    struct Student student1 = {.name = "hahaCoder"};
    printf("学号:%d\n姓名:%s\n性别:%c\n地址:%s\n",student.num,student.name,student.sex,student.addr);
    printf("==========================\n");
    printf("学号:%d\n姓名:%s\n性别:%c\n地址:%s\n",student1.num,student1.name,student1.sex,student1.addr);
    return 0;
}
  • 可以通过结构体变量名.成员名引用结构体变量中成员的值,不能企图输出结构体变量名来达到输出结构体变量所有成员的值;
  • 如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。
代码语言:javascript
复制
#include<stdio.h>
int main(){
    struct Date{
        int year;
        int month;
        int day;
    };
    struct Student{
        int num;
        char name[20];
        char sex;
        struct Date birthday;
        char addr[20];
    }student = {100001,"shipudong",'M',{2021,10,11},"China Xi'an"};
    struct Student student1 = {.name = "hahaCoder"};
    printf("学号:%d\n姓名:%s\n性别:%c\n出生日期:%d年%d月%d日\n地址:%s\n",student.num,student.name,student.sex,student.birthday.year,student.birthday.month,student.birthday.day,student.addr);
    printf("==========================\n");
    printf("学号:%d\n姓名:%s\n性别:%c\n出生日期:%d年%d月%d日\n地址:%s\n",student1.num,student1.name,student1.sex,student1.birthday.year,student1.birthday.month,student1.birthday.day,student1.addr);
    return 0;
}
  • 对结构体变量的成员可以像普通变量一样进行各种运算
  • 同类的结构体变量可以互相赋值;
代码语言:javascript
复制
#include<stdio.h>
int main(){
    struct Date{
        int year;
        int month;
        int day;
    };
    struct Student{
        int num;
        char name[20];
        char sex;
        struct Date birthday;
        char addr[20];
    }student = {100001,"shipudong",'M',{2021,10,11},"China Xi'an"};
    struct Student student1 = {.name = "hahaCoder"};
    printf("学号:%d\n姓名:%s\n性别:%c\n出生日期:%d年%d月%d日\n地址:%s\n",student.num,student.name,student.sex,student.birthday.year,student.birthday.month,student.birthday.day,student.addr);
    printf("==========================\n");
    printf("学号:%d\n姓名:%s\n性别:%c\n出生日期:%d年%d月%d日\n地址:%s\n",student1.num,student1.name,student1.sex,student1.birthday.year,student1.birthday.month,student1.birthday.day,student1.addr);
    student1 = student;
    printf("==========================\n");
    printf("学号:%d\n姓名:%s\n性别:%c\n出生日期:%d年%d月%d日\n地址:%s\n",student.num,student.name,student.sex,student.birthday.year,student.birthday.month,student.birthday.day,student.addr);
    return 0;
}
  • 可以引用结构体变量成员的地址,也可以引用结构体变量的地址,结构体变量的地址主要用作函数参数,传递结构体变量的地址;

例9.2 输入两个学生的学号、姓名和成绩,输出成绩较高的学生的学号、姓名和成绩。

代码语言:javascript
复制
#include<stdio.h>
int main(){
    struct Student{
        int num;
        char name[20];
        float score;
    }student1,student2;
    printf("请分别输入两个学生的学号、姓名和分数:\n");
    scanf("%d %s %f",&student1.num,student1.name,&student1.score);
    scanf("%d %s %f",&student2.num,student2.name,&student2.score);
    printf("成绩较高的学生为:\n");
    if(student1.score>student2.score){
        printf("%d %s %f\n",student1.num,student1.name,student1.score);
    }else if (student1.score<student2.score){
        printf("%d %s %f\n",student2.num,student2.name,student2.score);
    }else{
        printf("%d %s %.2f\n",student1.num,student1.name,student1.score);
        printf("%d %s %.2f\n",student2.num,student2.name,student2.score);
    }
    return 0;
}

9.2 使用结构体数组

9.2.1 定义结构体数组

例9.3 有3个候选人,每个选民只能投票选1人,要求编一个统计选票的程序,先后输入被选人的名字,最后输出各人得票结果。

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
struct Person{
    char name[20];
    int count;
}leader[3] = {"hahaCoder",0,"hahaAI",0,"hahaWebsite.",0};

int main(){
    char leader_name[20];
    for (int i = 1; i <= 8; i++) {
        printf("请输入第%d个候选人姓名:",i);
        scanf("%s",leader_name);
        for (int j = 0; j < 3; j++) {
            if(strcmp(leader_name, leader[j].name)==0){
                leader[j].count++;
            }
        }
    }
    
    for (int i = 0; i < 3; i++) {
        printf("姓名:%s --> 选票数:%d\n",leader[i].name,leader[i].count);
    }
    return 0;
}

定义结构体数组的一般形式为:

代码语言:javascript
复制
struct 结构体名{
	成员列表;
}数组名[数组长度];

9.2.2 结构体数组的应用举例

例9.4 有n个学生的信息(包括学号、姓名、成绩),要求按照成绩的高低顺序输出各学生的信息。

代码语言:javascript
复制
#include<stdio.h>
struct Student{
    int num;
    char name[20];
    float score;
};

int main(){
    struct Student student[5] = {
        {0001,"hahaAI",98},
        {0002,"hahaCoder",99},
        {0003,"hahaWebsite",90},
        {0004,"hahaOCR",89},
        {0005,"hahaBook",100}
    };
    struct Student temp;
    int i,j,k;
    const int n = 5;
    printf("得分由小到大的顺序为:\n");
    for (i = 0; i < n-1; i++) {
        k = i;
        for (j = i+1; j < n; j++) {
            if(student[j].score < student[k].score){
                k = j;
            }
        }
        if(k!=i){
            temp = student[k];
            student[k] = student[i];
            student[i] = temp;
        }
    }
    for (int i = 0; i < n; i++) {
        printf("学号:%d\t姓名:%s\t得分:%.2f\n",student[i].num,student[i].name,student[i].score);
    }
    return 0;
}

9.3 结构体指针

所谓结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。

9.3.1 指向结构体变量的指针

指向结构体对象的指针变量既可指向结构体变量,也可指向结构体数组中的元素,指针变量的基类型必须与结构体变量的类型相同。

例9.5 通过指向结构体变量的指针变量输出结构体变量中成员的信息。

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>

int main(){
    struct Student{
        int num;
        char name[20];
        char sex;
        float score;
    }student,*p;
    p = &student;
    student.num = 100001;
    strcpy(student.name, "hahaCoder");
    student.sex = 'M';
    student.score = 98.29;
    printf("学号:%d\t姓名:%s\t性别:%c\t分数:%.2f\n",student.num,student.name,student.sex,student.score);
    printf("学号:%d\t姓名:%s\t性别:%c\t分数:%.2f\n",(*p).num,(*p).name,(*p).sex,(*p).score);
    printf("学号:%d\t姓名:%s\t性别:%c\t分数:%.2f\n",p->num,p->name,p->sex,p->score);
    return 0;
}

如果p指向一个结构体变量stu,以下3种方法等价:

  • stu.成员名stu.num
  • (*p).成员名(*p).num
  • p->成员名p->num

9.3.2 指向结构体数组的指针

例9.6 有3个学生的信息,放在结构体数组中,要求输出全部学生的信息。

代码语言:javascript
复制
#include<stdio.h>
struct Student{
    int num;
    char name[20];
    float score;
};
struct Student student[5] = {
    {0001,"hahaAI",98},
    {0002,"hahaCoder",99},
    {0003,"hahaWebsite",90},
    {0004,"hahaOCR",89},
    {0005,"hahaBook",100}
};

int main(){
    struct Student *p;
    for (p = student; p < student+5; p++) {
        printf("学号:%d\t姓名:%s\t分数:%.2f\n",p->num,p->name,p->score);
    }
    return 0;
}

9.3.3 用结构体变量和结构体变量的指针作函数参数

将一个结构体变量的值传递给另一个函数,有3种方法:

  • 用结构体变量的成员作参数;
  • 用结构体变量作实参;
  • 用指向结构体变量或数组元素的指针作实参,将结构体变量或数组元素的地址传给形参;

例9.7 有n个结构体变量,内含学生学号、姓名和3门课的成绩,要求求出平均成绩最高的学生的信息。

代码语言:javascript
复制
#include<stdio.h>
#define NUM 3
struct Student{
    int num;
    char name[20];
    float score[3];
    float aver;
};

int main(){
    void input(struct Student student[]);
    struct Student max(struct Student student[]);
    void print(struct Student student);
    struct Student student[NUM],*p = student;
    input(p);
    print(max(p));
    return 0;
}
void input(struct Student student[]){
    for (int i = 0; i < NUM; i++) {
        printf("请输入第%d个学生的学号、姓名、三门课成绩等信息:\n",i+1);
        scanf("%d %s %f %f %f",&student[i].num,student[i].name,&student[i].score[0],&student[i].score[1],&student[i].score[2]);
        student[i].aver = (student[i].score[0]+student[i].score[1]+student[i].score[2])/3.0;
    }
}
struct Student max(struct Student student[]){
    int max_num = 0;
    for (int i = 0; i < NUM; i++) {
        if(student[i].aver > student[max_num].aver){
            max_num = i;
        }
    }
    return student[max_num];
}
void print(struct Student student){
    printf("成绩最高的学生为:\n");
    printf("学号:%d\t姓名:%s\t三门课成绩分别为:%.2f、%.2f、%.2f\t平均成绩:%.2f\n",student.num,student.name,student.score[0],student.score[1],student.score[2],student.aver);
    
}

9.4 用指针处理链表

9.4.1 什么是链表

链表有一个头指针变量,图中以head表示,它存放一个地址,该地址指向一个元素,链表中每一个元素称为结点,每个结点都应该包括两个部分:

  • 用户需要用的实际数据;
  • 下一个结点的地址;

可以看出,head指向第1个元素,第1个元素又指向第2个元素......直到最后一个元素,该元素不再指向其他元素,它称为表尾,它的地址部分放一个NULL,表示空地址,链表到此结束。链表中各元素在内存中的地址可以是不连续的,要找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素,如果不提供头指针,则整个链表无法访问。

9.4.2 建立简单的静态链表

参考试听课代码。

9.4.3 建立动态链表

参考试听课代码。

9.4.4 输出链表

参考试听课代码。

9.5 共用体类型

9.5.1 什么是共用体类型

定义共用体类型的一般形式为:

代码语言:javascript
复制
union 共用体名{
	成员列表
}变量列表;

共用体与结构体定义形式类似,但它们的含义是不同的,结构体变量所占内存长度是各成员占的内存长度之和,每个成员分别占有其自己的内存单元,而共用体变量所占的内存长度等于最长的成员的长度。

代码语言:javascript
复制
#include<stdio.h>
struct Student{
    int num;
    char name[20];
    float score[3];
    float aver;
};
union Person{
    int num;
    char name[20];
    float score[3];
    float aver;
};

int main(){
    printf("结构体Student的大小为:%d\n",sizeof(struct Student)); // 40
    printf("共用体union的大小为:%d\n",sizeof(union Person)); // 20
    return 0;
}

9.5.2 引用共用体变量的方式

代码语言:javascript
复制
#include<stdio.h>
union Person{
    int num;
    char name[20];
    float aver;
} person;
 
int main(){
    person.num = 1000;
    printf("学号:%d\t姓名:%s\t平均分:%.2f\n",person.num,person.name,person.aver);
    return 0;
}

9.5.3 共用体类型数据的特点

  • 同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一个成员,而不是同时存放几个;
  • 可以对共用体变量初始化,但初始化列表中只能有一个常量;
  • 共用体变量中起作用的成员是最后一次被赋值的成员,在对共用体变量中的一个成员赋值后,原有变量存储单元中的值就被取代;

共用体类型的数据的应用场景:有时需要对同一段空间安排不同的用途。

例9.8 有若干个人员的数据,其中有学生和教师,学生的数据中包括:姓名、号码、性别、职业、班级;教师的数据包括:姓名、号码、性别、职业、职务。

代码语言:javascript
复制
#include<stdio.h>
struct{
    int num;
    char name[10];
    char sex;
    char job;
    union{
        int clas;
        char position[10];
    }category;
}person[2];

int main(){
    int i;
    for (i = 0; i < 2; i++) {
        printf("请输入第%d个用户的信息:\n",(i+1));
        scanf("%d %s %c %c",&person[i].num,person[i].name,&person[i].sex,&person[i].job);
        if(person[i].job=='s'){
            printf("请输入学生班级信息:\n");
            scanf("%d",&person[i].category.clas);
        }else if (person[i].job == 't'){
            printf("请输入老师职务信息:\n");
            scanf("%s",person[i].category.position);
        }else{
            printf("输入错误!\n");
        }
    }
    for (i = 0;i < 2; i++) {
        if(person[i].job == 's'){
            printf("学号:%d\t姓名:%s\t性别:%c\t职业:%c\t班级:%d\n",person[i].num,person[i].name,person[i].sex,person[i].job,person[i].category.clas);
        }else{
            printf("号码:%d\t姓名:%s\t性别:%c\t职业:%c\t职务:%s\n",person[i].num,person[i].name,person[i].sex,person[i].job,person[i].category.position);
        }
    }
    return 0;
}

9.6 使用枚举类型

所谓枚举就是把可能的值一一列举出来,变量的值只限于列举出来的值的范围内,声明枚举类型用enum开头,其一般形式为:enum [枚举名]{枚举元素列表};

  • C编译对枚举类型的枚举元素按常量处理,故不能对它们赋值;
  • 每一个枚举元素都代表一个整数,C语言编译按定义时的顺序默认它们的值为0、1、2、3、4...;
  • 枚举元素可以用来做比较;

例9.9 枚举类型案例

代码语言:javascript
复制
#include <stdio.h>
 
enum DAY
{
      MON, TUE, WED, THU, FRI, SAT, SUN
};
 
int main()
{
    enum DAY day;
    day = WED;
    printf("%d\n",day);
    return 0;
}

9.7 用typedef声明新类型

  • 简单地用一个新的类型名代替原有的类型名
代码语言:javascript
复制
#include <stdio.h>
 
int main(){
//  int a = 10;
    typedef int shipudongInt;
    shipudongInt a = 10;
    printf("%d\n",a);
    return 0;
}
  • 命名一个简单的类型名代替复杂的类型表示方法
    • 命名一个新的类型名代表结构体类型
代码语言:javascript
复制
typedefstruct{
	int month;
	int day;
	int year;
}Date;
Date birthday;
代码语言:javascript
复制
typedef int NUM[100];
NUM a;
代码语言:javascript
复制
typedef char* string;
string p;
代码语言:javascript
复制
typedef int (*pointer)();//pointer为指向函数的指针类型,该函数返回整型值;
pointer p1,p2;//p1、p2为pointer类型的指针变量

本文最后

这已经是《C语言程序设计》系列的第九篇文章了,据我了解,最近新关注我的小伙伴都是为了研究生考试或者期末考试,所以我来发起一个投票,统计一下本系列文章结束后大家是否需要讲解课本的课后题、期末考试题或者研究生考试真题,请大家按照自己的需求如实填写。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-10-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 hahaCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • “ 关注hahaCoder 获取最新资讯”
  • 前言
  • 9.1 定义和使用结构体变量
    • 9.1.1 自己建立结构体类型
      • 9.1.2 定义结构体类型变量
        • 9.1.3 结构体变量的初始化和引用
        • 9.2 使用结构体数组
          • 9.2.1 定义结构体数组
            • 9.2.2 结构体数组的应用举例
            • 9.3 结构体指针
              • 9.3.1 指向结构体变量的指针
                • 9.3.2 指向结构体数组的指针
                  • 9.3.3 用结构体变量和结构体变量的指针作函数参数
                  • 9.4 用指针处理链表
                    • 9.4.1 什么是链表
                      • 9.4.2 建立简单的静态链表
                        • 9.4.3 建立动态链表
                          • 9.4.4 输出链表
                          • 9.5 共用体类型
                            • 9.5.1 什么是共用体类型
                              • 9.5.2 引用共用体变量的方式
                                • 9.5.3 共用体类型数据的特点
                                • 9.6 使用枚举类型
                                • 9.7 用typedef声明新类型
                                • 本文最后
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档