C语言结构体的内存对齐以及指针访问

在学C和使用C的道路上,我遇见了许许多多有趣的细节,因为不想忘记,所以我把它们一个个的依次记录在这里,并且将坚持记录。
我知道或许这里的很多知识对于以后的我来说或许显得无比幼稚,乏善可陈。但,或许它们是我以后生活中难能可贵的回忆。
记录此文,仅以镜鉴,或者纪念。


1.结构体的内存对齐

a.结构体的一般情况

今天在写题目的时候,看到了一道很有趣的题目:

若有定义
struct stu
{char name[10];int num;} s ;
那么,s在内存中所占的字节数为()

如果在不熟悉结构体特性的情况下,会算成1Byte*10 + 4Byte=14Byte
但是,答案真的是这样吗?
我们来尝试一下:
利用sizeof运算符写代码如下:

#include <stdio.h>
#include <stdlib.h>

struct stu
{
    char name[10];
    int num;
} s;

int main()
{
    int n=sizeof(s);
    printf("%d",n);
    return 0;
}

结果是:

16

那么为什么会出现这种情况呢,原因是结构体变量分配内存时有个叫做内存对齐的原则:

(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。

用图来表示可能更直观一些:

char|char|char|char
char|char|char|char
char|char|    |    
|    int占四字节   |

但是还要注意:结构体成员的顺序影响结构体分配内存的大小
例如:

struct stu1
{ 
       char c1; 
       int i;
       char c2;
}
struct stu2
{
       char c1;
       char c2;
       int i;
 }

这两个结构体所占内存的大小是不相同的,第一个结构体占12Byte,第二个结构体占8Byte,如下图:

stu1:
char|    |    |    |
|       int        |
char|    |    |    |	//3*4=12

stu2:
char|char|    |    |
|       int        |	//2*4=8

b.结构体嵌套

那么如果我们遇见结构体嵌套怎么办呢?

(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。

举个例子来说明:

struct stu5
{
      short i;
      struct 
      {
           char c;
           int j;
      } ss; 	//ss占据8Byte
      int k;
}		//该结构体总占据16Byte

显然,此结构体是占据16Byte,在此不再详述图解。

3.一些其他细节

此外需要注意的是:

  • 如果结构体成员是数组,那么算其整数倍为数组最小单元所占的内存的整数倍,而非整个数组所有单元总和的整数倍。即int array[10]的整数倍是4的整数倍而非40的整数倍。
  • 静态数据成员的存放位置与结构体实例的存储地址无关(注意只有在C++中结构体中才能含有静态数据成员,而C中结构体中是不允许含有静态数据成员的)。a是单独存放在静态数据区的,因此用siezof计算其大小时不会将a所占的空间计算进来。
  • 编译器不会为结构体分配内存,只会为结构体成员分配内存

2.结构体指针的两种访问成员方法

我们先来认识一下->符号:

“->”是一个整体,它是用于指向结构体子数据的指针,用来取子数据。
换种说法,如果我们在C语言中定义了一个结构体,然后申明一个指针指向这个结构体,那么我们要用指针取出结构体中的数据,就要用到“->”。

是不是感觉还是没有完全理解,那我们看个例子:

#include <stdio.h>

struct{
int day;
char mouth;
int year;
}a,*b;
int main()
{
	b=&a;
	return 0;
}

显然,我们可以利用a.day来引用结构成员,那么如果我们想要通过b来引用结构体成员,你能想到该怎么做呢?
答案是:b->day*b.day

第一种引用很好理解,就是用->来访问结构体成员
第二种呢,因为b是a的指针(b=&a),所以我们通过*来对b解引用(或称:取值),就可以访问到a的结构体成员day了。


部分资料参考自:
https://blog.csdn.net/szchtx/article/details/8801583
https://blog.csdn.net/qq_41068271/article/details/83446623

posted @   言念君君子  阅读(120)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示