• C语言学习之路(基础篇)—— 复合类型(自定义类型)


    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

    结构体

    1) 概述

    数组:描述一组具有相同类型数据的有序集合,用于处理大量相同类型的数据运算。

    结构体:将多个相同或不同类型的数据存在在一块连续的内存空间中。

    有时我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别/年龄/地址等属性。显然单独定义以上变量比较繁琐,数据不便于管理。

    语言中给出了另一种构造数据类型——结构体。
    在这里插入图片描述

    2) 结构体变量的定义和初始化

    定义结构体变量的方式:

    • 先声明结构体类型再定义变量名
    • 在声明类型的同时定义变量
    • 直接定义结构体类型变量(无类型名)

    在这里插入图片描述

    结构体类型和结构体变量关系:

    • 结构体类型:指定了一个结构体类型,它相当于一个模型,但其中并无具体数据,系统对之也不分配实际内存单元。
    • 结构体变量:系统根据结构体类型(内部成员状况)为之分配空间。

    示例1:定义一个结构体数据类型

    // 定义一个结构体数据类型
    // 关键字 struct 代表这个是一个结构体类型,
    // stu   是这个结构的名字
    // 整个结构体的类型是   struct  stu
    // 结构体类型struct  stu   {}中是结构体的成员,一个有3个成员,每个成员的类型可以是
    // 任意的类型
    // 定义结构体类型时,{}后面记得加分号
    // 注意定义结构struct  stu,它只是一个类型,一个模板,没有空间,不可以给结构体成员赋值
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    }; 
    int main()
    {
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    示例2:定义结构体变量

    // 第一种常用定义方式
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    }a; //定义类型时,同时定义了一个结构体变量,相当于struct  stu a;
    
    struct stu2
    {
    	int id;
    	int age;
    	char name[128];
    }a,b; //定义类型时,同时定义了两个结构体变量,相当于struct  stu a,b;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    // 第二种常用定义方式(用的最多)
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    };
    struct  stu c;
    int main()
    {
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    // 第三种常用定义方式(用的很少)
    struct
    {
    	int id;
    	int age;
    	char name[128];
    }a;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例3:结构体变量的初始化

    //结构体类型的定义
    struct stu
    {	
    	int id;
    	int age;
    	char name[128];
    };
    
    //先定义类型,再定义变量(常用)
    struct stu s1 = { 1, 18, "cdtaogang" };
    
    
    //定义类型同时定义变量
    struct stu2
    {	
    	int id;
    	int age;
    	char name[128];
    }s2 = { .age=22 }; // 给部分成员初始化,其他成员内容为0
    
    struct
    {	
    	int id;
    	int age;
    	char name[128];
    }s3 = { "yuri", 25 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3) 结构体成员的使用

    示例1:通过结构体变量操作结构体成员,使用点域.操作

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    // 定义一个结构体数据类型
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    }a; //定义类型时,同时定义了一个结构体变量,相当于struct  stu a;
    struct  stu b;
    int main()
    {	
    	//struct  stu c = {1,20,"cdtaogang"};
    	//struct  stu c = { .age=20 };//给部分成员初始化,其他成员内容为0
    	struct  stu d;
    	//如何给结构体成员赋值(如何操作结构体成员)
    	//通过结构体变量操作结构体成员,使用点域.操作
    	d.id = 2;
    	d.age = 20;
    	//d.name = "cdtaogang"; // error 数组名是一个常量,不能被赋值
    	strcpy(d.name , "cdtaogang"); 
    	printf("%d %d %s\n",d.id,d.age,d.name);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    示例2:通过结构体的地址操作结构体成员,使用指向->操作

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    // 定义一个结构体数据类型
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    }a; //定义类型时,同时定义了一个结构体变量,相当于struct  stu a;
    struct  stu b;
    int main()
    {	
    	struct  stu d;
    	// 通过结构体的地址操作结构体成员,使用->
    	(&d)->id = 3;
    	(&d)->age = 21;
    	strcpy((&d)->name, "cdtaogang");
    	printf("%d %d %s\n", (&d)->id, (&d)->age, (&d)->name);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    4) 结构体数组

    结构体数组:是一个数组,数组的每一个元素都是结构体

    在这里插入图片描述

    示例:定义一个结构体数组

    #include 
    
    
    struct stu
    {	
    	int id;
    	int age;
    	char name[128];
    };
    
    int main()
    {	
    	// 定义一个结构体数组,结构体数组有5个元素,每个元素是struct stu类型
    	struct stu data[5] = { {1,20,"laowang"},{2,21,"lihao"},{3,22,"cdtaogang"},{4,23,"zhaoqiang"},{5,24,"wangwu"} };
    	
    	for (int i = 0; i < sizeof(data)/sizeof(data[0]); i++)
    	{
    		printf("%d %d %s\n", data[i].id, data[i].age, data[i].name);
    	}
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    输出结果
    1 20 laowang
    2 21 lihao
    3 22 cdtaogang
    4 23 zhaoqiang
    5 24 wangwu
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    案例:统计学生成绩

    #include 
    
    //统计学生成绩
    struct stu2
    {
    	int num;
    	char name[20];
    	char sex;
    	float score;
    };
    
    int main()
    {
    	//定义一个含有5个元素的结构体数组并将其初始化
    	struct stu2 boy[5] = {
    		{ 101, "Li ping", 'M', 45 },
    		{ 102, "Zhang ping", 'M', 62.5 },
    		{ 103, "He fang", 'F', 92.5 },
    		{ 104, "Cheng ling", 'F', 87 },
    		{ 105, "Wang ming", 'M', 58 } };
    
    	int i = 0;
    	int c = 0;
    	float ave, s = 0;
    	for (i = 0; i < 5; i++)
    	{
    		s += boy[i].score;	//计算总分
    		if (boy[i].score < 60)
    		{
    			c += 1;		//统计不及格人的分数
    		}
    	}
    
    	printf("s=%f\n", s);//打印总分数
    	ave = s / 5;					//计算平均分数
    	printf("average=%f\ncount=%d\n\n", ave, c); //打印平均分与不及格人数
    
    	for (i = 0; i < 5; i++)
    	{
    		printf(" name=%s,  score=%f\n", boy[i].name, boy[i].score);
    		// printf(" name=%s,  score=%f\n", (boy+i)->name, (boy+i)->score);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    5) 结构体套结构体

    示例:结构体套结构体

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    };
    
    struct cls_stu
    {
    	/*int id;
    	int age;
    	char name[128];*/
    	struct stu s;
    	char subject[128];
    };
    
    int main()
    {
    	struct cls_stu cs;
    	cs.s.id = 1;
    	cs.s.age = 20;
    	strcpy(cs.s.name, "cdtaogang");
    	strcpy(cs.subject, "c/c++");
    	printf("id=%d, age=%d, name=%s, subject=%s", cs.s.id, cs.s.age, cs.s.name, cs.subject);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    输出结果
    id=1, age=20, name=cdtaogang, subject=c/c++
    
    • 1
    • 2

    6) 结构体赋值

    示例1:第一种方法

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    
    
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    };
    
    void memcpy_str(struct stu *x, struct stu* y)
    {
    	memcpy(x, y, sizeof(*x));
    
    }
    
    int main()
    {
    	struct stu a;
    	struct stu b = { 1, 22, "cdtaogang" };
    	//memcpy(&a, &b, sizeof(a));
    	memcpy_str(&a, &b); //将上面改为函数调用实现形参改变实参的值
    	printf("%d %d %s\n", a.id, a.age, a.name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    示例2:第二种方法

    int main()
    {
    	struct stu a;
    	struct stu b = { 1, 22, "cdtaogang" };
    	// 第一种方法
    	//memcpy(&a, &b, sizeof(a));
    	//memcpy_str(&a, &b);
    	// 第二种方法
    	a.id = b.id;
    	a.age = b.age;
    	strcpy(a.name, b.name);
    	printf("%d %d %s\n", a.id, a.age, a.name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    示例3:第三种方法

    int main()
    {
    	struct stu a;
    	struct stu b = { 1, 22, "cdtaogang" };
    	// 第一种方法
    	//memcpy(&a, &b, sizeof(a));
    	//memcpy_str(&a, &b);
    	// 第二种方法
    	/*a.id = b.id;
    	a.age = b.age;
    	strcpy(a.name, b.name);*/
    	// 第三种方法
    	// a = b 内核实现的原理就是memcpy(&a, &b, sizeof(a));
    	a = b; // 相同类型的变量是可以相互赋值
    	printf("%d %d %s\n", a.id, a.age, a.name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    7) 结构体和指针*

    7.1 指向普通结构体变量的指针

    示例:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    #include 
    
    
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    };
    
    int main()
    {
    	//struct stu* p; // error 野指针 没有初始化,指向随机
    	// 第一种方式
    	struct stu s;
    	struct stu* p = &s;
    	(*p).id = 1;
    	(*p).age = 20;
    	strcpy((*p).name,"cdtaogang");
    
    	printf("(*p).id=%d, (*p).age=%d, (*p).name=%s", (*p).id, (*p).age, (*p).name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    输出结果
    (*p).id=1, (*p).age=20, (*p).name=cdtaogang
    
    • 1
    • 2

    7.2 堆区结构体变量

    示例:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    #include 
    
    
    struct stu
    {
    	int id;
    	int age;
    	char name[128];
    };
    
    int main()
    {
    	//struct stu* p; // error 野指针 没有初始化,指向随机
    	// 第一种方式
    	/*struct stu s;
    	struct stu* p = &s;*/
    	// 第二种方式
    	struct stu* p = malloc(sizeof(struct stu));
    	p->id = 1;
    	p->age = 20;
    	strcpy(p->name, "cdtaogang");
    
    	printf("p->id=%d, p->age=%d, p->name%s\n", p->id, p->age, p->name);
    	printf("(*p).id=%d, (*p).age=%d, (*p).name=%s", (*p).id, (*p).age, (*p).name);
    	
    	free(p);
    	p = NULL;
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    输出结果
    p->id=1, p->age=20, p->namecdtaogang
    (*p).id=1, (*p).age=20, (*p).name=cdtaogang
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    7.3 结构体套一级指针

    示例1:

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    #include 
    
    
    struct std
    {	
    	int age;
    	char* name; //一级指针
    };
    
    int main() 
    {
    	struct std* p = (struct std*)malloc(sizeof(struct std));
    	p->age = 18;
    	p->name = "cdtaogang";
    
    	printf("%d %s\n", p->age, p->name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    输出结果
    18 cdtaogang
    
    • 1
    • 2

    示例2:

    struct std
    {	
    	int age;
    	char* name; //一级指针
    };
    
    int main() 
    {
    	struct std* p = (struct std*)malloc(sizeof(struct std));
    	p->age = 18;
    	//p->name = "cdtaogang";
    	strcpy(p->name, "cdtaogang"); // error 野指针 p没有指向 相当于 char *name; strcpy(name, "cdtaogang")一个道理
    
    	printf("%d %s\n", p->age, p->name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    在这里插入图片描述

    示例3:

    struct std
    {	
    	int age;
    	char* name; //一级指针
    };
    
    int main() 
    {
    	struct std* p = (struct std*)malloc(sizeof(struct std));
    	p->age = 18;
    	//p->name = "cdtaogang"; // ok
    	p->name = (char*)malloc(128);
    	strcpy(p->name, "cdtaogang"); // error 野指针 p没有指向
    
    	printf("%d %s\n", p->age, p->name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    输出结果
    18 cdtaogang
    
    • 1
    • 2

    示例4:简化分析p->name = "cdtaogang";strcpy(p->name, "cdtaogang");两种方式,这里的name在以下示例以p来表示

    // 正确示例
    int main()
    {
    	char* p;
    	p = "cdtaogang";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    // 错误示例
    int main()
    {
    	int* p;
    	strcpy(p, "cdtaogang");// 将cdtaogang的内容拷贝到p所指向的空间(地址)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    // 正确示例
    int main()
    {
    	char* p;
    	p = (int*)malloc(128);
    	strcpy(p, "cdtaogang");// 将cdtaogang的内容拷贝到p所指向的空间(地址)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    示例5:结构体套结构体一级指针

    struct s
    {
    	int a;
    };
    struct std
    {	
    	int age;
    	char* name; //一级指针
    	struct s* num; // 指针需要申请开辟空间
    	//struct s num2; // 变量不需要申请开辟空间
    };
    
    int main()
    {
    	struct std* p = (struct std*)malloc(sizeof(struct std));
    	p->age = 20;
    
    	p->name = (char*)malloc(128);
    	strcpy(p->name, "cdtaogang");
    	//p->num2.a = 100;  // num2是变量用.不能用->
    	p->num->a = 200; // error  num是野指针,不能直接赋值给num所指向的空间
    
    	printf("%d %s\n", p->age, p->name);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    解决方法一样申请开辟空间即可

    struct s
    {
    	int a;
    };
    struct std
    {	
    	int age;
    	char* name; //一级指针
    	struct s* num; // 指针需要申请开辟空间
    	//struct s num2; // 变量不需要申请开辟空间
    };
    
    int main()
    {
    	struct std* p = (struct std*)malloc(sizeof(struct std));
    	p->age = 20;
    
    	p->name = (char*)malloc(128);
    	strcpy(p->name, "cdtaogang");
    	//p->num2.a = 100;  // num2是变量用.不能用->
    	//p->num->a = 200; // error  num是野指针,不能直接赋值给num所指向的空间
    	p->num = (struct s*)malloc(sizeof(struct s));
    	p->num->a = 200;
    
    	printf("%d %s %d\n", p->age, p->name, p->num->a);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    释放空间,从里往外释放,有多少个malloc就释放free多少个(p的空间是定义的时候就有的 ,而p指向的空间是malloc之后才有的,即才有了age、name、num的空间而name和num指向的空间是malloc之后才有的

    int main()
    {
    	struct std* p = (struct std*)malloc(sizeof(struct std));
    	p->age = 20;
    
    	p->name = (char*)malloc(128);
    	strcpy(p->name, "cdtaogang");
    	//p->num2.a = 100;  // num2是变量用.不能用->
    	//p->num->a = 200; // error  num是野指针,不能直接赋值给num所指向的空间
    	p->num = (struct s*)malloc(sizeof(struct s));
    	p->num->a = 200;
    
    	printf("%d %s %d\n", p->age, p->name, p->num->a);
    
    	free(p->name);
    	free(p->num);
    	free(p);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    8) 结构体做函数参数*

    8.1 结构体普通变量做函数参数

    示例:结构体普通变量做函数参数

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include 
    
    //结构体类型的定义
    struct stu
    {
    	char name[50];
    	int age;
    };
    
    //函数参数为结构体普通变量
    void set_stu(struct stu tmp)
    {
    	strcpy(tmp.name, "cdtaogang");
    	tmp.age = 18;
    	printf("tmp.name = [%s], tmp.age = [%d]\n", tmp.name, tmp.age);
    }
    
    int main()
    {
    	struct stu s = { 0 };
    	set_stu(s); //值传递
    	printf("s.name = [%s], s.age = [%d]\n", s.name, s.age);
    
    	return 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    输出结果
    tmp.name = [cdtaogang], tmp.age = [18]
    s.name = [], s.age = [0]
    
    • 1
    • 2
    • 3

    8.2 结构体指针变量做函数参数

    示例:结构体指针变量做函数参数

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include 
    
    //结构体类型的定义
    struct stu
    {
    	char name[50];
    	int age;
    };
    
    //函数参数为结构体指针变量
    void set_stu_pro(struct stu* tmp)
    {
    	strcpy(tmp->name, "cdtaogang");
    	tmp->age = 18;
    	printf("tmp->name = [%s], tmp->age = [%d]\n", tmp->name, tmp->age);
    }
    
    int main()
    {
    	struct stu s = { 0 };
    	set_stu_pro(&s); //地址传递
    	printf("s.name = [%s], s.age = [%d]\n", s.name, s.age);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    输出结果
    tmp->name = [cdtaogang], tmp->age = [18]
    s.name = [cdtaogang], s.age = [18]
    
    • 1
    • 2
    • 3

    8.3 结构体数组名做函数参数

    示例:结构体数组名做函数参数

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include 
    
    
    struct stu
    {
    	
    	int id;
    	char name[128];
    
    };
    //void set_tmp(struct stu tmp[5], int n)
    void set_tmp(struct stu *p, int n)
    {
    	for (int i = 0; i < n; i++)
    	{	
    		// 第一种方式用点域
    		(*(p + i)).id = 22;
    		p[i].id = 22; // 上面的简写
    		// 第二种方式用指向
    		//(p + i)->id = 22;
    		char buf[128];
    		sprintf(buf, "%s%d", "cdtaoang", i+1);
    		strcpy(p[i].name, buf);
    		printf("p[%d].id = %d, p[%d].name = %s\n", i, p[i].id, i, p[i].name);
    	}
    }
    
    int main()
    {
    
    	struct stu tmp[5] = { 0 };
    	int n = sizeof(tmp) / sizeof(tmp[0]);
    	set_tmp(tmp, n); // tmp = &tmp[0]
    	printf("\n");
    	for (int i = 0; i < n; i++)
    	{
    		printf("tmp[%d].id = %d, tmp[%d].name = %s\n", i, tmp[i].id, i, tmp[i].name);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    在这里插入图片描述

    8.4 const修饰结构体指针形参变量

    示例:const修饰结构体指针形参变量

    #include
    
    
    struct stu
    {
    	int id;
    	char name[128];
    };
    
    int main()
    {
    	struct stu a;
    	struct stu b;
    	struct stu const *p = &a;
    	// p->id = 10; // error  const修饰的是*,不能通过指针p去修改p指向的那块空间里面内容(指向)
    
    	struct stu * const p2 = &a;
    	p2->id = 20; // ok
    	//p2 = &b; // error const修饰的是指针变量p, 不能修改变量p本身的内容(指向)
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    共用体(联合体)

    • 联合union是一个能在同一个存储空间存储不同类型数据的类型;
    • 联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体;
    • 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用;
    • 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖;
    • 共用体变量的地址和它的各成员的地址都是同一地址。

    1) 共用体的定义和初始化

    示例1:定义一个共用体数据类型

    union test
    {
    	char a;
    	short b;
    	int c;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例2:定义共用体变量,跟结构体定义方式一样

    union test
    {
    	char a;
    	short b;
    	int c;
    }tmp;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    union test
    {
    	char a;
    	short b;
    	int c;
    };
    union test tmp;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    union
    {
    	char a;
    	short b;
    	int c;
    }tmp;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例3:共用体变量的初始化(共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖

    #include 
    
    
    union test
    {
    	char a;
    	short b;
    	int c;
    };
    
    int main()
    {	
    	union test tmp;
    	tmp.a = 0x01;
    	tmp.b = 0x0a0b;
    	tmp.c = 0x01020304;
    	
    	printf("tmp.a = %x\n", tmp.a); // 04
    	printf("tmp.b = %x\n", tmp.b); // 0304
    	printf("tmp.c = %x\n", tmp.c); // 01020304
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    #include 
    
    
    union test
    {
    	char a;
    	short b;
    	int c;
    };
    
    int main()
    {	
    	union test tmp;
    	tmp.a = 0x01;
    	tmp.c = 0x01020304;
    	tmp.b = 0x0a0b;
    	
    	printf("tmp.a = %x\n", tmp.a); // 0b
    	printf("tmp.b = %x\n", tmp.b); // 0a0b
    	printf("tmp.c = %x\n", tmp.c); // 01020a0b
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    示例4:共用体的大小

    printf("sizeof(tmp)=%d", sizeof(tmp));  //sizeof(tmp)=4 即 sizeof(int)=4 联合体所占的内存长度等于其最长成员的长度倍数
    
    • 1

    2) 共用体判断大小端

    小端: 低位存低地址,高位存高地址(大型服务器)
    大端: 低位存高地址,高位存低地址(小型计算机)

    在这里插入图片描述

    示例:共用体判断大小端

    #include 
    
    
    union test
    {
    	short b;
    	char buf[2];
    };
    
    int main()
    {
    	union test tmp;
    	tmp.b = 0x0102;
    
    	if (tmp.buf[0] == 0x01)
    	{
    		printf("大端\n");
    	}
    	else
    	{
    		printf("小端\n");
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    输出结果
    小端
    
    • 1
    • 2

    枚举

    枚举: 将枚举类型的变量的值一一列举出来,变量的值只限于列举出来的值的范围内。

    枚举类型定义:

    enum  枚举名
    {
    	枚举值表
    };
    
    • 1
    • 2
    • 3
    • 4
    • 在枚举值表中应列出所有可用值,也称为枚举元素。
    • 枚举值是常量,不能在程序中用赋值语句再对它赋值。
    • 举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2 …

    1) 枚举定义

    示例1:为了避免需要多次定义宏,C语言提供了枚举

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #define Mon 1
    #define Tue 2
    #define Wed 3
    
    
    int main()
    {	
    	int num;
    	scanf("%d", &num);
    
    	if (Mon == num)
    	{
    		printf("游泳\n");
    	}
    	else if (Tue == num)
    	{
    		printf("跑步\n");
    	}
    	else if (Wed == num)
    	{
    		printf("游戏\n");
    	}
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    // 枚举定义
    // 默认枚举里面的值从0开始
    enum week
    {
    	Mon,
    	Tue,
    	Wed
    };
    
    int main()
    {	
    	printf("%d %d %d", Mon, Tue, Wed); // 0 1 2
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2) 枚举赋值

    示例2:枚举赋值

    enum week
    {
    	Mon=1,
    	Tue,
    	Wed
    };
    
    int main()
    {	
    	printf("%d %d %d", Mon, Tue, Wed); // 1 2 3
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    enum week
    {
    	Mon,
    	Tue=5,
    	Wed
    };
    
    int main()
    {	
    	printf("%d %d %d", Mon, Tue, Wed); // 0 5 6
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3) 定义枚举变量

    示例1:先定义枚举类型,再定义枚举变量

    enum week
    {
    	Mon,
    	Tue=5,
    	Wed
    };
    
    int main()
    {	
    	enum week day = Wed; //给枚举变量 day 赋值,值就是Wed枚举元素
    	printf("%d %d %d", Mon, Tue, Wed); // 0 5 6
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    示例2:定义枚举类型的同时定义枚举变量

    enum week
    {
    	Mon,
    	Tue=5,
    	Wed
    }day;// 表示 定义了一个枚举类型 enum week,同时定义了一个变量 day(类型是 enum week)
    
    int main()
    {	
    	day = Wed; //给枚举变量 day 赋值,值就是某个枚举元素
    	printf("%d %d %d", Mon, Tue, Wed); // 0 5 6
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    示例3:省略枚举名称,直接定义枚举变量

    ```c
    enum
    {
    	Mon,
    	Tue=5,
    	Wed
    }day;//这样使用枚举,该枚举类型只能使用一次
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    案例:使用枚举实现#define false 0 #define true 1

    #include 
    
    enum weekday
    {
    	sun = 2, mon, tue, wed, thu, fri, sat
    } ;
    
    enum bool
    {
    	flase, true
    };
    
    int main()
    {	
    	// 先定义枚举类型,再定义枚举变量
    	enum weekday a, b, c;
    	a = sun;
    	b = mon;
    	c = tue;
    	printf("%d,%d,%d\n", a, b, c);
    
    	enum bool flag;
    	flag = true;
    
    	if (flag == 1)
    	{
    		printf("flag为真\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    typedef

    typedefC语言的关键字,作用是为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型

    • #define不同,typedef仅限于数据类型,而不是能是表达式或具体的值
    • #define发生在预处理,typedef发生在编译阶段

    示例1:使用typedef起别名

    #include 
    
    
    typedef int u32;
    
    struct stu
    {
    	int id;
    	int age;
    };
    typedef struct stu ST;
    int main()
    {
    	int a = 10;
    	u32 b = 10;
    	ST tmp;
    	tmp.id = 2;
    	tmp.age = 20;
    	printf("%d %d\n", sizeof(a), sizeof(b));
    	printf("%d %d\n", tmp.id, tmp.age);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    输出结果
    4 4
    2 20
    
    • 1
    • 2
    • 3

    示例2:宏与typedef起别名

    #include 
    #define CHAR char
    typedef char CHAR32;
    
    int main()
    {
    	CHAR a;
    	CHAR32 b;
    
    	a = 10;
    	b = 20;
    	printf("%d %d\n", sizeof(a), sizeof(b));
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    输出结果
    1 1
    
    • 1
    • 2

    示例3:使用宏起别名存在的问题和风险

    #include 
    #define CHAR char*
    typedef char* CHAR32;
    
    int main()
    {
    	CHAR x, y;  // char *x,y;
    	CHAR32 j, k; // char *j,*k;
    	printf("%d %d\n", sizeof(x), sizeof(y));
    	printf("%d %d\n", sizeof(j), sizeof(k));
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    输出结果
    4 1
    4 4
    
    • 1
    • 2
    • 3

    在实际编程中,取别名广泛应用,如下图所示查看VS编译器中size_t类型其实就是int类型

    在这里插入图片描述

  • 相关阅读:
    TinyWebServer整体流程
    leetcode day05 加一
    自定义MVC01
    【算法题】309. 买卖股票的最佳时机含冷冻期
    Qt状态机框架
    vue2.0 监听用户无操作页面停留时长然后弹窗提示
    Java之spring新手教程(包教包会)
    WTM 增加IOT 大屏展示界面页面
    AI二次开发C#变量与数据集
    每日一学————基本配置和管理
  • 原文地址:https://blog.csdn.net/qq_41782425/article/details/128010399