恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

结构体成员访问全解析:从点运算符到箭头运算符的底层原理与实战

  • 首页
  • 资讯中心
  • /
  • 结构体成员访问全解析:从点运算符到箭头运算符的底层原理与实战

相关资讯

python-mastery 练习 1.5:用 Stock 类掌握 Python 对象与类定义 2026/10/5 4:45:27
073链地址哈希表 2026/10/5 4:45:27
Chrome 插件开发实战指南 2026/10/5 4:45:27

最新资讯

RT-Thread IIO 工业 I/O 框架解析:基于 Device Tree io-channels 的通道发现与设备树驱动集成
JSP订餐系统实战:从环境搭建到防重提交与事务控制
《碳硅合抱之锚:一项基于自指宇宙学的协议在技术全面失效与伦理极限冲突下的鲁棒性验证》
MRAM替代EEPROM:PIC18F96J65工业嵌入式存储方案实战
MRAM与STM32L432KC实战:SPI驱动、掉电保护与性能对比
MagiskBoot 两条命令拆包 boot.img:改内核参数不伤砖

今日推荐

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单
YOLOv5 OBB旋转框训练实战:从DOTA数据准备到调参避坑全流程
Zeron 终端、Worktree 与 Diff 面板:像 IDE 一样查看并驱动你的代码变更

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

结构体成员访问全解析:从点运算符到箭头运算符的底层原理与实战

