C语言结构体入门:定义、访问与传参全解析

在C语言中,结构体(struct)是处理复杂数据的核心工具------它能将不同类型的数据(如字符串、整数)封装成一个整体,特别适合描述真实世界中的实体(比如学生、员工、商品)。本文将通过"学生信息管理"的实例,从零讲解结构体的定义、三种访问方式,以及函数传参的两种常用形式,搭配完整代码演示,帮你快速掌握结构体核心用法。

一、结构体基础:如何定义一个"数据模板"

结构体的本质是自定义数据类型,我们先定义一个"学生"模板,包含姓名、年龄、性别、学号四个属性:

// 方式1:直接定义结构体类型

struct stu

{

char name20; // 姓名(字符串数组存储)

int age; // 年龄(整型)

char sex5; // 性别(字符串数组,兼容多字符)

char id23; // 学号(字符串数组,适配长学号)

};

// 方式2:用typedef给结构体起"别名"(更简洁)

typedef struct stu

{

char name20;

int age;

char sex5;

char id23;

} stp1; // stp1是struct stu的别名,后续可直接用stp1定义变量

  • 关键点: typedef 的作用是简化类型名,避免每次定义变量都写 struct stu ,直接用 stp1 即可,代码更简洁(后文以别名方式为主演示)。

二、结构体变量的三种访问方式

定义结构体变量后,有三种常用方式访问其内部成员,核心区别在于是否使用指针。我们先定义变量和指针,再逐一演示:

// 定义结构体变量并初始化

stp1 st1 = {"龙傲天", 20, "男", "124124552"};

stp1* p = &st1; // 定义指针p,指向结构体变量st1的地址

  1. 直接访问:变量名.成员名(最直观)

通过"变量名 + 点号(.) + 成员名"直接访问,适合非指针场景:

printf("姓名:%s\n", st1.name); // 输出:龙傲天

printf("年龄:%d\n", st1.age); // 输出:20

printf("性别:%s\n", st1.sex); // 输出:男

printf("id:%s\n", st1.id); // 输出:124124552

  1. 解引用访问:(*指针).成员名(指针场景基础用法)

如果拿到的是结构体指针,需先通过 * 解引用获取指针指向的变量,再用点号访问成员(注意括号不能少, * 优先级低于 . ):

printf("姓名:%s\n", (*p).name); // 解引用p,等价于st1.name

printf("年龄:%d\n", (*p).age); // 输出:20

  1. 指向符访问:指针->成员名(指针场景简化用法)

C语言专门为结构体指针提供了简化语法 -> ,直接用"指针名 + -> + 成员名"访问,无需解引用,是指针场景的首选:

printf("姓名:%s\n", p->name); // 等价于(*p).name,更简洁

printf("年龄:%d\n", p->age); // 输出:20

三种方式效果对比

运行代码后,三种访问方式输出结果完全一致:

plaintext

姓名:龙傲天

年龄:20

性别:男

id:124124552

==========================

姓名:龙傲天

年龄:20

性别:男

id:124124552

==========================

姓名:龙傲天

年龄:20

性别:男

id:124124552

  • 总结:非指针用 变量.成员 ,指针用 指针->成员 (推荐), (*指针).成员 是等价写法但稍繁琐。

三、结构体函数传参:两种方式对比

结构体变量可作为函数参数传递,核心有两种方式:值传递和指针传递,我们通过两个函数演示差异。

  1. 指针传参:void ad1(stp1* p)

将结构体变量的地址(指针)传给函数,函数内部通过 -> 访问成员:

void ad1(stp1* p)

{

printf("姓名:%s\n", p->name);

printf("年龄:%d\n", p->age);

printf("性别:%s\n", p->sex);

printf("id:%s\n", p->id);

}

// 调用方式:传入指针p或&st1

ad1(p); // 正确

ad1(&st1); // 也正确,直接传变量地址

  1. 值传递:void ad2(stp1 st1)

将结构体变量的"副本"传给函数,函数内部通过 变量.成员 访问:

void ad2(stp1 st1)

{

printf("姓名:%s\n", st1.name);

printf("年龄:%d\n", st1.age);

printf("性别:%s\n", st1.sex);

printf("id:%s\n", st1.id);

}

// 调用方式:直接传入结构体变量

ad2(st1);

两种传参方式核心区别

传参方式 优点 缺点 适用场景

指针传递 不拷贝数据,效率高;可修改原变量 需注意指针合法性(避免野指针) 结构体较大、需修改原数据

