尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
C语言学习笔记:类型转换、数组传参与指针调试避坑指南
1. 为什么2.0版本的学习路线被我推倒重来1.1 第一轮学习的翻车现场把时间拉回半年前。我第一次翻开《C程序设计第五版》时心态就是典型的教程都买了等于我会了。每天按部就班地看书、抄代码、跑结果前四章确实顺风顺水——printf能输出scanf能读入if和for也能照葫芦画瓢。但到了函数和指针情况急转直下我开始能看懂每一个知识点却完全不知道这些知识在真实程序里怎么配合。最典型的例子是我写了一个交换两个变量的函数代码照着例题敲进去结果主函数里a和b纹丝不动。那时候我连值传递和地址传递的区别都没真正吃透只知道死记硬背要传指针。后来我复盘发现第一轮学习最大的问题不是不努力而是把教材当成了阅读材料而不是训练手册。《C程序设计第五版》的章节编排确实是经典的由浅入深路线但它的定位是配合课堂教学的每一章的知识密度非常大如果只是顺着读一遍很难在脑子里留下可调用的索引。于是我在第二个月断了更新直到某天重新翻看后面几章的习题发现自己连求最大公约数都要想半天才下定决心推倒重来。1.2 第五版教材的定位与新计划的起点这一轮我给自己定的原则只有一个每一章必须留下至少一个可以独立运行、并且我能在不看答案的前提下讲清楚原理的小项目。学习日记升级到2.0就是要把之前看书—抄码—跑通的流程改成预习—猜测—实验—对照教材—写笔记的闭环。比如学完运算符那一节我就顺手写了一个输入秒数换算时分秒的程序学完循环就写一个会打印菱形的程序。哪怕程序简单到只有二十行只要能自己从头写出需求分析、变量设计、流程组织印象就比抄十遍例题深刻得多。环境方面我一开始用的是某在线编译页面图省事。可到了数组越界、野指针调试的时候没有断点、没有内存查看根本没法查。后来本地装了一款支持断点的IDE搭配GCC编译器调试能力才算跟上。很多人觉得学C语言随便找个网页就能跑但我的体会是如果你认真想学本地编译器加单步调试是必需品这不只是工具问题还直接影响你对程序运行时状态的判断能力。下文中所有实验都是在本地IDE里完成的。2. 从数据表示看到C语言的斤斤计较2.1 整型占位符与字节数不同环境下的隐形差异第二遍学习从数据的存储开始我才意识到自己第一轮连printf的%d、%u、%ld都分不清楚。教材表格里列得很清楚int通常是4字节short是2字节long在32位和64位系统下长度不同。真正让知识落地的是我做了个小的环境探测程序——用sizeof打印所有基础类型的字节数再用printf按不同格式符输出同一个变量观察结果错乱。实测下来发现如果在Windows下用某旧版IDElong和int都是4字节而在Linux下long变成8字节。这说明教材上具体长度由系统决定这句话不是废话而是谁踩坑谁知道。更隐蔽的是unsigned类型。我写了一段代码int a -1; unsigned int b 1; if (a b) { printf(a b\n); } else { printf(a b\n); }第一轮我判断是a小于b因为-1明明小于1。实际输出却是a b。原因就在于C语言的隐式类型转换当有符号数和无符号数混合比较时有符号数会被转换成无符号数。-1在int里是补码0xFFFFFFFF转换成unsigned int后就变成了4294967295当然大于b。这个例子说出来很简单但如果你没亲手跑过考试遇到大概率会错。我现在的笔记里专门留了一个格式符对照表每次写printf前都会确认该用%d、%u还是%ld变量类型常用格式符注意事项int%d最常用unsigned int%u和%d混用会出怪值long%ld64位系统下区别明显char%c / %d字符本质是整型float%f默认输出6位小数double%lf与%f混用在某些编译器下出错2.2 浮点比较与反直觉的类型转换浮点数部分教材给出的警示是不要直接用判断浮点数是否相等。我第一次看没当回事直到写程序判断两个计算结果是否相同时翻车double x 1.0 / 3.0; double y 3.0 * (1.0 / 3.0) / 3.0 * 3.0; if (x y) { printf(equal\n); } else { printf(not equal\n); }实际跑出来是not equal。原因是1.0/3.0在二进制里是无限循环小数存储时必然被截断经过不同运算路径以后误差累积方向不同。后来我给自己定了一个笨办法比较浮点数时计算它们的差的绝对值看是否小于某个极小阈值比如1e-6而不是直接取等。这一章我还给自己留了一道综合题输入一个整数输出它的二进制补码表示。这道题需要用位运算、循环、数组还得处理负数补码做完以后整型存储一节基本就通了。我的建议是学数据表示这一章不要只背整型几字节而是亲手跑上面这类小实验把隐式转换、补码、浮点误差这些看得见摸不着的概念变成看得到的结果。3. 选择结构的花式踩坑switch、分支与逻辑短路3.1 switch穿透一个没有break的诡异连锁选择结构是C语言里看起来最简单、写起来最容易出神bug的部分。我印象最深的是switch语句的穿透问题。教材里特别强调每个case后面都要加break但没说如果不加会发生什么。我自己做了个实验输入一个成绩档次输出对应评语int level 2; switch (level) { case 1: printf(优秀\n); case 2: printf(良好\n); case 3: printf(及格\n); default: printf(未知档次\n); }运行结果是三行全部打印。这就是穿透switch匹配到某个case后会从那里开始依次执行到break或switch结束为止。第一轮学的时候我把它理解为case是一个分段的门其实更准确的理解是case只是一个入口标签每个case之间的代码并不是独立的盒子而是拼在一起的长走廊break是走廊里的出口。意识到这一点后我再看switch就再也没漏过break。3.2 逻辑表达式里的短路现象另一个让我开了眼界的知识点是逻辑运算符的短路求值。教材提到左侧表达式为假时右侧不再执行||左侧表达式为真时右侧不再执行。理论很简单但实际影响变量值时就不一样了。我写了这样一段代码int a 0; int b 5; if (a ! 0 b / a 1) { printf(ok\n); }表面上看b/a会除零程序应该崩。但实际运行时没有任何错误因为a不等于0为假后面的b/a表达式根本没机会执行。再看另一个例子int i 1; int result (i 0) || (i 100); printf(i %d\n, i);输出是i1而不是100因为||左侧为真右侧整个赋值表达式被跳过。这个坑在多条件组合的复杂判断里特别常见如果你在条件表达式的右侧写了赋值、自增、函数调用却没意识到它可能不会执行结果就会和预期偏差很大。我的笔记里记了一条铁律不要在条件表达式的有副作用分支里做重要操作要么拆开写要么用临时变量。4. 循环边界排查差一错误与break/continue的细节4.1 从九九乘法表看循环边界循环的差一错误off-by-one几乎是每个初学者都会经历的。第一轮我写九九乘法表用的是for (int i 1; i 9; i) { for (int j 1; j i; j) { printf(%d*%d%d , j, i, i * j); } printf(\n); }这能跑但我只是抄出来的对i9和ji为什么这样写并没有真正理解。第二轮我换了个方式先写出需求打印下三角矩阵再猜测边界条件然后故意把i9改成i9把ji改成ji观察输出缺了哪一行哪一列。这样一做边界的含义就非常直观了——循环次数不是i小于9决定的而是i从初值到终值一共经过多少次决定的。之后再做冒泡排序、二分查找这类算法题时我再也没犯过下标越界或漏掉最后一个元素的错。4.2 break只能跳出一层循环break和continue的区别教材里简单说明break跳出循环continue结束本次循环但真正写嵌套循环时问题就来了。我试过一个例子遍历一个二维数组找到第一个负数后立即停止所有遍历。第一版代码只写了break结果内层循环跳出来了外层还在继续跑输出里出现了多个负数。原因是break只能跳出一层循环并不能让外层循环也停下。要让整个双层循环都停止要么在break之后加一个标志变量外层循环每次判断这个标志要么使用goto不推荐但确实是C语言的能力。我把完整方案整理成了小笔记int found 0; for (int i 0; i 3 !found; i) { for (int j 0; j 3; j) { if (array[i][j] 0) { found 1; printf(找到负数%d\n, array[i][j]); break; } } }外层循环条件里的!found是我从教材的循环条件可以是任意表达式一句悟出来的。这个写法比在循环体末尾判断标志更清爽也少了出错机会。continue的坑则主要在它是否跳过循环变量的更新语句。在for循环中continue之后会自动执行i但在while循环中continue会直接跳回条件判断如果i在continue后面就会死循环。我专门用while写了一个需要continue却忘递增的例子亲眼看着程序卡死之后对continue跳到哪里就异常敏感了。5. 数组与函数手把手确认参数传递的分工5.1 数组传参为什么长得像传地址函数一章是我第一轮学习的分水岭也是第二轮最有收获的地方。最核心的问题就是为什么普通变量传入函数后修改不影响外部数组传入函数后却能直接修改外部数据教材的解释是数组名作为参数时传递的是地址但为什么数组就这么特殊我做了两组对比实验。第一组是普通变量void change(int x) { x 100; } int a 1; change(a); printf(%d\n, a); // 输出1第二组是数组元素和数组名传递void changeElement(int arr[]) { arr[0] 100; } void changeValue(int x) { x 100; } int arr[3] {1, 2, 3}; changeElement(arr); printf(%d\n, arr[0]); // 输出100 int val 1; changeValue(val); printf(%d\n, val); // 输出1实验做完结论非常清晰普通变量传值函数拿到的是副本数组名传过去的是首地址函数通过地址操作原来的内存单元。如果非要严格解释C语言里数组参数会退化为指针所以函数里写的arr[0]本质上等价于*(首地址0)。理解了这一点再去读后面指针章节很多疑问就提前被消解了。5.2 全局变量与局部变量变量遮蔽的实测作用域是另一个容易被忽略的细节。我给自己设计了一个测试定义一个全局变量x在一个函数里再定义一个同名局部变量x并修改它最后分别打印函数内和主函数后的值。实测结果是函数内修改的只是局部变量全局变量纹丝不动。这种局部变量遮蔽全局变量的现象教材在注释里提过但不去亲手验证遇到时很容易懵。我在笔记里画了一张简单的对照表把传值、传地址、全局变量三种数据共享方式放在一起比较方式能否修改外部变量被调函数能否影响调用方适用场景值传递不能不能简单数据回传地址传递指针能能需要修改多个外部变量全局变量能能多个函数共享少量数据我原本觉得全局变量省事实际写程序后发现随便用全局变量会导致函数之间依赖关系不清晰。后来遵循教材建议尽量用参数和返回值传递数据只有配置类常量才放全局。这一章的收尾练习我写了一个学生成绩管理系统的控制台版用数组存成绩函数负责输入、计算平均分、排名、查找不及格学生。写完发现自己对函数设计有了真正的手感——哪个函数负责什么、哪种数据该通过参数传、哪种该用返回值返回不再靠蒙。6. 指针预习笔记数组名、指针变量与动态内存6.1 指针不是拿来就能用初始化是底线指针是《C程序设计第五版》后半部分的第一道高墙。第一轮我就是在这里放弃的因为我始终想不明白指针变量里存的到底是什么东西。第二轮我换了个类比普通变量是一个贴了标签的抽屉抽屉里放着值指针变量也是一个抽屉但里面放的是另一张写着某样东西在第几排第几格的索引条。这个类比帮我绕过了指针就是地址这句抽象话。真正动手时我第一个踩的坑是未初始化指针。代码长这样int *p; *p 100;第一轮我觉得声明了指针就能用结果程序运行时崩溃。原因在于p没有初始化它指向一个随机的内存地址往这个地址写100可能踩到系统保护区域。教材里反复强调指针必须先赋值再使用这不是啰嗦而是血的教训。我用自己的IDE试验后把规则记成了三句话指针变量声明后要嘛置NULL要嘛立刻指向一个合法变量要嘛用malloc分配内存。6.2 野指针排查实录指针最难的部分是动态内存。我写了一小段程序打算动态分配一个数组并给它赋值int *arr (int*)malloc(5 * sizeof(int)); if (arr NULL) { printf(分配失败\n); return 1; } for (int i 0; i 5; i) { arr[i] i; } free(arr);代码看起来挺正常但运行到一半偶尔会报错。我盯着for循环看了很久最后发现条件i5意味着要访问arr[5]可分配的空间只有arr[0]到arr[4]。数组越界不一定会立刻崩溃但会悄悄破坏相邻内存区域的数据——这正是为什么有时能跑有时崩的解释。修正成i5之后程序就稳定了。这次的排查经历让我真正明白内存安全是什么意思。C不像其他语言会检查数组下标它把这件事完全交给了程序员。我后来给指针章节做了个自查清单每个malloc是否检查了返回值、每个数组操作是否确认不越界、每次free后是否将指针置为NULL。教材后面的习题里有一类找错题表面在考语法实际上就是在训练这些安全意识。7. 阶段自测与避坑清单7.1 阶段自测题目日记更新到2.0阶段我做了一个自我评测把零散笔记汇总成几道题目。如果你也正在学习《C程序设计第五版》不妨先在心里过一遍输入一个正整数n打印前n项斐波那契数列n不超过100时结果不会溢出吗如果要支持更大的n数据类型该换成什么写一个函数传入一个字符串数组和一个整数k返回把数组元素循环左移k位后的结果。要求用指针实现不能直接用临时大数组。输入若干学生成绩统计不及格人数、平均分、最高分。要求只使用函数和数组不得用全局变量传递结果。设计一个函数判断一个整数是否为素数并输出它所有小于自身的因数。要求至少用三种不同循环方式实现同一个功能。解释下面代码的输出结果并说明每一步内存状态变化char *s hello; char t[] world; s t; t[0] H; printf(%s\n, s);这几道题不偏不怪但每一道都需要打破抄代码的惯性。第5题尤其考察字符串常量能否被修改、字符数组与字符指针的区别——我在做这道题时就把常量区的字符串不能改而数组里的可以改这个教材重点彻底串起来了。7.2 避坑清单最后把我这阶段踩过的坑浓缩成一张清单后续看日记时直接对照坑点表现正确的做法scanf忘记加程序崩溃或变量未更新普通变量前必须加数组下标从1开始数组首元素异常记住下标从0开始循环边界用还是搞混多跑一次或少跑一次先数清楚执行次数switch漏break多个case同时执行每个case末尾确认break浮点直接比较判断结果时对时错用差值阈值比较未初始化指针直接赋值运行时随机崩溃初始化NULL或指向合法变量malloc后不检查NULL内存分配失败时崩溃分配后立即检查free后不置NULL重复free报错free后手动置NULL字符串常量写入修改运行时崩溃用字符数组保存可修改字符串有些坑看起来很基础但在真实编写过程中越是基础的坑越容易在调试两小时后才发现。我把这张表放成了一张图片存在手机相册里平时写小程序前扫一遍出事故的概率明显降低。学习《C程序设计第五版》的过程本质上不是看懂而是亲手操作、亲手失败、亲手修正。2.0版本的学习日记和第一版最大的区别就是我允许自己犯错并且把每次犯错都变成了一项新的实验记录。如果你也卡在函数和指针附近我的建议很简单放下要把整本书读完的执念挑一个知识点、写一段小代码、故意制造一个错误然后把它修好。这个过程比一本书从头到尾读三遍都有用。
RELATED

