一、结构体(struct
关键字)
结构体类型用于描述复杂数据,是一种构造类型(用户自定义类型)。
1. 结构体的声明
struct Student
{
int id;
char name[20];
float score;
};
说明:
-
struct
是关键字; -
Student
是结构体名; -
成员列表可包含变量、数组、指针等;
-
成员间用分号分隔;
-
结尾必须加分号。
2. 定义变量
struct Student s;
3. 成员赋值
s.id = 1;
strcpy(s.name, "zhangsan");
s.score = 99.5;
注意:
-
使用点运算符
.
; -
s.name = "zhangsan"
是错误的,不能直接赋值给数组。
4. 结构体变量之间赋值
struct Student s1 = {1, "zhangsan", 90};
struct Student s2;
s2 = s1;
5. 初始化结构体变量
struct Student s = {1, "zhangsan", 99};
也可以使用部分初始化(C99支持):
struct Student s = { .id = 1, .score = 90 };
未赋值成员自动补 0。
二、结构体内存对齐原则
结构体内存对齐规则(32位系统为例):
-
默认按最大成员大小对齐;
-
每个成员的偏移量必须是其类型大小的整数倍;
-
总大小是最大对齐值的整数倍。
struct Demo {
char a;
int b;
short c;
};
sizeof(struct Demo)
输出为 12 字节。
内存对齐的目的是提高CPU访问效率(空间换时间)。
三、结构体成员访问
1. 点操作符 .
用于变量
printf("%d\n", s.id);
2. 箭头操作符 ->
用于指针
struct Student *p = &s;
printf("%d\n", p->id);
3.输出函数1:注:该函数为值传递(过程需要拷贝);不建议使用
4.输出函数2:注:该函数为指针传参(效率更好)
四、结构体常见操作示例
遍历结构体数组
结构体逆序
交换结构体数组的元素
采用回调函数按学生成绩排序
采用qsort函数按学生名字排序
五、共用体(union
)
共用体多个成员共享同一块内存,总大小为最大成员的大小。
4个字节被3个长度不同的变量共享时,共享总是从起始部分开始共享的(所有成员起始地址是相同的);
定义示例
union Data {
int i;
float f;
char ch;
};
共用体只能使用最后一次赋值的成员。
union Data d;
d.i = 10;
d.f = 3.14; // 覆盖了 i 的值
共用相同的内存空间(所以称为共用体); 运行结果:4(共占4个字节)
六、使用共用体判断大小端
七、枚举类型(enum
)
用于限定变量的取值范围,提高可读性。
示例定义
enum Status {
SLEEP, // 0
RUNNING, // 1
ERROR = 4,
STOP // 5
};
说明:
-
默认从 0 开始;
-
可以指定某个枚举常量的值;
-
枚举本质是
int
类型; -
可用于
switch
语句。
使用示例
enum Status s = RUNNING;
printf("%d\n", s); // 输出 1
注意事项:
(1)枚举中逐个列举的值,默认是从0开始;如果有给定的值,则后续没有给值的枚举成员依次加1;
(2)枚举本质是一个int 类型的数据(可以放在switch中使用);
(3)每个值可以用%d输出。
示例:运行结果:sleep
运行结果为4;
运行结果为2(列举的值默认从0开始);
运行结果为13(有给定的值,后续没有给值的枚举常量依次+1);
八、typedef
关键字
用于给已有类型起别名,提升可读性,简化复杂声明。
示例
typedef int INT;
INT a = 10;
typedef struct {
int id;
char name[20];
} Student; Student s;
九、位运算
1. 按位与 &
unsigned char a = 0x9E; // 1001 1110
unsigned char b = 0x32; // 0011 0010
printf("%02X\n", a & b); // 12
作用:清零特定位
2. 按位或 |
printf("%02X\n", a | b); // 0xBE
作用:指定位置1;
3. 按位异或 ^
printf("%02X\n", a ^ b); // 0xAC
作用:位翻转
4. 取反 ~
printf("%02X\n", (unsigned char)(~a)); // 0x61
作用:0变1,1变0
5. 左移 <<
1、<<:双目运算符,优先级为5级,结合方向自左至右;
2、写法:a<<n (表示将a这个数据左移n位 )(C语言中为逻辑左移)
3、最高位无论是1还是0全丢掉,后面补0;
4、作用:指定位清零( ~(1 << n));
eg:
0000 0001
0000 0010
左移1位 相当于乘 2
6. 右移 >>
1、>>:双目运算符,优先级为5级,结合方向自左至右;
2、写法:a>>n(表示将 a这个数据 右移 n位)
3、算术右移是看符号位和看数据类型的:
(1)有符号数据类型,右移时,最高位补的是符号位; (算术右移)
(2)无符号类型的数据,右移时,最高位补的0 ;(逻辑右移)
注:在使用右移运算符时最好定义无符号数据类型(eg:unsigned char)
1000
1100
-----------
0100
0010
右移1位 相当于除 2
总结
本节内容是 C 语言和底层操作的重要基础,包括:
-
struct
建立复杂数据结构; -
union
共用内存空间; -
enum
提升代码可读性; -
typedef
简化类型书写; -
位运算用于高效的位级操作。