1.示例代码
#include <stdio.h>
// 定义包含三个char类型成员变量的结构体
typedef struct{
char a;
char b;
char c;
char d[5];
}MyStruct;
int main() {
// 定义结构体变量
MyStruct myStruct;
// 定义指向结构体的指针
char *ptr = &(myStruct.a); // 指向结构体第一个成员a的地址
// 通过指针进行偏移赋值
*ptr = 'X'; // 赋值a成员为'X'
ptr++; // 将指针向后移动一个char大小的偏移量
*ptr = 'Y'; // 赋值b成员为'Y'
ptr++; // 再次向后移动一个char大小的偏移量
*ptr = 'Z'; // 赋值c成员为'Z'
for (int i = 0; i < 5; i++)
{
ptr[i] = '0' + i; // 对d数组赋值
}
// 遍历打印结构体中的数据
// 打印结果为:x y z 0 1 2 3 4
#if 0
ptr = &(myStruct.a); // 重新指向a成员的地址 (结构体的起始地址和a成员的地址相等)
#else
ptr = (char *)&myStruct; // 重新指向结构体的起始地址 (a成员的地址和结构体的起始地址相等)
#endif
for (int i = 0; i < sizeof(MyStruct); i++)
{
#if 0
printf("%c ", *ptr);
ptr++; // 向后移动一个char大小的偏移量
#else
printf("%c ", *(ptr + i));
#endif
}
return 0;
}
2 . 指针自增
在上述代码中指针的自增操作ptr++并不是与指针所指向的数据类型直接相关的,而是与指针所指向的内存单元的大小有关。
指针自增操作会使指针指向下一个相邻的内存单元,其步长取决于指针所指向的数据类型的大小。
不同指针类型的自增 | 地址偏移长度(BYTE) |
---|---|
(char *) ptr++ | 1 |
(short *) ptr++ | 2 |
(int *) ptr++ | 4 |
(float *) ptr++ | 4 |
对于char类型的指针,无论指针所指向的数据类型是什么,自增操作都会使得指针向后移动一个字节的大小,因为char类型的大小就是1个字节。
对于其他数据类型比如int、float等,指针自增操作会使得指针向后移动相应数据类型的大小。
因此,尽管我们在示例中使用了char类型的指针来访问和操作结构体中的char类型成员变量,但其自增操作的长度并不是与结构体成员变量的类型直接相关的,而是根据指针所指向的数据类型的大小来确定的。
3 . sizeof获取结构体大小
typedef struct{
char a;
char b;
char c;
char d[5];
}MyStruct;
MyStruct myStruct;
sizeof(myStruct)
sizeof(MyStruct)
在上述代码中,sizeof(myStruct)和sizeof(MyStruct)的区别在于:
sizeof(myStruct):
这个表达式返回的是myStruct这个结构体变量的大小。也就是说,它会返回分配给myStruct实例的内存空间大小,包括结构体中所有成员变量和可能的填充字节。
sizeof(MyStruct):
这个表达式返回的是MyStruct这个结构体类型的大小。它表示的是MyStruct所占用的内存大小,包括结构体中所有成员变量的大小以及可能的填充字节。
通常情况下,sizeof(MyStruct)应该等于在myStruct实例化之后的sizeof(myStruct),因为它们都代表了同一个结构体类型的大小。
但是在某些情况下,由于编译器的内存对齐和填充策略,可能会导致sizeof(myStruct)与sizeof(MyStruct)不相等。
这种情况下,sizeof(myStruct)可能会大于sizeof(MyStruct),因为结构体实例可能会包含一些填充字节,而sizeof(MyStruct)只是结构体类型本身的大小。
所以,获取结构体的大小应该使用sizeof(MyStruct)这种方式。这样可以直接得到结构体类型的大小,而不会受到具体实例化的影响。
因为结构体实例化后可能会存在填充字节或者对齐导致的变化,直接使用结构体类型的大小能够更准确地反映结构体所占用的内存大小。