《C Primer Plus(第6版)中文版》一2.7 调试程序

简介:

本节书摘来自异步社区《C Primer Plus(第6版)中文版》一书中的第2章,第2.7节,作者 傅道坤,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.7 调试程序

现在,你可以编写一个简单的C程序,但是可能会犯一些简单的错误。程序的错误通常叫做bug,找出并修正错误的过程叫做调试(debug)。程序清单2.4是一个有错误的程序,看看你能找出几处。

程序清单2.4 nogood.c程序

/* nogood.c -- 有错误的程序 */
include <stdio.h>
int main(void)
(
    int n, int n2, int n3;

    /* 该程序有多处错误
    n = 5;
    n2 = n * n;
    n3 = n2 * n2;
    printf("n = %d, n squared = %d, n cubed = %d\n", n, n2, n3)

    return 0;
)

2.7.1 语法错误

程序清单2.4中有多处语法错误。如果不遵循C语言的规则就会犯语法错误。这类似于英文中的语法错误。例如,看看这个句子:Bugs frustrate be can[6]。该句子中的英文单词都是有效的单词(即,拼写正确),但是并未按照正确的顺序组织句子,而且用词也不妥。C语言的语法错误指的是,把有效的C符号放在错误的地方。

nogood.c程序中有哪些错误?其一,main()函数体使用圆括号来代替花括号。这就是把C符号用错了地方。其二,变量声明应该这样写:

int n, n2, n3;

或者,这样写:

int n;
int n2;
int n3;

其三,main()中的注释末尾漏掉了/(另一种修改方案是,用//替换/)。最后,printf()语句末尾漏掉了分号。

如何发现程序的语法错误?首先,在编译之前,浏览源代码看是否能发现一些明显的错误。接下来,查看编译器是否发现错误,检查程序的语法错误是它的工作之一。在编译程序时,编译器发现错误会报告错误信息,指出每一处错误的性质和具体位置。

尽管如此,编译器也有出错的时候。也许某处隐藏的语法错误会导致编译器误判。例如,由于nogood.c程序未正确声明n2和n3,会导致编译器在使用这些变量时发现更多问题。实际上,有时不用把编译器报告的所有错误逐一修正,仅修正第1条或前几处错误后,错误信息就会少很多。继续这样做,直到编译器不再报错。编译器另一个常见的毛病是,报错的位置比真正的错误位置滞后一行。例如,编译器在编译下一行时才会发现上一行缺少分号。因此,如果编译器报错某行缺少分号,请检查上一行。

2.7.2 语义错误

语义错误是指意思上的错误。例如,考虑这个句子:Scornful derivatives sing greenly(轻蔑的衍生物不熟练地唱歌)。句中的形容词、名词、动词和副词都在正确的位置上,所以语法正确。但是,却让人不知所云。在C语言中,如果遵循了C规则,但是结果不正确,那就是犯了语义错误。程序示例中有这样的错误:

n3 = n2 * n2;

此处,n3原意表示n的3次方,但是代码中的n3被设置成n的4次方(n2 = n * n)。

编译器无法检测语义错误,因为这类错误并未违反C语言的规则。编译器无法了解你的真正意图,所以你只能自己找出这些错误。例如,假设你修正了程序的语法错误,程序应该如程序清单2.5所示:

程序清单2.5 stillbad.c程序

/* stillbad.c -- 修复了语法错误的程序 */
#include <stdio.h>
int main(void)
{
    int n, n2, n3;

    /* 该程序有一个语义错误 */
    n = 5;
    n2 = n * n;
    n3 = n2 * n2;
    printf("n = %d, n squared = %d, n cubed = %d\n", n, n2, n3);

    return 0;
}

该程序的输出如下:

n = 5, n squared = 25, n cubed = 625

如果对简单的立方比较熟悉,就会注意到625不对。下一步是跟踪程序的执行步骤,找出程序如何得出这个答案。对于本例,通过查看代码就会发现其中的错误,但是,还应该学习更系统的方法。方法之一是,把自己想象成计算机,跟着程序的步骤一步一步地执行。下面,我们来试试这种方法。

main()函数体一开始就声明了3个变量:n、n2、n3。你可以画出3个盒子并把变量名写在盒子上来模拟这种情况(见图2.6)。接下来,程序把5赋给变量n。你可以在标签为n的盒子里写上5。接着,程序把n和n相乘,并把乘积赋给n2。因此,查看标签为n的盒子,其值是5,5乘以5得25,于是把25放进标签为n2的盒子里。为了模拟下一条语句(n3 = n2 * n2),查看n2盒子,发现其值是25。25乘以25得625,把625放进标签为n3的盒子。原来如此!程序中计算的是n2的平方,不是用n2乘以n得到n的3次方。


7d13f6401c297b344209cee24e785d94f7202833

图2.6 跟踪程序的执行步骤

对于上面的程序示例,检查程序的过程可能过于繁琐。但是,用这种方法一步一步查看程序的执行情况,通常是发现程序问题所在的良方。

2.7.3 程序状态

通过逐步跟踪程序的执行步骤,并记录每个变量,便可监视程序的状态。程序状态(program state)是在程序的执行过程中,某给定点上所有变量值的集合。它是计算机当前状态的一个快照。

我们刚刚讨论了一种跟踪程序状态的方法:自己模拟计算机逐步执行程序。但是,如果程序中有10000次循环,这种方法恐怕行不通。不过,你可以跟踪一小部分循环,看看程序是否按照预期的方式执行。另外,还要考虑一种情况:你很可能按照自己所想去执行程序,而不是根据实际写出来的代码去执行。因此,要尽量忠实于代码来模拟。

定位语义错误的另一种方法是:在程序中的关键点插入额外的printf()语句,以监视制定变量值的变化。通过查看值的变化可以了解程序的执行情况。对程序的执行满意后,便可删除额外的printf()语句,然后重新编译。

检测程序状态的第3种方法是使用调试器。调试器(debugger)是一种程序,让你一步一步运行另一个程序,并检查该程序变量的值。调试器有不同的使用难度和复杂度。较高级的调试器会显示正在执行的源代码行号。这在检查有多条执行路径的程序时很方便,因为很容易知道正在执行哪条路径。如果你的编译器自带调试器,现在可以花点时间学会怎么使用它。例如,试着调试一下程序清单2.4。

相关文章
|
安全
[UDS] --- WriteDataByIdentifier 0x2E
[UDS] --- WriteDataByIdentifier 0x2E
1234 0
|
10月前
|
运维 网络协议 Linux
Linux firewalld防火墙使用详解
firewalld是Linux动态防火墙管理工具,替代iptables,支持运行时与永久配置分离、区域隔离、富规则等特性。本教程详解firewall-cmd命令,涵盖核心概念、实战配置及高级功能,助力运维人员快速掌握防火墙管理技能。
|
11月前
|
人工智能 边缘计算 自然语言处理
2025年主流测试用例管理平台对比分析与最佳实践
文章聚焦2025年测试用例管理平台,介绍其SaaS化与AI赋能趋势,分析行业背景、痛点及解决方案。对比优测等主流平台,阐述各平台优势与局限。还给出技术路径选择建议,解答常见选型、AI效果、成本控制及跨团队协作等问题,助力企业适配合适方案。
|
SQL Oracle 关系型数据库
《深度剖析:MySQL、Oracle、SQL Server分页语法大揭秘》
分页查询是数据处理中的核心技术,尤其在海量数据场景下至关重要。本文深入解析了MySQL、Oracle和SQL Server三大主流数据库的分页语法及其特点。MySQL以简洁直观的LIMIT语法见长,适合中小规模数据;Oracle通过ROWNUM及新引入的OFFSET/FETCH实现复杂灵活的分页;SQL Server自2012版起支持OFFSET/FETCH,性能高效且扩展性强。开发者需根据项目数据量、业务需求及数据库版本选择合适的分页方案,以优化查询效率和用户体验。掌握这些技术,可为高效数据展示奠定坚实基础。
586 1
|
算法 编译器 C语言
【C语言】C++ 和 C 的优缺点是什么?
C 和 C++ 是两种强大的编程语言,各有其优缺点。C 语言以其高效性、底层控制和简洁性广泛应用于系统编程和嵌入式系统。C++ 在 C 语言的基础上引入了面向对象编程、模板编程和丰富的标准库,使其适合开发大型、复杂的软件系统。 在选择使用 C 还是 C++ 时,开发者需要根据项目的需求、语言的特性以及团队的技术栈来做出决策。无论是 C 语言还是 C++,了解其优缺点和适用场景能够帮助开发者在实际开发中做出更明智的选择,从而更好地应对挑战,实现项目目标。
908 0
|
存储 分布式计算 NoSQL
大数据基础知识
【10月更文挑战第15天】
1298 2
WK
|
监控 Ubuntu Linux
Linux系统平均负载如何查看?
在Linux系统中,有多种命令可用于查看平均负载,包括实时和历史数据。常用方法有:`uptime`命令显示系统运行时间和平均负载;`top`命令实时监控系统进程和资源使用;`w`命令展示用户信息及负载;通过`cat /proc/loadavg`查看特定文件中的负载信息;`sar`命令提供详尽的系统资源监控;而`htop`则以交互方式展示系统负载和资源使用情况。这些工具帮助用户全面了解系统性能状态。
WK
738 2
|
SQL 关系型数据库 MySQL
【MySQL 慢查询秘籍】慢SQL无处遁形!实战指南:一步步教你揪出数据库性能杀手!
【8月更文挑战第24天】本文以教程形式深入探讨了MySQL慢SQL查询的分析与优化方法。首先介绍了如何配置MySQL以记录执行时间过长的SQL语句。接着,利用内置工具`mysqlslowlog`及第三方工具`pt-query-digest`对慢查询日志进行了详细分析。通过一个具体示例展示了可能导致性能瓶颈的查询,并提出了相应的优化策略,包括添加索引、缩小查询范围、使用`EXPLAIN`分析执行计划等。掌握这些技巧对于提升MySQL数据库性能具有重要意义。
1259 1
|
SQL 数据可视化 atlas
用DataV Atlas探索杭州美食
DataV 可视分析地图 Atlas 作为一款面向时空地理数据的可视分析工具,支持海量时空数据的快显渲染和实时分析,能够通过 SQL 分析方式对用户的海量时空数据进行实时渲染和多维分析,帮助用户快速构建自己的地理分析地图,挖掘时空数据价值。 下面通过一份杭州的美食娱乐兴趣点数据在 DataV Atlas 产品上为大家探索一下所谓的美食荒漠城市到底有没有美食?
52679 10
|
存储 安全 数据可视化
ONLYOFFICE 8.0版本深度测评:革新之作还是失望之作?
ONLYOFFICE 8.0版本深度测评:革新之作还是失望之作?
1047 0

热门文章

最新文章