当前位置:首页 > 技术 > 正文内容

C语言结构体深入解析:声明、内存对齐与传参

访客 技术 2026年7月5日 4

结构体基础声明

结构体是一种用户自定义的数据类型,它将不同类型的数据组合成一个整体。每个组成部分被称为成员变量。

声明语法

struct 标签
{
    数据类型 成员1;
    数据类型 成员2;
    // ... 更多成员
};  // 注意分号

例如,定义一个学生结构体:

struct Student {
    char name[30];
    int age;
    char gender[10];
};

变量创建与初始化

#include <stdio.h>

struct Student {
    char name[30];
    int age;
    char gender[10];
    char student_id[20];
};

int main() {
    // 按成员顺序初始化
    struct Student stu1 = {"Alice", 22, "Female", "202401001"};
    printf("Name: %s\n", stu1.name);
    printf("Age: %d\n", stu1.age);
    printf("Gender: %s\n", stu1.gender);
    printf("ID: %s\n", stu1.student_id);

    // 指定成员初始化
    struct Student stu2 = {.age = 20, .name = "Bob", .student_id = "202401002", .gender = "Male"};
    printf("Name: %s\n", stu2.name);
    printf("Age: %d\n", stu2.age);
    printf("Gender: %s\n", stu2.gender);
    printf("ID: %s\n", stu2.student_id);

    return 0;
}

匿名结构体

声明结构体时可以省略标签,创建匿名结构体类型:

// 匿名结构体,直接定义变量
struct {
    int x;
    char y;
    float z;
} point;

// 可用于数组或指针
struct {
    int x;
    char y;
    float z;
} points[10], *ptr;

匿名结构体无法重复使用,仅适用于一次性定义。

结构体自引用

结构体内部不能包含自身类型的完整实例,否则会导致无限递归。正确的做法是使用指针:

// 错误声明
struct Node {
    int data;
    struct Node next;  // 编译错误
};

// 正确声明
struct Node {
    int data;
    struct Node* next;  // 使用指针
};

当与typedef结合时需注意:

// 错误用法:匿名结构体内无法使用Node
typedef struct {
    int data;
    Node* next;  // 编译错误:Node尚未定义
} Node;

// 正确用法
typedef struct Node {
    int data;
    struct Node* next;
} Node;

结构体内存对齐

结构体大小并非成员大小的简单相加,而是遵循内存对齐规则。这是由硬件和性能需求决定的。

对齐规则

  1. 第一个成员:从偏移量为0的地址开始存储。
  2. 其他成员:存储地址必须是对齐数的整数倍。对齐数 = min(编译器默认对齐数, 成员自身大小)。
  3. 结构体总大小:必须是最大对齐数的整数倍。
  4. 嵌套结构体:嵌套结构体对齐到其内部最大对齐数的整数倍处,总大小为所有最大对齐数(含嵌套结构体)的整数倍。

注意:VS默认对齐数为8,Linux GCC无默认对齐数(对齐数等于成员自身大小)。

示例分析

struct S1 {
    char c1;
    int i;
    char c2;
};  // 大小:12字节

struct S2 {
    char c1;
    char c2;
    int i;
};  // 大小:8字节

struct S3 {
    double d;
    char c;
    int i;
};  // 大小:16字节

struct S4 {
    char c1;
    struct S3 s3;
    double d;
};  // 大小:32字节

可以看到,成员顺序影响结构体大小。将小成员集中放置可节省空间,如S2比S1节省了4字节。

修改默认对齐数

#include <stdio.h>
#pragma pack(1)  // 设置对齐数为1

struct PackedStruct {
    char c1;
    int i;
    char c2;
};  // 大小:6字节

#pragma pack()  // 恢复默认对齐数

int main() {
    printf("Size: %zu\n", sizeof(struct PackedStruct));
    return 0;
}

结构体传参

传递结构体时,推荐使用指针而非值传递,以减少系统开销:

#include <stdio.h>

struct LargeData {
    int array[1000];
    int count;
};

struct LargeData data = {{1, 2, 3, 4}, 1000};

// 值传递:复制整个结构体,开销大
void print_by_value(struct LargeData d) {
    printf("Count: %d\n", d.count);
}

// 指针传递:仅复制地址,效率高
void print_by_address(struct LargeData* pd) {
    printf("Count: %d\n", pd->count);
}

int main() {
    print_by_value(data);     // 传结构体
    print_by_address(&data);  // 传地址
    return 0;
}

指针传递避免了结构体的完整拷贝,特别是当结构体较大时,能显著提升性能。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。