发布时间:2026/10/5 4:45:27
结构体成员访问全解析:从点运算符到箭头运算符的底层原理与实战 先说一个很多初学者容易忽略的事实结构体成员访问本质上不是“取名字”而是在算地址。你用p-name和s.name编译器帮你做的是拿到结构体首地址再加一个偏移量最终定位到那块内存。明白了这一点后面所有关于“点运算符还是箭头运算符”“指针能不能直接用点”的纠结都会迎刃而解。这篇内容我会围绕结构体成员访问的三种主要方式展开结合结构体数组、链表、文件读写、Keil5 调试、Qt/VS 工程里和 MySQL 结构体对接这些高频场景把原理、代码和踩坑记录一起整理出来。不管你是刚学 C 语言的学生还是被嵌入式调试折磨的工程师这篇都适合当一份随查随用的实操笔记。1. 先搞懂结构体在内存里怎么摆的成员访问才有依据很多教材一上来就讲“访问成员用点指针用箭头”却没有解释为什么。我见过太多人死记硬背“有指针用 -没指针用 .”结果遇到“指针用 . 也能编译过”的情况就懵了。要真正理解成员访问得先看结构体在内存里的布局。1.1 结构体变量的内存布局成员顺序和偏移量定义一个结构体本质上是在告诉编译器“帮我申请一块连续内存按我声明的顺序把每个成员的存储空间排好”。struct Student { char id[8]; // 0x00 偏移 int score; // 某个偏移位置 char name[16]; // 再往后 };当你写下struct Student stu;时系统在栈上分配一块连续空间。stu.id的地址就是结构体首地址stu.score的地址是“首地址 某个偏移量”stu.name又在后面。编译器在编译阶段就把这些偏移量算好了所以你写stu.score 90;时生成的机器码大致是“把结构体首地址加上 score 的偏移量把 90 写入那块内存”。这个偏移量不是简单地把每个成员大小加起来因为涉及内存对齐。比如上面这个结构体char id[8]占 8 字节int score占 4 字节但 score 的偏移量通常是 8因为 int 要 4 字节对齐而 8 已经满足char name[16]的偏移量是 12成员紧挨着排。整个结构体的大小是 28而不是简单的 841628看起来一致但换个成员顺序可能就不一样了。比如struct A { char c; // 偏移 0 int i; // 偏移 4中间有 3 个填充字节 char d; // 偏移 8 }; // sizeof(struct A) 12char c占偏移 0int i为了 4 字节对齐被放在偏移 4中间 1、2、3 三个字节是填充的不存数据。struct A总共 12 字节。这就是为什么有时候你用sizeof计算结构体大小发现比自己预估的大原因就是编译器自动插了填充字节。访问成员时编译器已经帮你处理了这些填充字节所以用s.i你永远不用担心“i 到底在哪个位置”编译器计算偏移时会自动跳过填充。这也是我们强调“用成员名访问而不是手动加减偏移”的最根本原因。1.2 点运算符和箭头运算符同一个东西的两副面孔点运算符是给“结构体变量”用的箭头运算符是给“结构体指针”用的。很多人搞混是因为没意识到箭头运算符其实是个语法糖。struct Student stu; struct Student *p stu; // 三种写法完全等价 stu.score 90; (*p).score 90; p-score 90;p-score就是(*p).score的简写。先把指针解引用拿到结构体本体再访问成员。C 语言之父们觉得(*p).score写起来太啰嗦干脆发明了-这个运算符。那为什么“有指针必须用箭头”的说法不完全对因为你用(*p).score也是完全合法的只是不够简洁。反过来如果 p 不是指针而是结构体变量本身那就不能用p-score因为-要求左边必须是“指向结构体的指针”。同理stu.score中 stu 如果是变量stu-score报错。再补充一个 C 里的引用情况。C 的引用是变量的别名不是指针所以访问成员用点不是箭头Student stu; Student ref stu; ref.score 90; // 正确引用用点判断规则其实就一条左边实体是结构体变量本身就用点左边是一个“拿着地址的变量”就用箭头。指针变量保存的是地址所以用箭头引用是别名本质还是那个变量所以用点。2. 成员访问的三种姿势直接、指针、偏移量这部分是全文的核心操作部分。我把成员访问拆成三种姿势从最常用的直接访问到嵌入式里必不可少的指针访问再到偶尔会用到的偏移量访问逐个聊清楚。2.1 直接访问结构体变量定义、初始化和成员的读写直接访问是入门第一课但初始化的细节很多人没吃透。定义一个结构体变量后你至少有三初始化的方式struct Student stu1 {10001, 90, 小明}; // 按声明顺序初始化 struct Student stu2 {.id 10002, .score 85, .name 小红}; // 指定初始化器C99 struct Student stu3; strcpy(stu3.id, 10003); stu3.score 88; strcpy(stu3.name, 小刚);第一种写法要求你记住成员声明的顺序漏掉一个成员后面全部错位。第二种指定初始化器是 C99 才有的我强烈推荐在项目里用这种方式可读性好也不会被成员顺序绑架。第二种还有个好处可以跳过中间某个成员不初始化未指定的成员自动置 0。第三种是先定义后赋值注意给字符串数组赋值不能用stu3.name 小刚;因为name是数组数组名不是左值不能整体赋值得用strcpy。这个坑新手必踩。直接访问的读写操作就是点运算符printf(学号: %s\n, stu1.id); if (stu1.score 60) { printf(%s 及格了\n, stu1.name); }这里有个细节stu1.id虽然看起来是“结构体成员”但它本身就是char[8]数组所以printf用%s可以直接传它因为数组在表达式中退化为指针。你不需要写stu1.id虽然写stu1.id类型上也说得通但这里直接传数组名就行。2.2 指针访问为什么嵌入式代码里几乎全是箭头嵌入式、单片机、驱动开发里结构体几乎没有“本体”传递都是传指针。原因有两个一是结构体可能很大按值传递会整个拷贝一遍浪费栈空间和 CPU二是很多结构体是在堆上动态创建的你手里只有地址。struct Student *pStu (struct Student *)malloc(sizeof(struct Student)); if (pStu NULL) { // 处理分配失败 } strcpy(pStu-id, 10004); pStu-score 92; strcpy(pStu-name, 小李); free(pStu);用指针访问成员时建议养成一个习惯任何指针对成员访问前先判空。一旦pStu是 NULL 或者是个野指针pStu-score 92;这句就是在向任意内存地址写数据轻则数据被篡改重则直接硬件异常。函数参数传递的场景更典型void print_student(struct Student *s) { if (s NULL) return; printf(%s %d %s\n, s-id, s-score, s-name); }如果写成void print_student(struct Student s)每次调用都会把整个结构体拷贝到新栈帧struct Student稍微大点比如有缓冲区数组性能损耗就很明显。传指针只拷贝 432 位或 864 位字节的地址划算得多。但代价是函数可以修改外部结构体内容如果你不希望被修改加constvoid print_student(const struct Student *s) { // s-score 60; // 编译报错不能修改 printf(%s %d %s\n, s-id, s-score, s-name); }链表是另一个离不开箭头运算符的场景。链表节点里存的是下一个节点的地址你要访问当前节点的数据成员用-要跳到下一个节点本质也是访问next成员拿地址struct Node { int data; struct Node *next; }; // 遍历链表 for (struct Node *cur head; cur ! NULL; cur cur-next) { printf(%d , cur-data); }这里cur-next是“访问 cur 指向的节点的 next 成员”拿到的是下一个节点的地址再赋给 cur循环继续。很多初学者会把cur-next-data和cur-data搞混看的时候多问一句“我现在在哪个节点上”2.3 通过偏移量访问底层视角的野路子有点意思但别乱用第三种方式是通过地址偏移直接访问成员这是靠编译器提供的offsetof宏和指针算术实现的。它在正常业务代码里不常用但在协议解析、操作系统内核、某些调试工具里会遇到。#include stddef.h struct Packet { char header[4]; int length; char payload[256]; }; struct Packet pkt; // 通过偏移量访问 length 成员 int len *(int *)((char *)pkt offsetof(struct Packet, length));offsetof(struct Packet, length)在编译期就能算出 length 成员相对结构体首地址的偏移量。这里先把pkt转成char *因为char *加减按字节计算加上偏移量后得到 length 的地址再转成int *解引用拿到值。这种写法在正常工程里不推荐原因有三一是不安全如果你算错偏移等于绕过类型系统去读任意内存二是可读性极差维护的人看到这行代码大概率要骂人三是不同编译器、不同对齐设置下的偏移可能不同可移植性差。真正用它的场景多半是底层代码需要“动态访问某个成员”而编译期无法确定成员名比如内核里统一处理大量结构体的场景。但理解偏移量这个概念非常重要因为在调试时你看到的内存窗口就是按偏移排的。你在 Keil 的 Memory 窗口看结构体其实就是在看“首地址偏移量”处的数据只是工具帮你把名字翻译出来了。3. 实战场景拆解结构体成员访问在不同项目里怎么用前面是基础姿势这一节我把结构体成员访问放到真实项目场景里从数组、链表、文件、嵌入式调试、数据库对接这几个高频场景逐个展开。3.1 结构体数组用下标定位元素再访问成员结构体数组常见于批量管理同类型对象比如一个班级的学生。定义方式是struct Student class1[30];访问第 i 个学生的 score用class1[i].score。这里下标运算发生在数组维度上点运算符作用在“已取出的元素”上优先级要搞清楚。struct Student class1[3] { {10001, 90, 小明}, {10002, 85, 小红}, {10003, 88, 小刚} }; for (int i 0; i 3; i) { printf(%s %d\n, class1[i].id, class1[i].score); }注意class1[i].score的运算顺序[]的优先级高于.实际上 C 语言里[]和.优先级相同且结合方向从左到右所以class1[i].score是(class1[i]).score也就是先取第 i 个元素再访问该元素的 score 成员。如果你写成class1.score[i]那意思就变成了“class1 这个数组有个 score 成员这个成员是数组”而实际上 class1 没有 score 成员编译直接报错。搞清楚优先级结构体和数组混用的代码就不会写错。如果数组元素本身是结构体指针那访问方式就变成pArr[i]-score比如struct Student *pStudents[30];这是一个“指针数组”每个元素存放一个结构体指针。访问第 i 个指针指向的结构体成员先取出 pStudents[i]再用箭头访问。这种结构在按条件动态筛选数据时很常用不用复制整个结构体只把符合条件的结构体指针装进数组遍历时访问效率高也不破坏原数据。3.2 结构体链表C/C 里节点成员访问的基本语法C 语言链表的节点本身就是一个结构体成员中有一个指向同类型结构体的指针。访问成员靠箭头已经是标准写法了。C 里定义链表节点除了可以用 struct也可以用 class但成员访问规则一致。struct ListNode { int data; ListNode *next; }; // 头插法创建节点 ListNode *head nullptr; ListNode *node new ListNode; node-data 10; node-next head; head node;C 里new返回指针所以node-data用箭头。如果是ListNode node2;这种栈上对象访问成员就改成node2.data。规则没有变化区别只在“你拿到的是对象还是指针”。链表的遍历和插入删除核心都围绕cur-next这个成员在倒腾// 删除某个值为 val 的节点 ListNode *prev nullptr; for (ListNode *cur head; cur ! nullptr; cur cur-next) { if (cur-data val) { if (prev nullptr) { head cur-next; } else { prev-next cur-next; } delete cur; break; } prev cur; }这段代码里prev-next cur-next;是访问两个不同节点的同一成员左边改的是前驱节点的 next 指针右边读的是当前节点的 next 指针语义完全不同。写这类代码时脑子里一定要有“我现在握着哪个节点的地址”这根弦。3.3 文件读写场景fscanf/fwrite 操作结构体成员的正确姿势热词里有 fscanf 结构体这个场景值得单独说。从文件里读结构体数据有两种路线。路线一格式化读写用fprintf和fscanf逐个成员处理struct Student stu {10001, 90, 小明}; FILE *fp fopen(student.txt, w); if (fp ! NULL) { fprintf(fp, %s %d %s\n, stu.id, stu.score, stu.name); fclose(fp); } FILE *fr fopen(student.txt, r); if (fr ! NULL) { struct Student tmp; fscanf(fr, %s %d %s, tmp.id, tmp.score, tmp.name); fclose(fr); }用fscanf读字符串成员时注意tmp.id本身就是char[8]在表达式里已经退化为指针不需要写tmp.id。而tmp.score是 int必须写tmp.score。这个不对称是因为“数组名自动退化指针”初学者很容易在fscanf的一行代码里同时写错这两个。格式化读写的优点是文件是明文可以用文本工具查看、修改跨平台迁移问题少。缺点是需要自己处理格式控制如果成员里有空格或特殊字符解析容易出问题。路线二二进制读写用fwrite和fread把整个结构体当一块内存写入读出fwrite(stu, sizeof(struct Student), 1, fp); fread(tmp, sizeof(struct Student), 1, fr);这样写很省事但有几个隐患。第一个是结构体里有填充字节这些字节的内容可能是随机值写进文件后不同编译器、不同版本读出来的填充区可能不一致导致文件无法跨编译器使用。第二个是结构体里有指针成员时写进去的指针值换了进程就失效这种场景不能用fwrite直接整块写必须逐个成员处理。第三个是文件格式和内存布局绑定如果结构体加了成员老文件就读不出来了。所以涉及持久化存储我通常建议要么用格式化读写要么定义明确的二进制协议逐个字段读写而不是无脑fwrite整个结构体。3.4 嵌入式场景Keil5 里怎么“引出”结构体成员热词里有个很具体的痛点“keil5怎么引出结构体成员”。这个问题的真实场景是在 Keil MDK 的调试界面里你定义了一个结构体变量想观察它的成员数据但 Watch 窗口里看不到或者看不到数组元素、嵌套结构体。下面说几个可行方案。方案一在 Watch 窗口添加结构体变量之后点击变量左边的三角形展开符号逐层展开成员。如果定义了结构体数组比如struct Student stu[3];Watch 窗口默认只显示stu这一个条目展开后可以看到[0]、[1]、[2]每个元素再继续展开。有些旧版本 Keil 需要你在 Expression 栏里手动输入stu[1].score才能精确跟踪单个元素我就经常直接输入stu[1].score来盯某个特定成员。方案二如果用 Watch 窗口展开后看不到成员内容别急着怀疑代码先检查编译优化等级。Keil 的优化等级设置为 -O2 或 -O3 时局部结构体变量可能被优化掉或者成员被放到寄存器里Watch 窗口就显示 “optimized out” 或者直接不显示。排查方法有两个临时把优化等级调到 -O0或者把结构体变量从局部变量改成全局变量。全局变量被优化的概率低很多调试起来就能稳定看到。方案三看内存原始数据。在调试模式下打开 Memory 窗口输入stu或stu[0]然后按 Hex 格式查看。这块区域就是结构体的原始内存你按结构体定义的成员顺序结合偏移量去读每个成员的数据。比如struct Student里 id 是 8 字节score 是 4 字节你在 Memory 窗口第一个 8 字节就是 id 的 ASCII 码紧跟着 4 字节就是 score 的小端序数据。这个方法看起来笨但在 Watch 窗口失灵的时候特别管用。方案四在 Command 窗口里输入表达式直接计算。Keil 的调试命令行支持输入pStu-score这类表达式按回车后会返回当前值。和 Watch 窗口配合使用定位问题更快。我个人的经验是Keil 调试结构体重点不是“怎么引出”而是“为什么有时引不出来”。先把优化等级降下来再把变量定义成全局九成的问题都能解决。剩下那一成多半是指针指向了非法地址导致调试器无法解引用。3.5 工程场景Qt 和 VS 里操作结构体成员以及 MySQL 结构体对接热词里有“qt”和“vs中mysql的结构体”这两个场景代表着“GUI 工程里结构体成员访问的常见问题”。Qt 项目里结构体经常作为自定义数据类型配合QVariant使用。你定义结构体后如果希望在QListWidget、QTreeWidget或QTableView里把结构体和界面项绑定常见做法是struct DeviceInfo { int id; QString name; bool online; }; // 在列表里存储结构体 QListWidgetItem *item new QListWidgetItem; DeviceInfo info; info.id 1; info.name 传感器A; info.online true; item-setData(Qt::UserRole, QVariant::fromValue(info)); // 取出时 DeviceInfo info2 item-data(Qt::UserRole).valueDeviceInfo(); qDebug() info2.name; // 访问成员QVariant::fromValue要求结构体用Q_DECLARE_METATYPE(DeviceInfo)声明否则编译不过。Qt 里访问结构体成员的规则和标准 C 一致info.name用点、item是指针用箭头没有特殊语法。容易出问题的反而是生命周期如果你把结构体指针塞进QVariant用T*类型要特别小心指针指向的对象已被销毁否则取出后访问成员就是悬垂指针。我的建议是能用值类型塞进去就别用指针。VS 里写 MySQL 客户端时会接触到 MySQL C API 的结构体。执行查询后拿到的是MYSQL_RES *通过mysql_fetch_row拿到的MYSQL_ROW本质上是char **就是“一个个字符串形式的字段值”。你要把数据库行映射到自己定义的结构体成员其实就是逐个字段做字符串转换struct UserInfo { int id; char name[32]; int age; }; MYSQL_ROW row mysql_fetch_row(result); if (row ! NULL) { struct UserInfo user; user.id atoi(row[0]); strncpy(user.name, row[1], 31); user.name[31] \0; user.age atoi(row[2]); }这里row[0]、row[1]、row[2]是 SQL 查询结果列的索引顺序取决于你SELECT语句的列顺序。如果数据库字段是 NULLrow[i]会是 NULLatoi(NULL)会导致崩溃判断时要先查row[i] ! NULL再转换。strncpy拷贝完后手动补\0是防止缓冲区溢出的标准做法因为如果源字符串超过 31 字节strncpy不会自动补结束符。这种“数据库字段到结构体成员”的映射是 VS 里写 MySQL 客户端最容易踩坑的地方——不是 C 语法不会而是边界条件没想全。4. 访问结构体成员时最容易踩的坑结构体成员访问的语法本身不难但实际工程里翻车往往翻在运行期。这里把我见过最多的四类问题整理成速查表每一个都是我或同事真实踩过的。4.1 空指针和未初始化指针成员访问的第一杀手struct Student *pStu; pStu-score 90; // 危险pStu未初始化是个野指针指向哪里完全随机。这种错误最可怕的地方在于有时候程序“碰巧”能运行因为野指针恰好指向了一块可写的内存你写进去的数据覆盖了别的变量的值导致间歇性 bug。排查这种问题最有效的办法就是“防御性编程”每次访问指针成员前先判if (pStu NULL) return;。malloc 之后也立刻判空。如果程序已经发生段错误用调试器绑定 core dump在崩溃现场看pStu的值。如果发现它是个“看起来很合理但逻辑上不可能”的地址比如0xCDCDCDCDDebug 模式未初始化内存填充或0x00000000那基本就是指针没赋值就拿来访问成员了。4.2 结构体对齐和 sizeof 陷阱为什么 sizeof 比想象的大前面提到过填充字节这里再强调一次它对成员访问的影响。你定义结构体时成员顺序不同结构体大小会变struct B { char c1; // 偏移 0 int i; // 偏移 4 char c2; // 偏移 8 }; // 大小 12 struct C { int i; // 偏移 0 char c1; // 偏移 4 char c2; // 偏移 5 }; // 大小 8同样三个成员结构体 C 比结构体 B 小 4 字节因为 C 的成员排列更紧凑。这个现象在结构体数组里会被放大struct B arr[1000]占 12000 字节struct C arr[1000]占 8000 字节差距 4000 字节。对内存敏感的单片机项目这是可以优化的点。还有一种陷阱是紧凑对齐设置。有些场景比如通信协议要求结构体不要填充字节你可能会用#pragma pack(1)或__attribute__((packed))强制紧凑排列。用是可以但有两个副作用一是访问未对齐成员比如地址是奇数时某些 ARM 内核会触发硬件异常二是把 packed 结构体指针传给非 packed 结构体指针时编译器可能生成低效或错误的代码。我见过有人对整包协议用了pack(1)导致结构体里 int 成员地址不对齐函数里直接访问时死机。协议解析还是建议按字节流手动解析别把整个网络包 cast 成结构体。4.3 越界访问改的不是自己的成员是别人家的内存这通常发生在两个场景。第一个是字符串拷贝越界struct Student stu; strcpy(stu.name, 一个非常非常非常长的名字超过了16字节);stu.name只有 16 字节这串字符加上结尾的\0远超 16直接把后面 score 成员甚至整个结构体边界外的内存覆盖了。在这个例子里你通过访问 name 成员间接改坏了 score 成员程序表现就是“score 莫名其妙变成一串乱码”。第二个场景是结构体数组越界struct Student class1[3]; for (int i 0; i 10; i) { class1[i].score 100; // i 超过 2越界 }i超过 2 之后访问的是数组之外的内存。由于数组在栈上越界访问可能踩到相邻变量、函数的返回地址甚至触发栈保护。之所以强调“访问结构体成员前先确认下标合法”就是因为这里的错误不一定在编译期暴露很多是运行到某个边界值才崩溃。排查这类问题建议用 AddressSanitizer 编译选项GCC/Clang 加-fsanitizeaddress或者用 VS 的调试堆。嵌入式的环境没有这些工具那就只能靠代码审查和边界判断多写几层保护。4.4 常见错误信息速查表报错信息含义常见原因解决办法error: request for member score in something not a structure or union在非结构体/联合体上访问成员左边变量不是结构体或左边是指针却用了点指针改箭头或先解引用(*p).scoreerror: invalid type argument of --左边不是指针左边是结构体变量本身改成点运算符stu.scorewarning: dereferencing void * pointer解引用了void *malloc返回值没有转成具体类型指针强制转换(struct Student *)malloc(...)error: assignment to expression with array type数组类型不能整体赋值直接给字符数组成员赋字符串字面量用strcpy或snprintfExpression must have pointer-to-struct-or-union type表达式必须有指向结构体的指针类型VS 下对普通变量名用了-变量用点指针用箭头optimized out变量被优化掉编译优化等级过高调 -O0或改成全局变量再观察这张表解决了“编译报错我不认识”的问题但真正难查的是“编译通过、运行崩溃”。遇到这类问题先不要怀疑编译器优先怀疑自己指针有没有初始化下标有没有越界成员拷贝有没有溢出结构体成员访问的底层逻辑就是“基地址 偏移量”崩溃的根源九成就是地址算错了。我在实际项目里调试过太多结构体相关的问题最深的一个体会是结构体成员访问表面上是语法本质上是内存管理。你把结构体看作一块有语义的内存块把点、箭头看作编译器帮你算偏移量的工具很多问题就想通了。写代码时给自己定几条规矩指针成员访问先判空字符串入成员用带长度限制的拷贝函数结构体作为函数参数尽量传指针并加 const数组访问前先确认下标在边界内。这几条规矩比记住一百条语法细节都管用。最后再分享一个小技巧在 C 语言里如果你希望某个结构体只在不同模块间传递“只读引用”定义常量时直接声明const struct类型成员访问时编译器就会拦截所有写操作。比如全局配置结构体全部标成const测试阶段能省下大量排查“谁改了配置”的时间。这个习惯我从一个老工程师那里学来后一直用到现在。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号