构造类型
结构体
-
产生及意义:把不同类型的数据存储在一块连续的空间。
-
结构体描述。结构体定义时不占内存空间,不要在定义是初始化。简单意义上,结构体是一个类型,定义结构体是在描述结构体类型。类似你在描述int,int这个类型不占空间,而是int类型变量占空间。
-
结构体成员是按照结构体描述的顺序在内存中顺序存放的。
-
结构体可以只用值或地址在函数中传递,建议使用地址传递,以减少内存开销。
-
结构体定义建议放在函数外,整个程序声明和定义的位置。
struct birthday { int year, month, day; }; struct student_st { int id; float math; struct birthday birth; }; // 多种结构体赋值 struct student_st stu = { 10011, 90, {2010, 10, 10} }; struct student_st stu = { .id = 10012, .math = 100, .birth.day = 10 }; struct student_st* p = &stu; stu.id = 10012; // 通过变量名引用 p->id = 10012; // 通过指针引用 // 结构体数组 struct student_st arr[N];
-
没有名字结构体(无头结构体),在声明时要将变量定义完成
-
占用空间大小。结构体不要求地址对齐时,其大小就是其成员各个空间大小的和。地址对齐的大小根据机器环境决定。
-
变长结构体
-
简易学生管理系统
/* MSVC中编译通过 */ #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #define NAMESIZE 32 struct student_st { int id; char name[NAMESIZE]; int math; int chinese; }; void stu_set(struct student_st* p, const struct student_st* q); void stu_show(struct student_st* p); void stu_changename(struct student_st* p, const char* newname); void menu(void); int main(void) { struct student_st stu, tmp; char newname[NAMESIZE]; int choice = 0, ret = 0 ; do { menu(); ret = scanf("%d", &choice); if (ret != 1) { break; } switch (choice) { case 1: printf("Please enter for the sud[id name math chinese]: "); ret = scanf("%d%s%d%d", &tmp.id, tmp.name, &tmp.math, &tmp.chinese); if (ret != 4) { printf("Input Error\n"); exit(1); } stu_set(&stu, &tmp); break; case 2: printf("Please enter the newname: "); ret = scanf("%s", newname); if (ret != 1) { printf("Input Error\n"); exit(1); } stu_changename(&stu, newname); stu_show(&stu); break; case 3: stu_show(&stu); break; default: printf("No this number\n"); break; } } while (true); return 0; } /* 将tmp中的信息拷贝到学生结构体stu中 */ void stu_set(struct student_st* stu, const struct student_st* tmp) { *stu = *tmp; } /* 显示学生结构体信息 */ void stu_show(struct student_st* p) { printf("%d %s %d %d\n", p->id, p->name, p->math, p->chinese); } /* 修改学生结构体中姓名 */ void stu_changename(struct student_st* p, const char* newname) { strncpy(p->name, newname, NAMESIZE); } /* 选择菜单 */ void menu(void) { printf("\n1 set\t2 change name\t3 show\n"); printf("Please enter the num(q for quit): "); }
共用体
-
产生及意义:有多个成员,但只有一个存在,内存根据成员中所占空间最大的来分配。说白了就是多个成员共用同一块空间。
-
基本实例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #define NAMESIZE 32 union MyUnion { int n; char ch; struct { int id; char name[NAMESIZE]; } student; }; int main(void) { union MyUnion un; strncpy(un.student.name, "Lisa", NAMESIZE); printf("%s\n", un.student.name); return 0; }
-
共用体和结构体嵌套使用的技巧
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <stdint.h> int main(void) { /* 任务:将内存中高16位和低16位相加 */ uint32_t n = 0x11223344; // 位运算实现示例 printf("%x\n", (n >> 16) + n & 0xFFFF); // 4466 // 共用体和结构体嵌套实现示例 union { struct { uint16_t i; uint16_t j; } add; uint32_t n; } test; test.n = n; // 先按32位存储 printf("%x\n", test.add.i + test.add.j); // 再看成两个16位相加 return 0; }
-
位域
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <stdint.h> union MyUnion { struct MyStruct { unsigned char a : 1; // 只占 1 位 unsigned char b : 2; // 只占 2 位 unsigned char c : 1; // 只占 1 位 } x; unsigned char y; } test; int main(void) { /* ----------------- | | | | | | | |1| ----------------- a a 占一位 b b b 占两位 c c 占一位 二进制以补码存储 */ test.y = 1; // 只有a是1,其他位都是0 printf("%u\n", test.x.a); // 输出:1 test.y = 4; // 4 的二进制 100 b的第二位为1,第一位和a都是0 printf("%u\n", test.x.a); // 输出:0 printf("%u\n", test.x.b); // 输出:2 return 0; }
枚举类型
-
枚举类型很多时候可以作为宏来使用,但不能等同于宏。枚举类型并不会在预处理阶段被解析。
-
枚举类型示例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <stdint.h> enum { MON = 1, TUS, THR, WES, FRI, SAT, SUN, }; enum { STATE_RUNNING = 1, STATE_CANCELED, STATE_OVER, LOOP = 1, RUN, }; enum { A, B, C, }; enum INSERT_MODE { INSERT_FORWARD = 1, INSERT_BACKWARD }; int main(void) { enum INSERT_MODE mode = INSERT_FORWARD; printf("%d\n", FRI); printf("%d\n", STATE_OVER); // RUN的上一个重新写为1,那么后面的内容也从1开始重新 +1 // 所有输出为 2 printf("%d\n", RUN); // 不写的话从 0 开始 printf("%d\n", A); return 0; }