C语言升级打怪之小小结构体

结构体,是C语言中一种重要的数据类型,它允许你将不同类型的数据组合成一个整体,以便于更好地组织和处理数据。你可以将结构体看作是一个容器,里面可以存放各种类型的数据。

目录

一.结构体的声明

1.一般情况

2.特殊声明

二.结构体变量的创建和初始化

三.结构体的自引用(链表)

四.结构体内存对齐

1.对齐规则

2.修改默认对齐数 

五.结构体传参

六.结构体实现位段

七.总结



一.结构体的声明

1.一般情况

struct 结构体名 {
    数据类型 成员名1;
    数据类型 成员名2;
    ...
    数据类型 成员名n;
}; //注意分号不能少

其中,struct是定义结构体的关键字,结构体名是你给这个结构体起的名字,成员名则是结构体中各个成员的名称,数据类型则指定了成员的数据类型。 

举个例子,如果你想要定义一个表示学生的结构体,可以这样做:


struct Student {
    char name[20];
    int age;
    float score;
};

 在这个例子中,我们定义了一个名为Student的结构体,它包含三个成员:name(表示学生的姓名,是一个字符数组)、age(表示学生的年龄,是一个整数)和score(表示学生的成绩,是一个浮点数)。

2.特殊声明

struct
 {
     int a;
     char b;
     float c;
 }x;

 匿名结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。


二.结构体变量的创建和初始化

定义了结构体之后,你就可以创建结构体的变量了。

创建结构体变量的语法如下:
 ①struct 结构体名 变量名;
 

#include <stdio.h>
 struct Stu
 {
     char name[20];//名字
 
    int age;//年龄
 
    char sex[5];//性别
 
    char id[20];//学号
};
 int main()
 { 
    //按照结构体成员的顺序初始化
     struct Stu s = { "张三", 20, "男", "20230818001" };
     printf("name: %s\n", s.name);
     printf("age : %d\n", s.age);
     printf("sex : %s\n", s.sex);
     printf("id  : %s\n", s.id);
    
   //按照指定的顺序初始化
     struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "⼥"};
     printf("name: %s\n", s2.name);
     printf("age : %d\n", s2.age);
     printf("sex : %s\n", s2.sex);
     printf("id  : %s\n", s2.id);
     return 0;
 }

struct 结构体名 {....}变量名;

#include <stdio.h>
 struct Stu
 {
     char name[20];//名字
     
    int age;//年龄
 
    char sex[5];//性别
 
    char id[20];//学号
 
  }s,s2;
 int main()
 {
     //按照结构体成员的顺序初始化
 
     s = { "张三", 20, "男", "20230818001" };
     printf("name: %s\n", s.name);
     printf("age : %d\n", s.age);
     printf("sex : %s\n", s.sex);
     printf("id  : %s\n", s.id);

   //按照指定的顺序初始化
 
     s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "⼥"};
     printf("name: %s\n", s2.name);
     printf("age : %d\n", s2.age);
     printf("sex : %s\n", s2.sex);
     printf("id  : %s\n", s2.id);
     return 0;
 }

三.结构体的自引用(链表)

struct Node
 {
 int data;
 struct Node* next;
 };

如果没有*是错误的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的大小就会无穷的大,是不合理的

 

四.结构体内存对齐

1.对齐规则

 1.结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处

 2.其他成员变量要对齐到对齐数的整数倍的地址处。

         对齐数=编译器默认的⼀个对齐数与该成员变量大小的较小值

        - V S 中默认的值为 8

        - Linux中gcc没有默认对齐数,对齐数就是成员自身的大小

3. 结构体总大小为最⼤对齐数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的 整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

struct S1
 {
 char c1;
 int i;
 char c2;
 };
 printf("%d\n", sizeof(struct S1));

分析如下图所示

2.修改默认对齐数 

#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1 
struct S
 {
     char c1;
     int i;
     char c2;
 };
 #pragma pack()//取消设置的对⻬数,还原为默认
 
int main()
 {
     //输出的结果是什么?
     printf("%d\n", sizeof(struct S));
     return 0;
 }

五.结构体传参

结构体还可以作为函数参数进行传递

struct S
 {
     int data[1000];
     int num;
 };
 struct S s = {{1,2,3,4}, 1000};

 //结构体传参
void print1(struct S s)
 {
 printf("%d\n", s.num);
 }

 //结构体地址传参
 void print2(struct S* ps)
 {
     printf("%d\n", ps->num);
 }
 int main()
 {

    print1(s);  //传结构体
    print2(&s); //传地址
    return 0;
 }

二者之间首选print2函数 

原因: 函 数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销较大,所以会导致性能的下降。

结论: 结构体传参的时候,要传结构体的地址。

六.结构体实现位段

位段的声明和结构是类似的,有两个不同:

1. 位段的成员必须是 int 或char ,在C99中位段成员的类型也可以 选择其他类型。

2. 位段的成员名后边有⼀个冒号和⼀个数字

 struct A
 {
     int _a:2;
     int _b:5;
     int _c:10;
     int _d:30;
 };

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

struct S
 {
 char a:3; //a占3个比特
 char b:4;
 char c:5;
 char d:4;
 };
 struct S s = {0};
 s.a = 10;
 s.b = 12;
 s.c = 3;
 s.d = 4;

位段的几个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位 置处是没有地址的不能对位段的成员使⽤&操作符

七.总结

总之,结构体是C语言中一种非常灵活和强大的数据类型,它可以帮助你更好地组织和处理复杂的数据结构。 

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值