前言:
C语言也给我们程序员规定了一种自定义 类 型,结构体的每一个成员可以是不同类型的变量,结构是⼀些值的集合,这些值称为成员变量,那么结构体的内存大小又是怎么算的呢?
结构是⼀些值的集合,这些值称为成员变量;关键字:struct
#include<stdio.h>
struct add//结构体的声明定义
{
int a;
}value;//value指的是这个结构体的名字 旁边这个分号必须要添加 value可以先不写,等我们需要的时候创建就行了
//比如
int main()
{
struct add s1 ;//我们创建的时候就能够这么写
return 0;
}这就是简单的结构体声明
假设当我们想要描述一个学生的时候。
struct stu
{
char name[20];
int age;
float Score;
};这就简单创建了一个简单结构体类型。
就拿我们的学生这个结构体来讲
#include<stdio.h>
struct stu//结构体声明定义
{
char name[20];
int age;
float Score;
};
int main()
{
//struct stu s1;这个是结构体的创建,类型位struct stu 名字位:s1
//结构体的创建和初始化
struct stu s1 = {"zhangsan",20,95.5f};//这就是我们简单的初始化,也可以部分初始化,或者不初始化。
//当我们想不按照这个顺序初始化的时候我们就要用到这个操作符
struct stu s2 = {.age = 20,.Score = 95.5f,.name = "zhangsan"};
return 0;
}#include<stdio.h>
struct stu//结构体声明定义
{
char name[20];
int age;
float Score;
};
int main()
{
struct stu s2 = {.age = 20,.Score = 95.5f,.name = "zhangsan"};
//打印
printf("%d\n",s2.age);
printf("%f\n",s2.Score);
printf("%s\n",s2.name);
return 0;
}
比如:
//这样类型的特殊声明
struct
{
char name[20];
int age;
float score;
}value;
//还有这样的结构体声明
struct
{
char name[20];
int age;
float score;
}value[10],*p;这样的声明省略掉了我们结构体的名字,直接就创建了我们的变量。
那么这样做编译器会不会报错呢?
答案:不会报错
警告:
**编译器会把上面的两个声明当成完全不同的两个类型,所以是非法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用一次。**
学到数据结构的时候我们就会知道链表这个概念。
就又没有想过,结构体里面包含结构体,一个连接着一个,形成一个链条一样的链表。
举例:
//就像这样写
struct Node
{
int a;
struct Node*next;
};以上就是我们的结构体的创建和初始化以及特殊的结构体声明定义。
那么结构体的内存大小又是怎么算的呢?
接下来我们来学习一下。
struct stu
{
char name[20];
int age;
};这个结构体内存大小多大呢?
答案:24
为什么是24呢?我们就要了解最大对齐数这个概念。
对其规则
**结构体的第1个成员对齐到和结构体变量起始位置偏移量为0的地址处。
从第2个成员变量开始,都要对齐到某个对其数的整数倍的地址处,(对其数 = 编译器默认的⼀个对其数与该成员变量大小的较小值。)
结构体总大小为最大对齐数的整数倍。
嵌套了结构体的情况下,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构
体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。**
举例:
注意:每一个编译器默认的对齐数都是不一样的,就像我们Vs这个编译器默认的对齐数为:8
#include<stdio.h>
struct S1
{
char c1;//对齐数位1
int i;//对齐数为4
char c2;//对齐数为1
};
int main()
{
printf("%zu\n", sizeof(struct S1));//选择最大对齐数的整数倍
return 0;
}

#include<stdio.h>
#pragam pack(1);//设置默认对齐数为1
struct S
{
char c1;//对齐数位1,而我们默认对齐数为1 , 对齐数为1
int i;//对齐数为4,而我们默认对齐数为1 , 对齐数为1
char c2;//对齐数为1,而我们默认对齐数为1 , 对齐数为1
};
#pragma pack();取消修改默认对齐数
int main()
{
printf("%d\n", sizeof(struct S));
return 0;
}

得到的结果都是我们的1000。这样我们就能知道:结构体传参的时候,要传结构体的地址
结构体又是怎么传参的呢?
#include<stdio.h>
struct S
{
int data[1000];
int num;
};
//结构体传参
//测试传结构体
void test1(struct S s)
{
printf("%d\n", s.num);
}
//测试地址
void test2(struct S* s)
{
printf("%d\n", s->num);
}
int main()
{
struct S s = {{1,2,3,4}, 1000};
test1(s);//传结构体
test2(&s);//传地址
return 0;
}
得到的结果都是我们的1000。这样我们就能知道:结构体传参的时候,要传结构体的地址
什么是位段?
位段:
**1. 位段的成员必须是int、unsigned int 或signed int ,在C99中位段成员的类型也可以选择其他整型家族类型,比如:char。
2. 位段的成员名后边有⼀个冒号和⼀个数字。**
举例:
struct A
{
int _a:2;
int _b:3;
int _c:30;
};
int main()
{
printf("%d\n", sizeof(struct A));
return 0;
}
这就是我们位段的写法。
A就是⼀个位段类型。
**1. 位段的成员可以是int、 unsigned int、signed int 或者是char 等类型
2.位段的空间上是按照需要4个字节或者一个字节的方式开辟
3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。**
例如:
#include<stdio.h>
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
int main()
{
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
return 0;
}
**注意:
位段在跨平台的时候会出现问题。
问题:
int 这个位段被别的编译器当成有符号数还是无符号数是不确定的。
位段中最大位的数不能确定。
位段中的成员在内存中从左向右分配,还是从右向左分配
当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,无法容纳于第⼀个位段剩余的位时,是舍弃
剩余的位还是利用,这是不确定的。
总结:位段可以达到结构体那样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。**
完!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。