值传递 语法简单,不影响原变量 拷贝整个结构体,占用内存多、效率低 结构体较小、无需修改原数据

传参效果演示

调用两个函数后,输出结果与直接访问一致:

plaintext

============指针传参==============

姓名:龙傲天

年龄:20

性别:男

id:124124552

==========================

姓名:龙傲天

年龄:20

性别:男

id:124124552

四、完整可运行代码(含三种访问+两种传参)

#include <stdio.h> // 包含printf函数所需头文件

// 用typedef定义结构体并起别名stp1

typedef struct stu

{

char name20;

int age;

char sex5;

char id23;

} stp1;

// 指针传参函数

void ad1(stp1* p)

{

printf("姓名:%s\n", p->name);

printf("年龄:%d\n", p->age);

printf("性别:%s\n", p->sex);

printf("id:%s\n", p->id);

}

// 值传递函数

void ad2(stp1 st1)

{

printf("姓名:%s\n", st1.name);

printf("年龄:%d\n", st1.age);

printf("性别:%s\n", st1.sex);

printf("id:%s\n", st1.id);

}

int main()

{

// 定义并初始化结构体变量

stp1 st1 = {"龙傲天", 20, "男", "124124552"};

stp1* p = &st1; // 定义结构体指针

// 方式1:直接访问(变量.成员)

printf("==========直接访问==========\n");

printf("姓名:%s\n", st1.name);

printf("年龄:%d\n", st1.age);

printf("性别:%s\n", st1.sex);

printf("id:%s\n", st1.id);

// 方式2:解引用访问((*指针).成员)

printf("==========解引用访问==========\n");

printf("姓名:%s\n", (*p).name);

printf("年龄:%d\n", (*p).age);

printf("性别:%s\n", (*p).sex);

printf("id:%s\n", (*p).id);

// 方式3:指向符访问(指针->成员)

printf("==========指向符访问==========\n");

printf("姓名:%s\n", p->name);

printf("年龄:%d\n", p->age);

printf("性别:%s\n", p->sex);

printf("id:%s\n", p->id);

// 指针传参调用

printf("==========指针传参==========\n");

ad1(p);

// 值传递调用

printf("==========值传递==========\n");

ad2(st1);

return 0;

}

五、学习总结

  1. 结构体是"自定义数据类型",用于封装不同类型的关联数据,定义时可通过 typedef 起别名简化语法;

  2. 成员访问三剑客: 变量.成员 (非指针)、 (*指针).成员 (指针解引用)、 指针->成员 (指针简化,推荐);

  3. 函数传参二选一:指针传递(高效、可修改原数据)、值传递(简单、不影响原数据),优先用指针传递尤其是结构体较大时;

  4. 实操关键:初始化字符串用双引号,数组长度要预留足够空间(如姓名20位、学号23位),避免越界。

结构体是C语言面向对象编程的基础雏形,掌握它后,后续处理数组、链表、文件操作中的复杂数据会更轻松。建议多修改代码(比如添加"成绩"成员、修改传参逻辑),加深理解~

相关推荐
小小de风呀12 分钟前
de风——【从零开始学习C++】(十八):AVL树——让二叉搜索树自己“站起来“的自平衡黑科技
c++·科技·学习
MartinYeung543 分钟前
[论文学习]MCPTox:面向真实世界MCP服务器的工具投毒攻击基准测试
运维·服务器·学习
Chen—LSN1 小时前
C语言——数据在内存中的存储
c语言·开发语言·经验分享·笔记
math_hongfan1 小时前
事务下单与状态流转:ArkTS 的 JOIN 联表在鸿蒙订单里实战
android·学习·华为·harmonyos
caimouse1 小时前
ReactOS 图形系统分析(24):指针(光标)管理 — mouse.c/h
c语言·开发语言
caimouse1 小时前
ReactOS 图形系统分析(23):引擎内存管理 — mem.c
c语言·开发语言
caimouse1 小时前
ReactOS 图形系统分析(15):窗口对象 — EWNDOBJ(engwindow.c)
c语言·开发语言
weixin_431600441 小时前
NestJS 入门(9):连上数据库,SQL 写在哪?
数据库·后端·sql·学习·nest.js
举手1 小时前
Epoll模型
linux·c++·学习
MartinYeung52 小时前
[论文学习]JBShield:通过激活概念分析与操纵防御大语言模型越狱攻击
人工智能·学习·语言模型