相关推荐

重复文件查找工具完全指南:哈希比对、相似扫描与绿色版部署

重复文件查找工具完全指南:哈希比对、相似扫描与绿色版部署

简介:重复文件查找工具基于文件内容进行高速比对,面向需要清理磁盘空间、整理个人数据的普通用户与办公人士,可有效解决文件冗余、存储混乱的问题,尤其适合照片、视频、文档大量堆积的电脑环境。资源压缩包约196KB,体积…

📅 2026/10/23 21:59:50
ASP影视站源码解析:从部署到二次开发全指南

ASP影视站源码解析:从部署到二次开发全指南

简介:这是一套面向视频站点搭建者的ASP源码程序,即ADN视频收藏专家ACC版,适合希望快速部署影视资源站、需要采集与静态化功能的站长或开发者使用。压缩包共414个文件,以89个asp动态页面、70个js脚本、185个gif界面素材为主&#x…

📅 2026/10/23 21:54:50
QuartusⅡ交通灯控制电路设计:状态机与Verilog实现

QuartusⅡ交通灯控制电路设计:状态机与Verilog实现

简介:这份资源面向数字逻辑电路设计的学习者与课程实践者,提供一套基于QuartusⅡ的十字路口交通灯控制电路完整工程。设计涵盖甲车道主道75秒、乙车道辅道25秒的交替通行逻辑,黄灯先亮3秒再切换车道,且黄灯期间每秒闪亮一次&#…

