C语言之结构体

张开发
2026/4/11 23:40:01 15 分钟阅读

分享文章

C语言之结构体
本篇目标1. 结构体类型的声明2. 结构体变量的创建和初始化3. 结构成员访问操作符4. 结构体内存对齐。一.结构体1.结构体的声明C语言已经提供了内置类型如char、short、int、long、float、double等但是只有这些内置类 型还是不够的假设我想描述学生描述⼀本书这时单⼀的内置类型是不行的。 描述⼀个学生需要名字、年龄、学号、、体重等 描述⼀本书需要书名作者、出版社、定价等。所以C语言为了解决这个问题增加了结构体这种自定义的数据类 型让程序员可以自己创造适合的类型。结构是成员变量的集合结构的每个成员可以是不同类型的变量例如我们描述书店里的一本书时就在这个结构里面包含书名作者、出版社、定价此时就可以很好的表述这本书。用代码来举例struct Book { char title[100]; // 书名 char author[50]; // 作者 char publisher[50]; // 出版社 double price; // 定价 };这个就是结构体书的声明注意结构体结束时的;分号不要少了2.结构体变量的定义和初始化仍然以书来举例例如先定义变量1.声明类型的同时定义变量 p1struct Book { char title[100]; // 书名 char author[50]; // 作者 char publisher[50]; // 出版社 double price; // 定价 }b1;2.定义结构体变量struct Book { char title[100]; // 书名 char author[50]; // 作者 char publisher[50]; // 出版社 double price; // 定价 }; struct Book b2; //全局的 int main() { struct Book b3; //main函数里的 return 0; }注意可以看出写一个结构体变量是要带上struct的如果我们嫌麻烦可以用typedef一下再初始化变量例如struct Book { char title[100]; // 书名 char author[50]; // 作者 char publisher[50]; // 出版社 double price; // 定价 }b1 {修仙,张三,天上,99.99}; struct Book b3 {《红楼梦》, 曹雪芹, 人民文学出版社, 59.70};//顺序初始化 struct Book b1 {.title 《百年孤独》,.author 马尔克斯,.publisher 南海出版公司,.price 55.00};//指定内容初始化如果有一个嵌套的结构体struct Point { int x; int y; }; struct Stu { int age; char name[15]; struct Point p1; };就可以这样初始化struct Stu s1{20,李四,{22,90}};3.结构成员访问操作符3.1.结构体成员的直接访问通过点操作符.访问的点操作符接受两个操作数使用方式结构体变量.成员名例如#includestdio.h struct Book { char title[100]; // 书名 char author[50]; // 作者 char publisher[50]; // 出版社 double price; // 定价 }b1 {修仙,张三,天上,99.99}; int main() { printf(书名%s\n, b1.title); printf(作者%s\n, b1.author); printf(出版社%s\n, b1.publisher); printf(定价%.2f\n, b1.price); return 0; }输出结果3.2.结构体成员的间接访问但是当我们得到的是⼀个指向结构体的指针时就要用-访问成员变量使用方式结构体指针-成员名例如#includestdio.h struct Book { char title[100]; // 书名 char author[50]; // 作者 char publisher[50]; // 出版社 double price; // 定价 }b1 {修仙,张三,天上,99.99}; int main() { struct Book* ptr b1; printf(书名%s\n, ptr-title); printf(作者%s\n, ptr-author); printf(出版社%s\n, ptr-publisher); printf(定价%.2f\n, ptr-price); return 0; }4.结构体内存对齐对齐规则1. 结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处。2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处。对齐数编译器默认的对齐数与该成员变量大小的比较中的较小值vs中默认的对齐数为83. 结构体总大小为最大对齐数结构体中每个成员变量都有⼀个对齐数所有对齐数中最大的的整数倍。4.如果嵌套了结构体的情况嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体中成员的对齐数的整数倍。练习例1struct S1 { char c1; int i; char c2; }; printf(%d\n, sizeof(struct S1));输出的结果为12。解释因为vs中默认的对齐数8变量大小比char与int的变量大小都大所以可以忽略vs中默认的对齐数而c1在位置 0i是 4 字节起始位置必须是 4 的倍数当前位置是 1所以补 3 字节位置从4开始 占据 4~7c2是 1 字节起始位置必须是 1 的倍数。当前位置是 8满足占据 8当前占了 9 个字节但是结构体内最大成员是 4字节所以总大小必须是 4 的倍数。因此 9 要往上补到 12 字节9,10,11 为末尾 Padding所以总大小为12。可以如图理解练习2struct S2 { char c1; char c2; int i; }; printf(%d\n, sizeof(struct S2));输出结果为8。解释因为vs中默认的对齐数8变量大小比char与int的变量大小都大所以可以忽略vs中默认的对齐数而c1是 1 字节在位置0 c2是1字节起始位置必须是 1 的倍数当前位置是 1满足条件所以不需要补字节 i 是 4 字节起始位置必须是 4 的倍数。当前位置是 2所以需要补 2 字节 从位置 4 开始; 当前占了 8 个字节结构体内最大基本成员是 4字节所以总大小必须是 4 的倍数而8 刚好是 4 的倍数不需要在末尾补字节所以总大小为 8 字节。练习3struct S3 { double d; char c; int i; }; printf(%d\n, sizeof(struct S3));输出结果为16解释因为vs中默认的对齐数8大于或等于double 、int 与char 的变量自身大小所以可以忽略vs中默认的对齐数直接按变量自身大小对齐即可而是 double是8 字节在位置 0 c是 1 字节起始位置必须是 1 的倍数当前位置是 8满足条件所以不需要补字节 i是 4 字节起始位置必须是 4 的倍数。当前位置是 9所以需要补 3 字节从位置 12 开始当前占了 16 个字节结构体内最大基本成员是 8字节所以总大小必须是 8 的倍数而 16 刚好是 8 的倍数不需要在末尾补字节所以总大小为 16 字节。练习4struct S4 { char c1; struct S3 s3; double d; }; printf(%d\n, sizeof(struct S4)); //结构体嵌套输出结果为32解释因为VS中默认的对齐数8大于或等于char 和double 的变量自身大小也大于等于嵌套结构体s3的内部最大基本成员double8字节的大小所以其实可以忽略VS中默认的对齐数即它们都是被自身大小限制取min后不变而c1 是1字节在位置 0 s3 是嵌套结构体自带 16 字节大小它的对齐要求取它内部最大基本成员和默认对齐数的较小值即s3min(8, 8) 8d所以起始位置必须是 8 的倍数当前位置是 1所以需要补 7 字节从位置 8 开始占据16个也就是位置 8 ~ 23 d 是 8 字节起始位置必须是 8 的倍数。当前位置是 24刚好满足条件不需要补字节从位置 24 开始占据位置 24 ~ 31 当前占了 32 个字节结构体 内包含嵌套的结构体最大基本成员是 8字节总大小对齐要求是 8 的倍数。而 32 刚好是 8 的倍数不需要在末尾补字节所以总大小为 32 字节。为什么存在内存对齐?原因如果访问未对齐的内存编译器需要作两次内存访问而对齐的内存访问仅需要⼀次访问例如我们访问一个结构体中包含char类型的i和int类型的a如果是未对齐的内存这个结构体大小为5访问a时就要两次内存访问而对齐的内存访问仅需要⼀次访问总体来说结构体的内存对齐是拿空间来换取时间的做法。

更多文章