学懂C语言(二十三):深入学习C语言 结构体及其大小的计算

        

目录

一、结构体的定义

二、结构体变量的声明

三、访问结构体成员

四、结构体初始化

五、结构体指针

六、结构体数组

七、结构体嵌套

八、类型定义和结构体

九、结构体与函数

十、结构体大小的计算(*重点)

结构体成员的顺序对结构体的总大小的影响:(*重点)

小结


构体是C语言中一种用来将不同类型的数据聚合在一起的复合数据类型。结构体使得我们可以定义一种新的数据类型,它由若干个其他数据类型的变量组成,这些变量可以是不同类型的。通过结构体,可以更加方便地组织和管理复杂的数据。

一、结构体的定义

在C语言中,可以使用 struct 关键字来定义一个结构体。定义一个结构体的基本语法如下:

struct 结构体名 {
    数据类型1 成员名1;
    数据类型2 成员名2;
    // 其他成员
};

例如,定义一个表示点(Point)的结构体:

struct Point {
    int x;
    int y;
};

二、结构体变量的声明

定义结构体之后,可以使用该结构体类型来声明变量:

struct Point p1;

也可以在定义结构体时同时声明结构体变量:

struct Point {
    int x;
    int y;
} p1, p2;

三、访问结构体成员

使用点运算符 . 来访问结构体变量的成员:

p1.x = 10;
p1.y = 20;
printf("Point p1: (%d, %d)\n", p1.x, p1.y);

四、结构体初始化

可以在声明结构体变量时进行初始化:

struct Point p1 = {10, 20};

还可以通过指定成员名的方式进行初始化(C99标准引入):

struct Point p1 = {.x = 10, .y = 20};

五、结构体指针

可以使用指针来访问结构体的成员。对于结构体指针,可以使用箭头运算符 -> 访问成员:

struct Point p1 = {10, 20};
struct Point *pPtr = &p1;

pPtr->x = 30;
pPtr->y = 40;
printf("Point p1: (%d, %d)\n", pPtr->x, pPtr->y);

六、结构体数组

可以声明结构体类型的数组:

struct Point points[3] = {{1, 2}, {3, 4}, {5, 6}};

七、结构体嵌套

结构体成员可以是其他结构体类型:

struct Point {
    int x;
    int y;
};

struct Circle {
    struct Point center;
    int radius;
};

struct Circle c = {{0, 0}, 5};
printf("Circle: Center(%d, %d), Radius %d\n", c.center.x, c.center.y, c.radius);

八、类型定义和结构体

可以使用 typedef 关键字为结构体类型定义一个别名,以简化结构体类型的使用:

typedef struct {
    int x;
    int y;
} Point;

Point p1 = {10, 20};

九、结构体与函数

结构体可以作为函数参数和返回值:

void printPoint(struct Point p) {
    printf("Point: (%d, %d)\n", p.x, p.y);
}

struct Point createPoint(int x, int y) {
    struct Point p;
    p.x = x;
    p.y = y;
    return p;
}

int main() {
    struct Point p1 = createPoint(10, 20);
    printPoint(p1);
    return 0;
}

十、结构体大小的计算(*重点)

C 语言中,我们可以使用 sizeof 运算符来计算结构体的大小,sizeof 返回的是给定类型或变量的字节大小。

对于结构体,sizeof 将返回结构体的总字节数,包括所有成员变量的大小以及可能的填充字节。

以下实例演示了如何计算结构体的大小:

#include <stdio.h>

struct Person {
    char name[20];
    int age;
    float height;
};

int main() {
    struct Person person;
    printf("结构体 Person 大小为: %zu 字节\n", sizeof(person));
    return 0;
}

        以上实例中,我们定义了一个名为 Person 的结构体,它包含了一个字符数组 name、一个整数 age 和一个浮点数 height

在 main 函数中,我们声明了一个 Person 类型的变量 person,然后使用 sizeof 运算符来获取 person 结构体的大小。

最后,我们使用 printf 函数打印出结构体的大小,输出结果如下:

结构体 Person 大小为: 28 字节

注意,结构体的大小可能会受到编译器的优化和对齐规则的影响,编译器可能会在结构体中插入一些额外的填充字节以对齐结构体的成员变量,以提高内存访问效率。因此,结构体的实际大小可能会大于成员变量大小的总和,如果你需要确切地了解结构体的内存布局和对齐方式,可以使用 offsetof 宏和 __attribute__((packed)) 属性等进一步控制和查询结构体的大小和对齐方式。

结构体成员的顺序对结构体的总大小的影响:(*重点)

考虑以下结构体:以8字节对齐计算

struct A {
    char c;
    int i;
    double d;
};

内存布局及大小计算如下:

  1. 成员cchar 类型,占1字节。
  2. 成员iint 类型,占4字节。为了对齐int类型,成员 i 需要从4字节对齐的地址开始。因此,在成员 c 之后会插入3个填充字节。
  3. 成员ddouble 类型,占8字节。为了对齐double类型,成员 d 需要从8字节对齐的地址开始。

布局如下:

|  c  | padding |   i   |     d      |
| 1B  |   3B    |  4B   |    8B      |

总大小为 16 字节。

现在我们改变成员顺序:以8字节对齐计算

struct B {
    char c;
    double d;
    int i;
};

 内存布局及大小计算如下:

  1. 成员cchar 类型,占1字节。为了对齐结构体的大小,需要在成员 c 之后插入7个填充字节,使结构体的总大小是最大对齐需求的整数倍(这里是8字节对齐)。
  2. 成员ddouble 类型,占8字节。
  3. 成员iint 类型,占4字节。为了对齐结构体的大小,需要在成员 i 之后插入4个填充字节,使结构体的总大小是最大对齐需求的整数倍(这里是8字节对齐)。

布局如下:

|  c (1B)  | padding1 (7B) |    d (8B)    |   i (4B)  | padding2 (4B) |

总大小为 24 字节。

小结

  1. 定义:使用 struct 关键字定义结构体。
  2. 声明变量:可以单独声明变量或在定义时声明。
  3. 访问成员:使用点运算符 . 访问成员,使用箭头运算符 -> 访问指针成员。
  4. 初始化:可以在声明时初始化,也可以使用指定成员名的方式初始化。
  5. 结构体指针:使用指针访问结构体成员。
  6. 结构体数组:可以声明结构体类型的数组。
  7. 嵌套结构体:结构体成员可以是其他结构体类型。
  8. 类型定义:使用 typedef 为结构体定义别名。
  9. 函数使用:结构体可以作为函数参数和返回值。
  10. 结构体大小计算:结构体的大小可能会受到编译器的优化和对齐规则的影响,同时结构体成员的定义顺序对结构体的大小也有影响。

通过结构体,可以方便地组织和管理复杂的数据,使得代码更加清晰和易维护。

  • 51
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿享天开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值