📅 2026/10/23 21:54:50
MORE NEWS

更多资讯

📰

vscode编写markdown文本,转换成pdf出现错误:“princexml” is required to be installed.

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

STM32F103 FFT频谱分析实战:定时器触发ADC与CMSIS-DSP实现

简介:基于ARM官方库的STM32F103 FFT例程是一套面向嵌入式开发者的实战工程,覆盖快速傅里叶变换在单片机上的完整落地流程,从定时器采样、ADC/DMA数据搬运到FFT运算与结果幅频转换,适合信号处理、频谱分析和实时监测场景&#xff0…

📰

[Kotlin]入门学习记录

本文为kotlin学习记录 文章目录本文内容一、语法1. companion object2. 正则表达式2.1 去除特定字符二、使用步骤1.引入库2.读入数据总结本文内容 本文用以记录笔者kotlin学习过程:包括语法等 一、语法 1. companion object 2. 正则表达式 2.1 去除特定字符 保…

📰

基于VS和Qt的FFmpeg播放器开发:从解码到音视频同步实战

简介:这是一份基于VS与Qt开发的视频播放器练习工程,面向刚开始接触Qt界面编程或VS项目配置的读者,可用于课程设计或个人练手。工程使用Qt的UI设计器搭建播放界面,实现了播放、暂停、文件选取与更换视频等常见交互,适合…

📰

Oracle - 两表关联更新

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

802.1X与EAP认证全解析:从端口状态机到落地排障

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