C语言结构体详解:从定义、内存对齐到指针访问

小鹿同学
小鹿同学
发布时间:2026-10-13 | 2人浏览过
原创

C语言中的结构体(struct)是将不同数据类型组合在一起的自定义类型。掌握其正确用法不仅涉及基础声明,更关键的是理解编译器如何分配内存,特别是“内存对齐”带来的空间优化问题,以及如何利用指针安全地读取数据。

结构体的基本定义与实例化

结构体的本质是一组值的集合,允许将逻辑上相关的数据打包在一起。在使用 struct 关键字定义结构体后,开发者有多种方式创建其实例:

  • 定义时初始化:直接在 main 函数中为成员赋值。
  • 全局或局部声明:在代码块外统一声明变量名。
#include <stdio.h>

// 定义用户信息结构体
struct User {
	char uName[20];
	char uPass[20];
};

int main() {
	// 方式1:定义同时初始化
	struct User u1 = {
		"abc", "123"
	};
	printf("%s\n", u1.uName);
	printf("%s\n", u1.uPass);

	// 方式2:先声明后使用
	struct User u2;
	u2 = {"user2", "pwd2"};
	
	return 0;
}

特殊声明写法

除了标准写法,结构体还有一些特殊的语法形式,了解它们有助于阅读更复杂的开源代码:

  1. 定义即声明多个实例:在结构体定义的结尾直接列出多个变量名。
  2. 匿名结构体:没有标签的结构体,定义后可直接使用,但无法再次定义新对象,通常用于一次性场景或局部作用域。
// 同时声明了 u1, u2, u3
struct User {
	char uName[20];
	char uPass[20];
} u1, u2, u3;

// 独立声明
struct User u4;

// 匿名结构体示例(仅限当前作用域有效)
struct {
	char name[20];
} x;

链表中常用的自引用结构体

在实际工程中最常见的结构体嵌套是“自引用”,典型如单链表。由于结构体本身大小未知,不允许结构体内包含同类型的完整对象(否则会导致无限递归的大小定义),因此只能包含指向自身的指针。

#include <stdio.h>

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

int main() {
	struct Node a = { 333, NULL };
	struct Node b = { 666, &a }; // b.next 指向 a
	
	// 通过指针访问a的val
	printf("%d\n", (&b)->next->val);
	return 0;
}

深入核心:内存对齐规则

C语言为了提升CPU访问数据的效率,规定了严格的内存对齐规则。如果在计算结构体 sizeof 时出现数值不符合预期,通常是未理解对齐规则所致。

内存对齐的三个关键原则

  1. 首地址对齐:结构体的起始地址必须是其最大成员对齐数(或编译器默认对齐值,如VS通常为8字节)的倍数。
  2. 成员偏移量对齐:每个成员的相对地址必须是对齐数的整数倍。该对齐数是以下两者的较小值:
    • 编译器默认的对该平台的对齐数(常见为4或8);
    • 该成员自身占用的字节数。
  3. 总大小对齐:整个结构体的大小必须是内部最大对齐数的整数倍,若不够则末尾会自动填充(Padding)字节。

案例演示:成员顺序对大小的影响

下面通过三种不同的成员排列组合,直观展示对齐规则的效果:

情况一:int + char + char(大小为 8 字节)

struct A {
    int a;      // 占4字节,偏移0(4的倍数)
    char b;     // 占1字节,偏移4(无需填充)
    char c;     // 占1字节,偏移5(无需填充)
};
// 总占用6字节,补齐至4的倍数 -> 8

情况二:char + int + char(大小为 12 字节)

struct A {
    char b;     // 占1字节,偏移0
    // 需填补3个空字节,使下一个int从第4字节开始
    int a;      // 占4字节,偏移4(4的倍数)
    char c;     // 占1字节,偏移8
    // 总占用9字节,补齐至4的倍数 -> 12
};

情况三:char + char + int(大小为 8 字节)

struct A {
    char b;     // 占1字节,偏移0
    char c;     // 占1字节,偏移1
    // 需填补2个空字节,使下一个int从第5字节开始
    int a;      // 占4字节,偏移4(4的倍数)
};
// 总占用8字节,恰好对齐 -> 8

结构体指针的高效访问

当需要操作指向结构体的指针时,除了使用解引用和点号运算符,C语言提供了更直观的箭头运算符 >>。

假设有一个结构体指针 ptr:

struct A a = { 333 };
struct A* ptr = &a;

// 推荐写法
printf("%d\n", ptr->a);

// 等价于传统写法
printf("%d\n", (*ptr).a); 

以上就是C语言结构体详细用法与底层内存布局的详细内容,更多关于C/C++指针与内存管理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表