C语言:结构体
本文最后更新于:2023年3月21日 晚上
定义
1 |
|
- struct 后跟的point称为结构标记,这种标识符在C语言中称为Tag
- struct声明定义了一种数据类型,可以将自定义的标识符声明为指定类型的变量,这里p1,p2都是point类型
- 如果在定义结构体类型的同时定义了变量,也可以不必写Tag,但这样就没有办法再次引用这个结构体类型(没有tag)
成员访问与引用
通过.
进行结构体的引用
struct point maxpt = {320, 200};
,那么maxpt.x可以访问maxpt的x成员,若有结构体内部的嵌套关系,也可以使用.
访问被嵌套的成员
通过->
进行引用struct point origin,*pp;
将 pp 定义为一个指向 struct point 类型对象的指针- pp = &origin,该指针指向origin结构体,然后就可以用
(*pp).x, (*pp).y
来访问结构体的变量 (*pp).x
中的圆括号是必需的,因为结构成员运算符.
的优先级比*
的优先级高。表达式*pp.x
的含义等价于*(pp.x),因为 x 不是指针,所以该表达式是非法的
C 语言提供了另一种简写方式,假定 p 是一个指向结构的指针,可以用p->结构成员这种形式引用相应的结构成员
假设有一个结构体定义如下:
1 |
|
list_ele_t *newh = (list_ele_t *)malloc(sizeof(list_ele_t));
分配了结构体的空间。但是这样不会给value分配空间newh->value = (char *)malloc(sizeof(char) * (strlen(s) + 1));
给结构体内的value分配了空间,这样之后才可以对value进行操作
赋值
- 结构体类型之间用赋值运算符是允许的
- 用一个结构体初始化另一个结构体也是允许的
- 将结构体作为函数参数、函数返回值是允许的
一个函数调用分析
1 |
|
变量z在main函数的栈帧中,参数z1和z2在add_complex函数的栈帧中,z的值分别赋给z1和z2
如果结构体中有char类型的数组,可以使用strcpy函数进行赋值
类型定义
typedef可以建立新的数据类型名,例如,typedef int Length;
将 Length 定义为与 int 具有同等意义的名字
比较复杂的类型定义:
1 |
|
该语句定义了类型 PFI 是“一个指向函数的指针,该函数具有两个 char *类型的参数,返回值类型为 int”
typedef有助于分析函数声明,比如下面的声明,可以暴力分析:
1 |
|
- 简化声明
void (*signal(int sig, func))(int);
void (*)(int);
- signal 是一个函数
- 有两个参数,一个为int类型,一个为指向函数的指针
- 返回值为指向函数的指针(参数为int,返回值为void)
也可以这样分析:
1 |
|
结构体排序的几种方法
通过重载 < 操作符
1 |
|
自定义sort的cmp函数
对于一个结构体而言,有多个关键字,在使用sort的时候可以针对不同关键字进行排序
比如下面这个结构体node存储数学和语文成绩
1 |
|
仅仅以math为关键字进行排序
1 |
|
优先以math为关键字排序,当math相等时,以Chinese为关键字排序
1 |
|
结构体对齐
- 原则一:数据成员对齐规则:
- 结构的数据成员,第一个数据成员放在offset为0的地方
- 以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)
- 原则二:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐
- 原则三:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储
- struct a里存有struct b,b里有char,int, double等元素, 那b应该从8的整数倍开始存储.
- 原则四:对齐参数如果比结构体成员的sizeof值小,该成员的偏移量应该以此值为准。也就是说,结构体成员的偏移量应该取二者的最小值
- 对齐参数就是#pragma pack(num)中的num值