结构体

为什么要使用结构体?
变量:内置数据类型,但是相对独立,缺乏联系
数组:可以存储多个变量,但是变量类型必须一致
想要存储类型不同但是互相之间关联的数据

结构体的声明

struct student{
    char name[20];
    char sex;
    int age;
    char job[40];
    char address[40];
};

结构体声明的一般形式:

struct 结构体名{  
    数据类型 成员变量名1;  
    ...
};

结构体变量声明的一般形式:

struct 结构体名 变量名;

也可以结合结构体声明和变量声明:

struct student{
    char name[20];
    char sex;
    ...
}stu1, stu2;

stu1的内存大小是其所有成员变量的总大小,stu2的内存大小也是其所有成员变量的总大小。
并且stu1和stu2是两个结构体变量,它们在内存中是独立的。

结构体类型的嵌套定义:

// birthday是student的成员变量
struct student{
    char name[20];
    char sex;
    struct birthday{
        int year;
        int month;
        int day;
    };
};

//先声明birthday,再声明student
struct birthday{
    int year;
    int month;
    int day;
};
struct student{
    char name[20];
    char sex;
    struct birthday birthday;
};

//结构体的自引用
struct student{
    char name[20];
    char sex;
    struct student *next;//指向下一个结点的指针
};

结构体变量的赋值

struct student{
    char name[20];
    char sex;
    int age;
    char job[40];
    long num;
    char address[40];
};

//方法1:程序内赋值
int main(){
    struct student stu;
    strcpy(stu.name,"张三");
    stu.sex='男';
    stu.age=20;
    strcpy(stu.job,"学生");
    stu.num=123456789;
    strcpy(stu.address,"北京");
}

//方法2:从键盘输入
int main(){
    struct student stu;
    printf("请输入姓名:");
    scanf("%s",stu.name);
    printf("请输入性别:");
    scanf(" %c",&stu.sex);
    printf("请输入年龄:");
    scanf("%d",&stu.age);
    printf("请输入工作:");
    scanf("%s",stu.job);
    printf("请输入学号:");
    scanf("%d",&stu.num);
    printf("请输入家庭住址:");
    scanf("%s",stu.address);
}

同时,stu1=stu2是合法的,其结果是将stu2中所有元素的值赋给stu1

需要注意的是,结构体变量之间不能直接比较,只能比较其元素

结构体数组

结构体数组的定义的形式:

struct student{
    char name[20];
    int num;
    char address[20];
    ...
};
struct student stu[5];
for (int i = 0; i < 5; i++){
    scanf("%s %d %s",stu[i].name,&stu[i].num,stu[i].address);
}

似乎少了什么东西……

指向结构体变量的指针

指针变量指向任一与指针变量类型一致的变量存储区域,同样可以定义指针变量来指向结构体变量

定义指针变量p1,p2,可用如下方式指向结构体类型变量:
p1=&stu1;
p2=

指向结构体变量的指针访问结构体成员: 结构体指针变量名 -> 成员变量名
p1 -> name

(*结构体指针变量名).成员变量名
(*p1).name

结构体与函数

C语言允许使用结构体作为函数的参数,将结构体成员逐个复制到形参中

将实参结构体变量成员的值赋给形参结构体变量的成员,是单向的值传递。后续对形参的修改,不会影响实参。

函数的返回值也可以是结构体类型

指向结构体的指针变量作为函数参数,是将实参结构体数组或结构体变量的起始地址传递给形参指针变量,这样可以提高函数的效率。

void func_1(struct student stu){//形参是结构体变量
    ...
}

void func_2(struct student *p){//形参是结构体指针变量
    ...
}

void func_3(struct student stu[]){//形参是结构体数组
    ...
}

结构体类型和普通类型的相似性

结构体变量的声明和定义与普通类型声明和定义相似

例如:

对整形类型变量的声明和定义:

int a;
int b[5];
int *c;
int *d[5];

相似的,对结构体类型变量的声明和定义:

struct student{
    char name[20];
    char sex;
    int age;
    char job[40];
    char address[40];
    ...
};
struct student stu1;
struct student stu2[5];
struct student *p1;
struct student *p2[5];//数组指针

应用例:链表

链表是一种特殊的线性表,它不是连续存储的,而是由一系列的结点组成,每个结点包含一个数据元素和指向下一个结点的指针。

创建链表

一般步骤:

定义链表的数据结构
定义头节点,置指针域为空,表示创建了一个空表
申请一个结点储存单元
将新结点的指针成员设为空。若是空表将新结点接到表头,若是非空表,将新结点接到表尾
循环,直到无新结点需要接入

struct student{
    char name[20];
    int data;
    struct student *next;
}

struct student *create(struct student *head){
    
}