自定义数据类型一 、自定义数据类型1、枚举1.1 定义枚举枚举使用 enum 关键字来定义,枚举名称和枚举元素名称都是标识符,定义一个枚举就是定义了一种枚举数据类型,语法如下:
enum 枚举名称?
{
? ? 枚举元素1,
? ? 枚举元素2,
? ? ...
? ? 枚举元素N
};枚举常量枚举元素也称为枚举成员或枚举常量,具有如下特点:(1)枚举元素的值必须在同一枚举中是唯一的(2)枚举元素的值必须是整数类型,通常是int(3)如果没有为枚举元素指定值,编译器会自动为它们分配值,从0开始,依次递增。(4)定义枚举的时候也可以为枚举元素自定义值,需保证唯一性和整型类型。enum Bool
{
? ? FALSE,//默认0
? ? TRUE//默认1
};
// // 枚举类似
// const int FALSE=0;
// const int TRUE=1;
// 定义枚举类型,表示星期一到星期天,枚举元素的值自动分配,从0到6。
enum Weekday
{
? ? MONDAY,
? ? TUESDAY,
? ? WEDNESDAY,
? ? THURSDAY,
? ? FRIDAY,
? ? SATURDAY,
? ? SUNDAY
};
// 定义枚举类型,表示一月到十二月。 给枚举元素JANUARY设置了值1,后面的枚举元素从1开始自增,分别是 1到12
enum Month?
{
? ? JANUARY = 1,
? ? FEBRUARY,
? ? MARCH,
? ? APRIL,
? ? MAY,
? ? JUNE,
? ? JULY,
? ? AUGUST,
? ? SEPTEMBER,
? ? OCTOBER,
? ? NOVEMBER,
? ? DECEMBER
};
// 定义枚举类型,表示北京地区一年四季的平均温度。为每个枚举元素都设置值,自己设置的值需要保证唯一性和整型类型
enum Season?
{
? ? SPRING = 18,
? ? SUMMER = 30,
? ? AUTUMN = 20,
? ? WINTER = -5
};1.2 枚举变量定义变量时指定类型是我们所定义的枚举类型,该变量称为枚举变量。枚举变量的值应该是枚举类型中的枚举常量中的一个,不能是其他值(自我约束)。(1)第一种:先定义枚举类型,再定义枚举变量。// 定义枚举类型
enum DAY?
{
? ? MON = 1,?
? ? TUE,?
? ? WED,?
? ? THU,?
? ? FRI,?
? ? SAT,?
? ? SUN
};?
// 使用枚举类型定义枚举变量
enum DAY day;(2)第二种:定义枚举类型的同时声明枚举变量。enum DAY?
{
? ? MON = 1,?
? ? TUE,?
? ? WED,?
? ? THU,?
? ? FRI,?
? ? SAT,?
? ? SUN
} day=TUE,day2=MON;(3)第三种:定义枚举类型的同时声明枚举变量,且省略枚举名称。enum?
{
? ? MON = 1,?
? ? TUE,?
? ? WED,?
? ? THU,?
? ? FRI,?
? ? SAT,?
? ? SUN
} day;
#include
int main()
{
? ? // 定义枚举类型(也有作用域限制)
? ? enum Weekday
? ? {
? ? ? ? MONDAY,
? ? ? ? TUESDAY,
? ? ? ? WEDNESDAY,
? ? ? ? THURSDAY,
? ? ? ? FRIDAY,
? ? ? ? SATURDAY,
? ? ? ? SUNDAY
? ? };
? ? // 定义枚举变量并赋值
? ? enum Weekday day = WEDNESDAY;
? ? printf("%d \n", day);?
? ? // 修改枚举变量的值
? ? day = FRIDAY;
? ? printf("%d \n", day);?
? ? // 修改枚举变量的值
? ? // 100 并不是枚举常量中的一个,这样做虽然不会报错,但失去了枚举的意义,不建议这么做
? ? day = 100;
? ? printf("%d \n", day);?
? ? return 0;
}
/*
输出结果:
2?
4
100
*/ 指针指向的是枚举变量 enum Weekday *day=&MONDAY2、结构体C语言提供了struct关键字,允许自定义复合数据类型,将不同类型的值组合在一起,这种类型称为结构体(structure)类型。C语言没有其他语言的对象(object)和类(class)的概念,struct 结构很大程度上提供了对象和类的功能。2.1 声明结构体1)格式
构建一个结构体类型的一般形式为:
struct 结构体名
{?
? ? 数据类型1 成员名1; ??
? ? 数据类型2 成员名2;?
? ? ……
? ? 数据类型n 成员名n;
};
// 定义结构体:学生
struct Student
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? enum
? ? {
? ? ? ? MALE,
? ? ? ? FEMALE;
? ? ? ? ELSE
? ? }gender;
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
};
// 定义结构体:通讯录
struct Contacts
{ ? ? ? ? ? ?
? ? char name[50]; ? ? ? ? ?//姓名
? ? int year; ? ? ? ? ? ? ? //年
? ? int month; ? ? ? ? ? ? ?//月
? ? int day; ? ? ? ? ? ? ? ?//日
? ? char email[100]; ? ? ? ?//电子邮箱
? ? char mobile_number[12]; //手机号
};2.2 声明结构体变量1)方式1 先定义结构体,然后再创建结构体变量// 定义结构体
struct Student
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
};
// 定义结构体变量
struct Student stu1,stu2;2)方式2 在定义结构体的同时定义结构体变量// 定义结构体的同时定义 stu1和 stu2 两个变量
struct Student
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
} stu1, stu2;
struct Stu
{
? ? int id;
? ? char *name;
? ? char gender;
? ? char *address;
}stu1={1001,"liming",'f',"ajdcno"},stu2={1002,"zhangsan",'m',"ieuinc"};3)方式3 在定义时也可以不给出结构体名// 不给出结构体的名字
struct
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
} stu1, stu2;2.3 成员的获取和赋值成员是结构体的一个组成部分,一般是基本数据类型、也可以是数组、指针、结构体等。结构体的成员也可以称为属性。结构体和数组类似,也是一组数据的集合,结构体使用点号 . 获取单个成员,可以进行赋值和取值。/**********************************************************************
?* 结构体
?**********************************************************************/
#include
#include
// 定义枚举类型
// enum Gender
// {
// ? ? MALE,
// ? ? FEMALE,
// ? ? ELSE
// };
// 定义结构体类型 描述学生信息(学号、姓名、性别、年龄、成绩、地址)
struct Student
{
? ? int id; ? ? ? ? ? ? ? ? // 学号
? ? char *name; ? ? ? ? ? ? // 姓名
? ? enum
? ? {
? ? ? ? MALE,
? ? ? ? FEMALE,
? ? ? ? ELSE
? ? } gender; ? ? ? ? ? ? ? // 性别
? ? int age; ? ? ? ? ? ? ? ?// 年龄
? ? double score; ? ? ? ? ? // 成绩
? ? char address[40]; ? ? ? // 地址
};
// 定义函数 打印学生信息
void printStuInfo(struct Student stu)
{
? ? // 处理性别信息
? ? char *gender = NULL;
? ? switch (stu.gender)
? ? {
? ? ? ? case MALE: gender = "男"; break;
? ? ? ? case FEMALE: gender = "女"; break;
? ? ? ? case ELSE: gender = "其他"; break;
? ? }
? ? // 打印
? ? printf("学号:%d, 姓名:%s, 性别:%s, 年龄:%d, 成绩:%.2lf, 地址:%s \n", stu.id, stu.name, gender, stu.age, stu.score, stu.address);
}
int main()
{
? ? // 根据结构体类型定义结构体变量
? ? struct Student stu1;
? ? // 先定义结构体变量,对成员挨个初始化赋值, 使用 . 运算符
? ? stu1.id = 1001;
? ? stu1.name = "曹操";
? ? stu1.gender = MALE;
? ? stu1.age = 48;
? ? stu1.score = 28;
? ? // stu1.address = "上海"; ? // 错误:字符数组不能直接用 = 赋值,需通过拷贝字符 / 初始化完成内容设置
? ? //数组名:是「首元素地址常量」,不能用 = 赋值(如 arr = "abc" 错误)
? ? strcpy(stu1.address, "上海");
? ? // 定义结构体变量并初始化赋值
? ? struct Student stu2 = {1002, "刘备", ELSE, 45, 98, "成都"};
? ? // 打印学生信息
? ? printStuInfo(stu1);
? ? printStuInfo(stu2);
? ? printf("\n");
? ? // ---------------------------------------------------
? ? // 定义数组,数组元素都是 struct Student 类型
? ? struct Student stus[3] = {
? ? ? ? {1003, "关羽", ELSE, 45, 98, "成都"},
? ? ? ? {1004, "张飞", ELSE, 45, 98, "成都"},
? ? ? ? {1005, "孙权", FEMALE, 25, 18, "南京"}
? ? };
? ? // 遍历并打印数组信息
? ? for (int i = 0; i < 3; i++)
? ? {
? ? ? ? printStuInfo(stus[i]);
? ? }
? ? return 0;
}
/*
学号:1001, 姓名:曹操, 性别:男, 年龄:48, 成绩:28.00, 地址:上海?
学号:1002, 姓名:刘备, 性别:其他, 年龄:45, 成绩:98.00, 地址:成都?
学号:1003, 姓名:关羽, 性别:其他, 年龄:45, 成绩:98.00, 地址:成都
学号:1004, 姓名:张飞, 性别:其他, 年龄:45, 成绩:98.00, 地址:成都
学号:1005, 姓名:孙权, 性别:女, 年龄:25, 成绩:18.00, 地址:南京
*/2.4 结构体指针结构体指针是指向结构体的指针变量,允许间接访问和操作结构体的成员,它提供了一种方便的方式来处理结构体数据。声明结构体指针的语法格式:
struct 结构体名 *结构体指针变量名;
#include
void addage(struct Student *stu)
{
? ? stu->age++;
? ? //(*stu).age++;都可以
}
int main()
{ ??
? ? // 结构体
? ? struct Student
? ? {
? ? ? ? char *name;
? ? ? ? int age;
? ? ? ? char gender;
? ? };
? ? // 结构体变量
? ? struct Student s = {"张三", 20, 'M'};
? ? // 通过结构体变量访问成员
? ? printf("name=%s,age=%d,gender=%c \n", s.name, s.age, s.gender);
? ? // 声明结构体指针
? ? struct Student *ps = &s;
? ? // 结构体指针通过解引用访问成员,*ps.name,这个不对,.的优先级比*高,因此要加()
? ? printf("name=%s,age=%d,gender=%c\n", (*ps).name, (*ps).age, (*ps).gender);
? ? // 结构体指针使用->访问成员
? ? printf("name=%s,age=%d,gender=%c\n", ps->name, ps->age, ps->gender);
? ??
? ? printf("年龄:%d\n",addage(&s));//年龄增加,如果值传递就不行了
? ? return 0;
}
/*
输出结果:
name=张三,age=20,gender=M?
name=张三,age=20,gender=M
name=张三,age=20,gender=M
*/
/*
总结:如果指针变量p指向一个结构体变量stu,以下3种用法等价:
(1)stu.成员名
(2)(*p).成员名
(3)p->成员名
*/2.5 结构体存储大小成员偏移位置对齐:每个成员的偏移位置一定是自身大小的整数倍(如果成员比基准对齐长度大,按照基准对齐长度偏移)。结构体整体对齐:结构体的总大小一定是基准对齐长度的整倍数。基准对齐长度:从大成员的大小和系统对齐长度之间取较小的一个。32位系统中,默认系统对齐长度是4字节。开发者可以使用 #pragma pack() 设置系统对齐长度。结构体成员是数组:数组的每个元素单独对齐,不作为整体结构体成员还是结构体:1. 计算基准对齐长度,不把作为成员的结构体当做整体,把内部成员取出来进行计算
2. 计算总长度,作为成员的结构体先整体对齐,再与其他成员对齐2.6 共用体有时需要一种数据结构,不同的场合表示不同的数据类型。比如,如果只用一种数据结构表示学生的“成绩”,这种结构就需要有时是整数(80、90),有时是字符(’A’、’B’),有时是浮点数(80.5、60.5)。C语言提供了共用体类型(Union 结构),用来自定义可以灵活变更的数据结构。它内部可以包含各种属性,但同一时间只能有一个属性,因为所有属性都保存在同一个内存地址,后面写入的属性会覆盖前面的属性。这样做的最大好处是节省空间。“共用体”与“结构体”的定义形式相似,但它们的含义是不同的。(1)结构体变量所占内存长度,可以认为是各成员占的内存长度的叠加;每个成员分别占有其自己的内存单元。(2)共用体变量所占的内存长度等于最长的成员的长度;几个成员共用一个内存区。① 定义共同体类型union 类型名称
{
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? ....
}注意: 类型名称和成员名称都需要符合标识符规范共用体体的成员类型可以是任意类型(整数、浮点、数组、指针、枚举、结构体)② 使用共用体类型定义共用体变量第一种方式 先定义类型,再定义变量
第二种方式 同时定义类型和变量
第三种方式 同时定义类型和变量并省略类型名称③ 共同体变量初始化赋值// 先声明共同体变量,再给其中一个成员赋值
union Score sc1;
sc1.a = 'A';
// 同时定义共用体变量并初始化赋值,给第一个成员赋值
union Score sc2 = {'C'};
// 同时定义共用体变量并初始化赋值,给指定成员赋值
union Score sc3 = {.b = 100};④ 共同体变量访问共同体成员使用 .⑤ 共用体指针访问共同体成员使用 ->
/**********************************************************************
?* 共用体
?**********************************************************************/
#include
// 使用共同体定义表示成绩的类型,该类型的数据可以是字母、可以是整数、可以是浮点
union Score
{
? ? char a;
? ? int b;
? ? double c;
};
int main()
{
? ? // 定义共用体变量 类型是 union Score
? ? union Score sc1;
? ? // 给 sc1 的成员赋值 ? 先声明共用体变量,再使用 . 给成员赋值
? ? sc1.a = 'B';
? ? sc1.b = 100;
? ? sc1.c = 98.13;
? ? // 打印
? ? printf("sc1 存储大小:%zu \n", sizeof sc1); // 8
? ? // 输出:sc1 存储大小:8
? ? // 原因:union的大小由最大成员决定,double占8字节
? ? printf("a: %c \n", sc1.a); // 输出:a: ? (乱码)
? ? // 原因:sc1.c = 98.13 覆盖了整个union
? ? // 现在读取的是double数据的第一个字节,不是原来的'B'
? ? printf("b: %d \n", sc1.b); // 输出:b: 一个随机的大整数
? ? // 原因:把double数据的低4字节当作int来解读,结果无意义
? ? printf("c: %.2lf \n\n\n", sc1.c); // 输出:c: 98.13
? ? // 唯一正确的输出,因为这是最后赋值的成员
? ? // 同时定义共用体变量并初始化赋值,给第一个成员赋值
? ? union Score sc2 = {'C'};
? ? printf("a: %c \n", sc2.a);
? ? printf("b: %d \n", sc2.b);
? ? printf("c: %.2lf \n\n\n", sc2.c);
? ? // 同时定义共用体变量并初始化赋值,给指定成员赋值
? ? union Score sc3 = {.b = 100};
? ? printf("a: %c \n", sc3.a);
? ? printf("b: %d \n", sc3.b);
? ? printf("c: %.2lf \n\n\n", sc3.c);?
? ? // 定义指针 指向共用体变量
? ? union Score *sc_ptr = &sc1;
? ? // 共同体指针可以使用 -> 访问成员
? ? printf("c: %.2lf \n", sc_ptr->c);
? ? return 0;
}2.7 typedef#define 类型别名与 typedef 类型别名的区别: ① 执行时机不同:#define在预处理阶段执行;typedef 在程序运行阶段执行。 ② 类型检查:#define只进行简单文本替换不作类型检查;typedef 在编译阶段会进行类型检查。 ③ 作用域:#define设置的别名无作用域的概念;typedef设置的别名具有作用域。① 基本类型别名typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;② 数组别名typedef int Int_array[];//取代变量名或标识符的位置
typedef double Double_array5[5];③ 函数别名typedef double Avg_function(int, int);④ 指针别名// 给指向基本类型数据的指针起别名
typedef int *Int_ptr;
typedef char *String;
// 数组指针起别名
typedef int (*Int_arr_ptr)[];
// 函数指针起别名
typedef double (*Avg_function_ptr)(int, int);⑤ 结构体别名// 5.1 先定义结构体类型,再取别名
struct User
{
? ? char *name;
? ? int age;
};
typedef struct User VipUser;
// 5.2 同时定义结构体类型并取别名
typedef struct Person
{
? ? char *name;
? ? int age;
} Person;
// 5.3 同时定义结构体类型并取别名,且省略结构体类型名(强烈推荐!!)
typedef struct //类型名不要加,不然就是Student就是变量了
{
? ? char *name;
? ? double score;
} Student;⑥ 共用体别名// 6.1 先定义共用体类型,再取别名
// 6.2 同时定义共用体类型和别名
// 6.3 同时定义共用体类型和别名,省略共用体类型名(强烈推荐)
typedef union
{
? ? char a;
? ? double b;
} Score;⑦ 枚举别名// 7.1 先定义枚举类型,再取别名
// 7.2 同时定义枚举类型和别名
// 7.3 同时定义枚举类型和别名,省略共用体类型名(强烈推荐)
typedef enum?
{
? ? MALE,
? ? FEMALE,
? ? ELSE
} Gender;扩展:特性字符数组(char arr[40])字符指针(char *p)本质可写内存块(存储字符)指针变量(存储地址)赋值方式初始化时 = "xxx",后续用 strcpy直接 p = "xxx"(指向字符串常量地址)可修改性数组内容可修改(arr[0] = 'x')指向的字符串常量不可修改(*p = 'x' 错误)存储位置栈区 / 全局数据区(可写)指针变量在栈区,指向只读数据区(字符串常量)长度固定(定义时指定或编译器自动计算)无固定长度,仅存储地址是否能使用scanf可以不可以(有时可以,有时不可)简单说:数组的「指向」不可改,「内容」默认可改;指针的「指向」可改,「内容」能否改看指向的内存权限。(1)数组的「指向」不可改,「内容」默认可改;//数组名是地址常量,不能给数组名赋值新地址
//(比如 char arr[10]; arr = "hello"; 报错,因为试图修改数组的「指向」)。
// 普通数组(可修改内容)
char arr[] = "hello";
arr[0] = 'H'; ?// 合法!内容改为 "Hello"
// const 数组(不可修改内容)
const char arr2[] = "hello";
// arr2[0] = 'H'; ?// 编译报错!const 修饰数组,内容不可改(2)指针的「指向」可改,「内容」能否改看指向的内存权限。//指针变量存储的是地址,可自由指向其他内存(只要类型兼容):
char *p = "hello"; ?// p 指向只读区的 "hello"
char arr[] = "world";
p = arr; ?// 合法!p 改为指向栈区的 arr(修改指向)
//情况 1:指向「只读内存」(字符串常量、const 变量)→ 不能修改内容:
char *p1 = "hello"; ?// 指向只读区的字符串常量
// *p1 = 'H'; ?// 运行报错(段错误)!只读内存不可写
//情况 2:指向「可写内存」(字符数组、堆内存)→ 可以修改内容:
char arr[] = "hello";
char *p2 = arr; ?// p2 指向栈区的可写数组
*p2 = 'H'; ?// 合法!arr 内容改为 "Hello"
//情况 3:const 指针(指向常量的指针)→ 编译期禁止修改内容(语法层面限制):
const char *p3 = "hello"; ?// p3 是「指向常量的指针」
// *p3 = 'H'; ?// 编译报错!语法禁止修改指向的内容
p3 = "world"; ?// 合法!指针指向可修改(const 只限制内容,不限制指向)练习题1、分析输出结果2、理解指针/**********************************************************************
? 有如下二维数组(选做,尽量做)
? ?int nums[3][4] = {
? ? ? ? {10,20,30,40},
? ? ? ? {100,200,300,400},
? ? ? ? {1000,2000,3000,400}
? ?}
? ?实现如下需求:
? ?① 定义指针,将 nums 赋值给该指针
? ?② 定义指针,将 &nums 赋值给该指针
? ?③ 定义指针,将 nums[1] 赋值给该指针
? ?④ 定义指针,将 &nums[1] 赋值给该指针
? ?⑤ 定义指针,将 &nums[1][1] 赋值给该指针
**********************************************************************/
#include
// 任何数组名(无论一维 / 二维),在多数表达式中(如赋值给指针),
//都会隐式转为「该数组首元素的地址」。
int main()
{
? ? // 定义二维数组
? ? int nums[3][4] = {
? ? ? ? {10, 20, 30, 40},
? ? ? ? {100, 200, 300, 400},
? ? ? ? {1000, 2000, 3000, 400}};
? ? // ① 定义指针,将 nums 赋值给该指针 ? ?nums 等同于 &nums[0]
? ? //nums是指向二维数组的整个第0行地址
? ? //nums 是二维数组名(类型 int[3][4])根据数组名隐式转换规则:
? ? //nums 的「元素类型」是 int[4](每个元素是 4 个 int 的数组,即二维数组的 “一行”);
? ? int (*ptr1)[4] = nums; ? ? ?
? ? printf("**ptr1=%d \n", **ptr1);//*ptr1是表示第0行第0个元素的地址
? ? // ② 定义指针,将 &nums 赋值给该指针,&nums 是取得是整个数组的地址
? ? int (*ptr2)[3][4] = &nums;
? ? printf("***ptr2=%d \n", ***ptr2);
? ? // ③ 定义指针,将 nums[1] 赋值给该指针,没有取地址, 等价于 &nums[1][0]?
? ? //nums[1] 是二维数组的「第 1 行」,本质是 int[4] 类型的数组名(一维数组名,对应 “一行 4 个 int”),
? ? //根据数组名隐式转换规则:nums[1] 的「元素类型」是 int(每个元素是单个 int);
? ? //nums[1] 隐式转为「指向该行首元素的指针」—— 首元素是 nums[1][0]
? ? //第1行第0个元素的地址 ?
? ? int *ptr3 = nums[1];
? ? printf("*ptr3=%d \n", *ptr3);
? ? // ④ 定义指针,将 &nums[1] 赋值给该指针,&nums[1] 是取得是整个第1行数组的地址
? ? int (*ptr4)[4] = &nums[1];
? ? printf("**ptr4=%d \n", **ptr4);
? ? // ⑤ 定义指针,将 &nums[1][1] 赋值给该指针
? ? int *ptr5 = &nums[1][1];
? ? printf("*ptr5=%d \n", *ptr5);
? ??
? ? return 0;
}
/*
**ptr1=10?
***ptr2=10?
*ptr3=100
**ptr4=100
*ptr5=200
*/3、小狗案例(1)编写一个Dog结构体,包含name(char *)、age(int)、weight(double)属性。(2)编写一个say函数,返回字符串,方法返回信息中包含所有成员值。(3)在main函数中,创建Dog结构体变量,调用say函数,将调用结果打印输出。#include
// 定义Dog结构体
struct Dog
{
? ? char *name;
? ? int age;
? ? double weight;
};
// say函数,返回字符串,信息中包含所有成员值
char *say(struct Dog dog)
{
? ? // 将这个信息放入到一个字符串(字符数组)
? ? static char info[50]; // 局部静态变量
? ? sprintf(info, "name=%s age=%d weight=%.2f", dog.name, dog.age, dog.weight);
? ? dog.name = "小花";
? ? return info;
}
int main()
{
? ? // 测试
? ? // 定义结构体变量
? ? struct Dog dog;
? ? char *info = NULL;
? ? dog.name = "小黄";
? ? dog.age = 1;
? ? dog.weight = 3.4;
? ? info = say(dog); // 结构体变量默认是值传递
? ? printf("小狗信息:%s \n", info);
? ? printf("main中小狗名字:%s \n", dog.name);
? ? return 0;
}4、盒子案例(1)编程创建一个Box结构体,在其中定义三个成员表示一个长方体的长、宽和高,长宽高可以通过控制台输入。(2)定义一个函数获取长方体的体积(volume)。(3)创建一个结构体指针,打印给定尺寸的长方体的体积。#include
// 定义Box结构体
struct Box
{
? ? double length;
? ? double width;
? ? double height;
};
// 获取立方体体积的函数
double getVolume(struct Box *box)
{
? ? return box->length * box->width * box->height;
}
int main()
{
? ? // 创建结构体变量
? ? struct Box box;
? ? // 创建结构体指针
? ? struct Box *cube = &box;
? ? printf("Enter length: ");
? ? scanf("%lf", &cube->length);
? ? printf("Enter width: ");
? ? scanf("%lf", &cube->width);
? ? printf("Enter height: ");
? ? scanf("%lf", &cube->height);
? ? // 调用函数获取体积并打印
? ? printf("Volume is: %.2f\n", getVolume(cube));
? ? return 0;
}5、景区门票案例/**********************************************************************
?* (1)一个景区根据游人的年龄收取不同价格的门票。
C语言实例href="MAP.MqKo.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.RvOs.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.VzTx.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.Z3X1.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.d7b5.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.hBf9.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.HFjD.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.LpJn.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.PtNr.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.TxRv.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.X1Vz.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.b5Z3.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.f9d7.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.jDhB.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.nHlF.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.rLpJ.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.RPtN.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.VzTx.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Z3X1.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.d7b5.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.hBf9.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.lFjD.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.qJnH.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.uOsM.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.ySwQ.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.2W0U.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.c64Y.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.gAe8.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.kEiC.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.oImG.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.sMqK.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.wQuO.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.0UyS.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.4Y2W.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.8c6a.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.CgAe.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.mGki.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.qKoI.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.uOsM.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.ySwQ.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.2W0U.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.6a4Y.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Ae8c.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.EiCg.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.JnHk.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.NrLp.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.xRvP.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.1VzT.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.5Z3X.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.9d7b.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.DhBf.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.HlFj.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.LpJn.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.PtNr.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.TxRv.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.31Vz.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.7b5Z.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.Bf9d.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.FjDh.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.JnHl.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.NrLp.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.RvPt.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.VzTx.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.Z3X1.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.d7b5.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.ECf9.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.ImGk.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.MqKo.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.QuOs.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.UySw.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Y2W0.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.c6a4.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.gAe8.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.kEiC.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.oImG.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.OsqK.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.SwQu.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.W0Uy.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.a4Y2.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.e8c6.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.iCgA.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.mGkE.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.qKoI.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.uOsM.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.ySwQ.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.Y2WU.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.d6a4.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.hBf9.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.lFjD.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.fzA1.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.tNrL.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.xRvP.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.1VzT.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.5Z3X.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.9d7b.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.jDhB.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.nHlF.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.rLpJ.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.vPtN.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.zTxR.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.3X1V.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.7b5Z.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Bf9d.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.FjDh.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.pnHl.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.tNrL.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.xRvP.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.1VzT.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.6a4X.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Ae8c.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.EiCg.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.ImGk.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.MqKo.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.QuOs.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.0ySw.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.4Y2W.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.8c6a.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.CgAe.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.GkEi.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.KoIm.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.OsMq.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.SwQu.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.W0Uy.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.a4Y2.b2ao5.inFO"循环冗余校验与
enum 枚举名称?
{
? ? 枚举元素1,
? ? 枚举元素2,
? ? ...
? ? 枚举元素N
};枚举常量枚举元素也称为枚举成员或枚举常量,具有如下特点:(1)枚举元素的值必须在同一枚举中是唯一的(2)枚举元素的值必须是整数类型,通常是int(3)如果没有为枚举元素指定值,编译器会自动为它们分配值,从0开始,依次递增。(4)定义枚举的时候也可以为枚举元素自定义值,需保证唯一性和整型类型。enum Bool
{
? ? FALSE,//默认0
? ? TRUE//默认1
};
// // 枚举类似
// const int FALSE=0;
// const int TRUE=1;
// 定义枚举类型,表示星期一到星期天,枚举元素的值自动分配,从0到6。
enum Weekday
{
? ? MONDAY,
? ? TUESDAY,
? ? WEDNESDAY,
? ? THURSDAY,
? ? FRIDAY,
? ? SATURDAY,
? ? SUNDAY
};
// 定义枚举类型,表示一月到十二月。 给枚举元素JANUARY设置了值1,后面的枚举元素从1开始自增,分别是 1到12
enum Month?
{
? ? JANUARY = 1,
? ? FEBRUARY,
? ? MARCH,
? ? APRIL,
? ? MAY,
? ? JUNE,
? ? JULY,
? ? AUGUST,
? ? SEPTEMBER,
? ? OCTOBER,
? ? NOVEMBER,
? ? DECEMBER
};
// 定义枚举类型,表示北京地区一年四季的平均温度。为每个枚举元素都设置值,自己设置的值需要保证唯一性和整型类型
enum Season?
{
? ? SPRING = 18,
? ? SUMMER = 30,
? ? AUTUMN = 20,
? ? WINTER = -5
};1.2 枚举变量定义变量时指定类型是我们所定义的枚举类型,该变量称为枚举变量。枚举变量的值应该是枚举类型中的枚举常量中的一个,不能是其他值(自我约束)。(1)第一种:先定义枚举类型,再定义枚举变量。// 定义枚举类型
enum DAY?
{
? ? MON = 1,?
? ? TUE,?
? ? WED,?
? ? THU,?
? ? FRI,?
? ? SAT,?
? ? SUN
};?
// 使用枚举类型定义枚举变量
enum DAY day;(2)第二种:定义枚举类型的同时声明枚举变量。enum DAY?
{
? ? MON = 1,?
? ? TUE,?
? ? WED,?
? ? THU,?
? ? FRI,?
? ? SAT,?
? ? SUN
} day=TUE,day2=MON;(3)第三种:定义枚举类型的同时声明枚举变量,且省略枚举名称。enum?
{
? ? MON = 1,?
? ? TUE,?
? ? WED,?
? ? THU,?
? ? FRI,?
? ? SAT,?
? ? SUN
} day;
#include
int main()
{
? ? // 定义枚举类型(也有作用域限制)
? ? enum Weekday
? ? {
? ? ? ? MONDAY,
? ? ? ? TUESDAY,
? ? ? ? WEDNESDAY,
? ? ? ? THURSDAY,
? ? ? ? FRIDAY,
? ? ? ? SATURDAY,
? ? ? ? SUNDAY
? ? };
? ? // 定义枚举变量并赋值
? ? enum Weekday day = WEDNESDAY;
? ? printf("%d \n", day);?
? ? // 修改枚举变量的值
? ? day = FRIDAY;
? ? printf("%d \n", day);?
? ? // 修改枚举变量的值
? ? // 100 并不是枚举常量中的一个,这样做虽然不会报错,但失去了枚举的意义,不建议这么做
? ? day = 100;
? ? printf("%d \n", day);?
? ? return 0;
}
/*
输出结果:
2?
4
100
*/ 指针指向的是枚举变量 enum Weekday *day=&MONDAY2、结构体C语言提供了struct关键字,允许自定义复合数据类型,将不同类型的值组合在一起,这种类型称为结构体(structure)类型。C语言没有其他语言的对象(object)和类(class)的概念,struct 结构很大程度上提供了对象和类的功能。2.1 声明结构体1)格式
构建一个结构体类型的一般形式为:
struct 结构体名
{?
? ? 数据类型1 成员名1; ??
? ? 数据类型2 成员名2;?
? ? ……
? ? 数据类型n 成员名n;
};
// 定义结构体:学生
struct Student
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? enum
? ? {
? ? ? ? MALE,
? ? ? ? FEMALE;
? ? ? ? ELSE
? ? }gender;
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
};
// 定义结构体:通讯录
struct Contacts
{ ? ? ? ? ? ?
? ? char name[50]; ? ? ? ? ?//姓名
? ? int year; ? ? ? ? ? ? ? //年
? ? int month; ? ? ? ? ? ? ?//月
? ? int day; ? ? ? ? ? ? ? ?//日
? ? char email[100]; ? ? ? ?//电子邮箱
? ? char mobile_number[12]; //手机号
};2.2 声明结构体变量1)方式1 先定义结构体,然后再创建结构体变量// 定义结构体
struct Student
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
};
// 定义结构体变量
struct Student stu1,stu2;2)方式2 在定义结构体的同时定义结构体变量// 定义结构体的同时定义 stu1和 stu2 两个变量
struct Student
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
} stu1, stu2;
struct Stu
{
? ? int id;
? ? char *name;
? ? char gender;
? ? char *address;
}stu1={1001,"liming",'f',"ajdcno"},stu2={1002,"zhangsan",'m',"ieuinc"};3)方式3 在定义时也可以不给出结构体名// 不给出结构体的名字
struct
{
? ? int id; ? ? ? ? ? // 学号
? ? int age; ? ? ? ? ?// 年龄
? ? char *name; ? ? ? // 姓名
? ? char gender; ? ? ?// 性别
? ? char *address; ? ?// 家庭住址
} stu1, stu2;2.3 成员的获取和赋值成员是结构体的一个组成部分,一般是基本数据类型、也可以是数组、指针、结构体等。结构体的成员也可以称为属性。结构体和数组类似,也是一组数据的集合,结构体使用点号 . 获取单个成员,可以进行赋值和取值。/**********************************************************************
?* 结构体
?**********************************************************************/
#include
#include
// 定义枚举类型
// enum Gender
// {
// ? ? MALE,
// ? ? FEMALE,
// ? ? ELSE
// };
// 定义结构体类型 描述学生信息(学号、姓名、性别、年龄、成绩、地址)
struct Student
{
? ? int id; ? ? ? ? ? ? ? ? // 学号
? ? char *name; ? ? ? ? ? ? // 姓名
? ? enum
? ? {
? ? ? ? MALE,
? ? ? ? FEMALE,
? ? ? ? ELSE
? ? } gender; ? ? ? ? ? ? ? // 性别
? ? int age; ? ? ? ? ? ? ? ?// 年龄
? ? double score; ? ? ? ? ? // 成绩
? ? char address[40]; ? ? ? // 地址
};
// 定义函数 打印学生信息
void printStuInfo(struct Student stu)
{
? ? // 处理性别信息
? ? char *gender = NULL;
? ? switch (stu.gender)
? ? {
? ? ? ? case MALE: gender = "男"; break;
? ? ? ? case FEMALE: gender = "女"; break;
? ? ? ? case ELSE: gender = "其他"; break;
? ? }
? ? // 打印
? ? printf("学号:%d, 姓名:%s, 性别:%s, 年龄:%d, 成绩:%.2lf, 地址:%s \n", stu.id, stu.name, gender, stu.age, stu.score, stu.address);
}
int main()
{
? ? // 根据结构体类型定义结构体变量
? ? struct Student stu1;
? ? // 先定义结构体变量,对成员挨个初始化赋值, 使用 . 运算符
? ? stu1.id = 1001;
? ? stu1.name = "曹操";
? ? stu1.gender = MALE;
? ? stu1.age = 48;
? ? stu1.score = 28;
? ? // stu1.address = "上海"; ? // 错误:字符数组不能直接用 = 赋值,需通过拷贝字符 / 初始化完成内容设置
? ? //数组名:是「首元素地址常量」,不能用 = 赋值(如 arr = "abc" 错误)
? ? strcpy(stu1.address, "上海");
? ? // 定义结构体变量并初始化赋值
? ? struct Student stu2 = {1002, "刘备", ELSE, 45, 98, "成都"};
? ? // 打印学生信息
? ? printStuInfo(stu1);
? ? printStuInfo(stu2);
? ? printf("\n");
? ? // ---------------------------------------------------
? ? // 定义数组,数组元素都是 struct Student 类型
? ? struct Student stus[3] = {
? ? ? ? {1003, "关羽", ELSE, 45, 98, "成都"},
? ? ? ? {1004, "张飞", ELSE, 45, 98, "成都"},
? ? ? ? {1005, "孙权", FEMALE, 25, 18, "南京"}
? ? };
? ? // 遍历并打印数组信息
? ? for (int i = 0; i < 3; i++)
? ? {
? ? ? ? printStuInfo(stus[i]);
? ? }
? ? return 0;
}
/*
学号:1001, 姓名:曹操, 性别:男, 年龄:48, 成绩:28.00, 地址:上海?
学号:1002, 姓名:刘备, 性别:其他, 年龄:45, 成绩:98.00, 地址:成都?
学号:1003, 姓名:关羽, 性别:其他, 年龄:45, 成绩:98.00, 地址:成都
学号:1004, 姓名:张飞, 性别:其他, 年龄:45, 成绩:98.00, 地址:成都
学号:1005, 姓名:孙权, 性别:女, 年龄:25, 成绩:18.00, 地址:南京
*/2.4 结构体指针结构体指针是指向结构体的指针变量,允许间接访问和操作结构体的成员,它提供了一种方便的方式来处理结构体数据。声明结构体指针的语法格式:
struct 结构体名 *结构体指针变量名;
#include
void addage(struct Student *stu)
{
? ? stu->age++;
? ? //(*stu).age++;都可以
}
int main()
{ ??
? ? // 结构体
? ? struct Student
? ? {
? ? ? ? char *name;
? ? ? ? int age;
? ? ? ? char gender;
? ? };
? ? // 结构体变量
? ? struct Student s = {"张三", 20, 'M'};
? ? // 通过结构体变量访问成员
? ? printf("name=%s,age=%d,gender=%c \n", s.name, s.age, s.gender);
? ? // 声明结构体指针
? ? struct Student *ps = &s;
? ? // 结构体指针通过解引用访问成员,*ps.name,这个不对,.的优先级比*高,因此要加()
? ? printf("name=%s,age=%d,gender=%c\n", (*ps).name, (*ps).age, (*ps).gender);
? ? // 结构体指针使用->访问成员
? ? printf("name=%s,age=%d,gender=%c\n", ps->name, ps->age, ps->gender);
? ??
? ? printf("年龄:%d\n",addage(&s));//年龄增加,如果值传递就不行了
? ? return 0;
}
/*
输出结果:
name=张三,age=20,gender=M?
name=张三,age=20,gender=M
name=张三,age=20,gender=M
*/
/*
总结:如果指针变量p指向一个结构体变量stu,以下3种用法等价:
(1)stu.成员名
(2)(*p).成员名
(3)p->成员名
*/2.5 结构体存储大小成员偏移位置对齐:每个成员的偏移位置一定是自身大小的整数倍(如果成员比基准对齐长度大,按照基准对齐长度偏移)。结构体整体对齐:结构体的总大小一定是基准对齐长度的整倍数。基准对齐长度:从大成员的大小和系统对齐长度之间取较小的一个。32位系统中,默认系统对齐长度是4字节。开发者可以使用 #pragma pack() 设置系统对齐长度。结构体成员是数组:数组的每个元素单独对齐,不作为整体结构体成员还是结构体:1. 计算基准对齐长度,不把作为成员的结构体当做整体,把内部成员取出来进行计算
2. 计算总长度,作为成员的结构体先整体对齐,再与其他成员对齐2.6 共用体有时需要一种数据结构,不同的场合表示不同的数据类型。比如,如果只用一种数据结构表示学生的“成绩”,这种结构就需要有时是整数(80、90),有时是字符(’A’、’B’),有时是浮点数(80.5、60.5)。C语言提供了共用体类型(Union 结构),用来自定义可以灵活变更的数据结构。它内部可以包含各种属性,但同一时间只能有一个属性,因为所有属性都保存在同一个内存地址,后面写入的属性会覆盖前面的属性。这样做的最大好处是节省空间。“共用体”与“结构体”的定义形式相似,但它们的含义是不同的。(1)结构体变量所占内存长度,可以认为是各成员占的内存长度的叠加;每个成员分别占有其自己的内存单元。(2)共用体变量所占的内存长度等于最长的成员的长度;几个成员共用一个内存区。① 定义共同体类型union 类型名称
{
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? 成员类型 成员名称;
? ? ....
}注意: 类型名称和成员名称都需要符合标识符规范共用体体的成员类型可以是任意类型(整数、浮点、数组、指针、枚举、结构体)② 使用共用体类型定义共用体变量第一种方式 先定义类型,再定义变量
第二种方式 同时定义类型和变量
第三种方式 同时定义类型和变量并省略类型名称③ 共同体变量初始化赋值// 先声明共同体变量,再给其中一个成员赋值
union Score sc1;
sc1.a = 'A';
// 同时定义共用体变量并初始化赋值,给第一个成员赋值
union Score sc2 = {'C'};
// 同时定义共用体变量并初始化赋值,给指定成员赋值
union Score sc3 = {.b = 100};④ 共同体变量访问共同体成员使用 .⑤ 共用体指针访问共同体成员使用 ->
/**********************************************************************
?* 共用体
?**********************************************************************/
#include
// 使用共同体定义表示成绩的类型,该类型的数据可以是字母、可以是整数、可以是浮点
union Score
{
? ? char a;
? ? int b;
? ? double c;
};
int main()
{
? ? // 定义共用体变量 类型是 union Score
? ? union Score sc1;
? ? // 给 sc1 的成员赋值 ? 先声明共用体变量,再使用 . 给成员赋值
? ? sc1.a = 'B';
? ? sc1.b = 100;
? ? sc1.c = 98.13;
? ? // 打印
? ? printf("sc1 存储大小:%zu \n", sizeof sc1); // 8
? ? // 输出:sc1 存储大小:8
? ? // 原因:union的大小由最大成员决定,double占8字节
? ? printf("a: %c \n", sc1.a); // 输出:a: ? (乱码)
? ? // 原因:sc1.c = 98.13 覆盖了整个union
? ? // 现在读取的是double数据的第一个字节,不是原来的'B'
? ? printf("b: %d \n", sc1.b); // 输出:b: 一个随机的大整数
? ? // 原因:把double数据的低4字节当作int来解读,结果无意义
? ? printf("c: %.2lf \n\n\n", sc1.c); // 输出:c: 98.13
? ? // 唯一正确的输出,因为这是最后赋值的成员
? ? // 同时定义共用体变量并初始化赋值,给第一个成员赋值
? ? union Score sc2 = {'C'};
? ? printf("a: %c \n", sc2.a);
? ? printf("b: %d \n", sc2.b);
? ? printf("c: %.2lf \n\n\n", sc2.c);
? ? // 同时定义共用体变量并初始化赋值,给指定成员赋值
? ? union Score sc3 = {.b = 100};
? ? printf("a: %c \n", sc3.a);
? ? printf("b: %d \n", sc3.b);
? ? printf("c: %.2lf \n\n\n", sc3.c);?
? ? // 定义指针 指向共用体变量
? ? union Score *sc_ptr = &sc1;
? ? // 共同体指针可以使用 -> 访问成员
? ? printf("c: %.2lf \n", sc_ptr->c);
? ? return 0;
}2.7 typedef#define 类型别名与 typedef 类型别名的区别: ① 执行时机不同:#define在预处理阶段执行;typedef 在程序运行阶段执行。 ② 类型检查:#define只进行简单文本替换不作类型检查;typedef 在编译阶段会进行类型检查。 ③ 作用域:#define设置的别名无作用域的概念;typedef设置的别名具有作用域。① 基本类型别名typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;② 数组别名typedef int Int_array[];//取代变量名或标识符的位置
typedef double Double_array5[5];③ 函数别名typedef double Avg_function(int, int);④ 指针别名// 给指向基本类型数据的指针起别名
typedef int *Int_ptr;
typedef char *String;
// 数组指针起别名
typedef int (*Int_arr_ptr)[];
// 函数指针起别名
typedef double (*Avg_function_ptr)(int, int);⑤ 结构体别名// 5.1 先定义结构体类型,再取别名
struct User
{
? ? char *name;
? ? int age;
};
typedef struct User VipUser;
// 5.2 同时定义结构体类型并取别名
typedef struct Person
{
? ? char *name;
? ? int age;
} Person;
// 5.3 同时定义结构体类型并取别名,且省略结构体类型名(强烈推荐!!)
typedef struct //类型名不要加,不然就是Student就是变量了
{
? ? char *name;
? ? double score;
} Student;⑥ 共用体别名// 6.1 先定义共用体类型,再取别名
// 6.2 同时定义共用体类型和别名
// 6.3 同时定义共用体类型和别名,省略共用体类型名(强烈推荐)
typedef union
{
? ? char a;
? ? double b;
} Score;⑦ 枚举别名// 7.1 先定义枚举类型,再取别名
// 7.2 同时定义枚举类型和别名
// 7.3 同时定义枚举类型和别名,省略共用体类型名(强烈推荐)
typedef enum?
{
? ? MALE,
? ? FEMALE,
? ? ELSE
} Gender;扩展:特性字符数组(char arr[40])字符指针(char *p)本质可写内存块(存储字符)指针变量(存储地址)赋值方式初始化时 = "xxx",后续用 strcpy直接 p = "xxx"(指向字符串常量地址)可修改性数组内容可修改(arr[0] = 'x')指向的字符串常量不可修改(*p = 'x' 错误)存储位置栈区 / 全局数据区(可写)指针变量在栈区,指向只读数据区(字符串常量)长度固定(定义时指定或编译器自动计算)无固定长度,仅存储地址是否能使用scanf可以不可以(有时可以,有时不可)简单说:数组的「指向」不可改,「内容」默认可改;指针的「指向」可改,「内容」能否改看指向的内存权限。(1)数组的「指向」不可改,「内容」默认可改;//数组名是地址常量,不能给数组名赋值新地址
//(比如 char arr[10]; arr = "hello"; 报错,因为试图修改数组的「指向」)。
// 普通数组(可修改内容)
char arr[] = "hello";
arr[0] = 'H'; ?// 合法!内容改为 "Hello"
// const 数组(不可修改内容)
const char arr2[] = "hello";
// arr2[0] = 'H'; ?// 编译报错!const 修饰数组,内容不可改(2)指针的「指向」可改,「内容」能否改看指向的内存权限。//指针变量存储的是地址,可自由指向其他内存(只要类型兼容):
char *p = "hello"; ?// p 指向只读区的 "hello"
char arr[] = "world";
p = arr; ?// 合法!p 改为指向栈区的 arr(修改指向)
//情况 1:指向「只读内存」(字符串常量、const 变量)→ 不能修改内容:
char *p1 = "hello"; ?// 指向只读区的字符串常量
// *p1 = 'H'; ?// 运行报错(段错误)!只读内存不可写
//情况 2:指向「可写内存」(字符数组、堆内存)→ 可以修改内容:
char arr[] = "hello";
char *p2 = arr; ?// p2 指向栈区的可写数组
*p2 = 'H'; ?// 合法!arr 内容改为 "Hello"
//情况 3:const 指针(指向常量的指针)→ 编译期禁止修改内容(语法层面限制):
const char *p3 = "hello"; ?// p3 是「指向常量的指针」
// *p3 = 'H'; ?// 编译报错!语法禁止修改指向的内容
p3 = "world"; ?// 合法!指针指向可修改(const 只限制内容,不限制指向)练习题1、分析输出结果2、理解指针/**********************************************************************
? 有如下二维数组(选做,尽量做)
? ?int nums[3][4] = {
? ? ? ? {10,20,30,40},
? ? ? ? {100,200,300,400},
? ? ? ? {1000,2000,3000,400}
? ?}
? ?实现如下需求:
? ?① 定义指针,将 nums 赋值给该指针
? ?② 定义指针,将 &nums 赋值给该指针
? ?③ 定义指针,将 nums[1] 赋值给该指针
? ?④ 定义指针,将 &nums[1] 赋值给该指针
? ?⑤ 定义指针,将 &nums[1][1] 赋值给该指针
**********************************************************************/
#include
// 任何数组名(无论一维 / 二维),在多数表达式中(如赋值给指针),
//都会隐式转为「该数组首元素的地址」。
int main()
{
? ? // 定义二维数组
? ? int nums[3][4] = {
? ? ? ? {10, 20, 30, 40},
? ? ? ? {100, 200, 300, 400},
? ? ? ? {1000, 2000, 3000, 400}};
? ? // ① 定义指针,将 nums 赋值给该指针 ? ?nums 等同于 &nums[0]
? ? //nums是指向二维数组的整个第0行地址
? ? //nums 是二维数组名(类型 int[3][4])根据数组名隐式转换规则:
? ? //nums 的「元素类型」是 int[4](每个元素是 4 个 int 的数组,即二维数组的 “一行”);
? ? int (*ptr1)[4] = nums; ? ? ?
? ? printf("**ptr1=%d \n", **ptr1);//*ptr1是表示第0行第0个元素的地址
? ? // ② 定义指针,将 &nums 赋值给该指针,&nums 是取得是整个数组的地址
? ? int (*ptr2)[3][4] = &nums;
? ? printf("***ptr2=%d \n", ***ptr2);
? ? // ③ 定义指针,将 nums[1] 赋值给该指针,没有取地址, 等价于 &nums[1][0]?
? ? //nums[1] 是二维数组的「第 1 行」,本质是 int[4] 类型的数组名(一维数组名,对应 “一行 4 个 int”),
? ? //根据数组名隐式转换规则:nums[1] 的「元素类型」是 int(每个元素是单个 int);
? ? //nums[1] 隐式转为「指向该行首元素的指针」—— 首元素是 nums[1][0]
? ? //第1行第0个元素的地址 ?
? ? int *ptr3 = nums[1];
? ? printf("*ptr3=%d \n", *ptr3);
? ? // ④ 定义指针,将 &nums[1] 赋值给该指针,&nums[1] 是取得是整个第1行数组的地址
? ? int (*ptr4)[4] = &nums[1];
? ? printf("**ptr4=%d \n", **ptr4);
? ? // ⑤ 定义指针,将 &nums[1][1] 赋值给该指针
? ? int *ptr5 = &nums[1][1];
? ? printf("*ptr5=%d \n", *ptr5);
? ??
? ? return 0;
}
/*
**ptr1=10?
***ptr2=10?
*ptr3=100
**ptr4=100
*ptr5=200
*/3、小狗案例(1)编写一个Dog结构体,包含name(char *)、age(int)、weight(double)属性。(2)编写一个say函数,返回字符串,方法返回信息中包含所有成员值。(3)在main函数中,创建Dog结构体变量,调用say函数,将调用结果打印输出。#include
// 定义Dog结构体
struct Dog
{
? ? char *name;
? ? int age;
? ? double weight;
};
// say函数,返回字符串,信息中包含所有成员值
char *say(struct Dog dog)
{
? ? // 将这个信息放入到一个字符串(字符数组)
? ? static char info[50]; // 局部静态变量
? ? sprintf(info, "name=%s age=%d weight=%.2f", dog.name, dog.age, dog.weight);
? ? dog.name = "小花";
? ? return info;
}
int main()
{
? ? // 测试
? ? // 定义结构体变量
? ? struct Dog dog;
? ? char *info = NULL;
? ? dog.name = "小黄";
? ? dog.age = 1;
? ? dog.weight = 3.4;
? ? info = say(dog); // 结构体变量默认是值传递
? ? printf("小狗信息:%s \n", info);
? ? printf("main中小狗名字:%s \n", dog.name);
? ? return 0;
}4、盒子案例(1)编程创建一个Box结构体,在其中定义三个成员表示一个长方体的长、宽和高,长宽高可以通过控制台输入。(2)定义一个函数获取长方体的体积(volume)。(3)创建一个结构体指针,打印给定尺寸的长方体的体积。#include
// 定义Box结构体
struct Box
{
? ? double length;
? ? double width;
? ? double height;
};
// 获取立方体体积的函数
double getVolume(struct Box *box)
{
? ? return box->length * box->width * box->height;
}
int main()
{
? ? // 创建结构体变量
? ? struct Box box;
? ? // 创建结构体指针
? ? struct Box *cube = &box;
? ? printf("Enter length: ");
? ? scanf("%lf", &cube->length);
? ? printf("Enter width: ");
? ? scanf("%lf", &cube->width);
? ? printf("Enter height: ");
? ? scanf("%lf", &cube->height);
? ? // 调用函数获取体积并打印
? ? printf("Volume is: %.2f\n", getVolume(cube));
? ? return 0;
}5、景区门票案例/**********************************************************************
?* (1)一个景区根据游人的年龄收取不同价格的门票。
C语言实例href="MAP.MqKo.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.RvOs.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.VzTx.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.Z3X1.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.d7b5.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.hBf9.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.HFjD.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.LpJn.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.PtNr.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.TxRv.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.X1Vz.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.b5Z3.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.f9d7.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.jDhB.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.nHlF.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.rLpJ.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.RPtN.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.VzTx.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Z3X1.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.d7b5.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.hBf9.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.lFjD.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.qJnH.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.uOsM.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.ySwQ.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.2W0U.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.c64Y.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.gAe8.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.kEiC.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.oImG.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.sMqK.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.wQuO.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.0UyS.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.4Y2W.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.8c6a.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.CgAe.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.mGki.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.qKoI.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.uOsM.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.ySwQ.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.2W0U.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.6a4Y.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Ae8c.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.EiCg.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.JnHk.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.NrLp.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.xRvP.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.1VzT.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.5Z3X.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.9d7b.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.DhBf.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.HlFj.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.LpJn.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.PtNr.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.TxRv.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.31Vz.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.7b5Z.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.Bf9d.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.FjDh.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.JnHl.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.NrLp.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.RvPt.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.VzTx.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.Z3X1.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.d7b5.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.ECf9.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.ImGk.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.MqKo.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.QuOs.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.UySw.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Y2W0.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.c6a4.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.gAe8.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.kEiC.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.oImG.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.OsqK.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.SwQu.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.W0Uy.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.a4Y2.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.e8c6.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.iCgA.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.mGkE.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.qKoI.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.uOsM.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.ySwQ.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.Y2WU.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.d6a4.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.hBf9.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.lFjD.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.fzA1.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.tNrL.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.xRvP.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.1VzT.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.5Z3X.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="MAP.9d7b.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.jDhB.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="MAP.nHlF.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.rLpJ.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.vPtN.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="MAP.zTxR.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.3X1V.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.7b5Z.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Bf9d.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="WAP.FjDh.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="WAP.pnHl.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.tNrL.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="WAP.xRvP.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="WAP.1VzT.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.6a4X.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="WAP.Ae8c.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.EiCg.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.ImGk.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.MqKo.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.QuOs.b2ao5.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.0ySw.b7sa3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.4Y2W.b5ai3.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.8c6a.s1fa6.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.CgAe.b3su9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.GkEi.s1ba9.inFO"循环冗余校验与 BMP
C语言实例href="BLOG.KoIm.b3yi6.inFO"循环冗余校验与 BMP
C语言实例href="MAP.OsMq.b2te8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.SwQu.b1ei8.inFO"循环冗余校验与 BMP
C语言实例href="MAP.W0Uy.b1di1.inFO"循环冗余校验与 BMP
C语言实例href="MAP.a4Y2.b2ao5.inFO"循环冗余校验与

最低0.47元/天 解锁文章
794

被折叠的 条评论
为什么被折叠?



