欢迎来到本期频道!
想要了解结构体吗?想知道如何使用结构体吗?满足你!(大佬请忽略)
为了能够更灵活地描述对象,C语言提供了结构体类型. |
一:结构体的初阶认识
1.什么是结构体(struct)
C语言中,结构体是一种数据类型,结构体类型属于自定义类型,结构体类型的成员变量可以是不同类型。
2.如何创建结构体类型
结构体类型可以用来描述一个复杂对象,例如描述一个学生:
一般情况下:
struct stu
{
int num[10];
char name[10];
int age;
//......
};
一些特殊情况下,会创建匿名结构体:
struct
{
char d;
short e;
int f;
}s; //s是一个该结构体类型变量
注意:结构体类型不能嵌套自身,因为无法定义,是不合法的。例如:
struct k
{
int a;
struct k u;
};
3.如何创建和使用结构体变量
struct stu s1={20220190,"张三",66}; //创建一个struct stu类型的变量并初始化
struct stu s2={.num=20210273,.age=38,.name="王五"}; //另一种初始化方式
struct stu *p=&s2;
printf("%s\n",s1.name);
printf("%d\n",p->age);
二:结构体的进阶认识
由于平台原因和性能原因,结构体需按对齐规则来存放,这是一种以空间换时间的做法。 |
1.结构体的内存对齐规则
①结构体成员的第一个变量对齐到结构体起始位置偏移量为0的地址。
②其它的成员变量对齐到偏移量为对齐数整数倍的位置。
该对齐数为编译器默认对齐数和该成员变量自身大小(如果是数组,取数组元素的大小)的最小值。
在vs2019中,这里的默认对齐数是可以修改的:
#pragma pack (n)
默认对齐数改为n
③结构体的总大小是最大对齐数 (所有成员的对齐数比较) 的整数倍。
④如果嵌套了结构体,当计算最大对齐数时,该结构体变量的所有成员的对齐数都要参与比较。
根据该规则,我们就可以分析结构体大小了,例如:
2.结构体传参
#include<stdio.h>
struct grade
{
char name[10];
int Math;
int English;
int Chinese;
};
int total1(struct grade s) //传值
{
return s.Math + s.English + s.Chinese;
}
int total2(struct grade* s) //传址
{
return s->Math + s->English + s->Chinese;
}
int main()
{
struct grade a = { "张三", 60, 59, 38 };
struct grade b = { "李四", 57, 50, 66 };
int ret1 = total1(a);
int ret2 = total2(&b);
return 0;
}
两种方式都能达到想要的功能,但是哪种方式效率更高呢?显然是传址,因为传址只需创建一个指针变量,而传值要创建一个结构体变量,如果结构体变量特别大,那在传参时会有很大的时间和空间上的系统开销。所以尽量使用传址传参。
三:结构体的引申
1.位段
C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域。
位段是专门用来节省空间的,但有跨平台问题。 |
②位段成员后有一个冒号和一个数字。
位段的创建:
struct p
{
char a : 2;
char b : 3;
char c : 4;
};
位段成员的访问和结构体是一样的,这里就不细说了。
位段的内存分配
以上述所建类型为例:
位段的注意事项:
①int类型位段被当成有符号还是无符号是不确定的。
②位段中的最大位的数目不能确定。(例如32位和16位机器上的位数就不同,不能跨平台)
③位段中的成员在内存中从左向右,还是从右向左分配,没有明确规定。
④当一个结构包含两个位段,第二个位段成员较大,剩余的位无法容纳时,是浪费还是继续使用,没有明确规定。
⑤对位段成员不能取地址操作。(bit位没有地址)
2.柔性数组
在c99中,结构中的最后一个成员允许是未知大小的数组,这个就是柔性数组成员。
在结构体中只能有一个柔性数组成员,该成员必须是结构体的最后一个成员。 |
例如:
struct s
{
int a;
int arr[]; //或者arr[0] 柔性数组成员
}
柔性数组特点:
①结构中,柔性数组成员前面必须至少有一个其它成员。
②sizeof返回此结构的大小不包含柔性数组的内存。
③包含柔性数组成员的结构体用malloc函数动态分配内存,并且分配的内存应大于结构体的大小,以适应柔性数组的预期大小。
我们利用这些特点来使用柔性数组:
#include<stdio.h>
#include<stdlib.h>
struct stu
{
char name[5];
int grade[];
};
int main()
{
void* p = malloc(sizeof(struct stu) + 10*sizeof(int)); //根据需要开辟空间
if (p == NULL)
{
perror("malloc");
return 1;
}
struct stu *person = (struct stu*)p;
int i = 0;
for (i = 0; i < 10; i++) //使用为柔性数组开辟的空间
{
person->grade[i] = 57+i;
printf("%d ", person->grade[i]);
}
free(p);
p = NULL;
return 0;
}
除此之外,我们还可以 模拟 柔性数组:
#include<stdio.h>
#include<stdlib.h>
struct s
{
char name[5];
int* grade;
};
int main()
{
struct s stu = { "老王" };
void* t1 = malloc(10 * sizeof(int));
if (t1 == NULL)
{
perror("malloc");
return 1;
}
stu.grade = (int*)t1;
int i = 0;
for (i = 1; i < 10; i++)
{
stu.grade[i] = 57 + i;
printf("%d ", stu.grade[i]);
}
free(t1);
t1 = NULL;
return 0;
}
本期分享就到这里了,希望能够让你更热爱C语言。 |