任何标识符(包括变量、函数名等)都要先声明再使用。如果在程序中没有声明fahr的变量,那就会出现类似下面的错误。

这时,我们要加上类似下面这样的语句:

int fahr;

更多的时候,是因为我们定义了一个变量,但使用的时候拼写错了,比如定义了int fahr; 但使用的时候写成了farh。

注:关于声明(declaration)和定义(definition),两者还是有区别的,具体就不展开了。

(5)除法操作符/引发的错误

执行下面这段程序后,celsius并不是我们期望的值37.8度,而是celsius=0.000000,这是为什么呢?

原因就在于除法运算/。

在这里,涉及到C语言运算的一个重要规则:

任何双目操作符进行运算,两个操作数的类型必须一致。

在上面的表达式celsius=5/9*(fahr-32)中,第一步执行5/9,两个操作数都是整数。对于整数,/运算符就是做取整的除法,结果还是整数,因此是0。从而,右边表达式的值就是0。最后,赋值操作=也要求操作符两边的数据类型一致,此时c语言取整,会进行默认的数据类型转换,把右边的整数0先转换为小数后赋值给celsius。

要想改为正确的程序很简单,把5或9中的至少一个改为小数即可,比如5改为5.0后,运行结果就正确了。

类似于这样的错误,在下面这段计算1-1/3+1/5-1/7+…的代码里也同样存在,你能找出它吗?

(6)输入法错误

在源代码中切换到中文输入模式,输入了字符,常见的是逗号、分号、小括号和引号,比如下面代码第一行行末的分号和第二行最右侧的小括号。

此时,编译器会提示类似下面这样的错误,这里类似243这样的是用转义字符给出的非标准ASCII字符编码提示。

修改错误很简单,切换回英文输入模式即可。

(7)printf()的常见错误

printf中的f是指formatted,即格式化输出。这个函数里面有若干个参数,第一个参数用字符串给出了输出字符串的格式,里面有普通的字符,也有以%开头的格式化控制符,比如%d, %f, %c等,我喜欢把它们称为占位符。

原则上每出现一个%的占位符,后面就要用一个对应的参数来替换这个占位符,并且要求前后类型一致,否则运行时就会出现比较“离奇”的结果。

比如,下面这段代码:

运行结果是:

其原因在于celsius是float类型的,但在printf()中把它作为%d格式输出,也就是把celsius里以浮点格式存储的32位比特被解释成了整数予以输出,所以会出现奇怪的结果。

为了深入理解这一点,有必要就数据类型多说几句。

所有的数据在计算机里都以二进制的形式存储,但每个数据都有相应的数据类型。

数据类型决定下面几个方面:

(1)数据占用的存储空间的大小;

(2)数据的编码和存储格式;

(3)能对数据进行的操作。

浮点数有浮点数的编码和存储格式c语言取整,整数有整数的编码和存储格式,字符串有字符串的存储格式,输出格式必须与存储格式相匹配才行,否则就会出现错误的输出。

在上面的例子中,为了得出正确的结果,直接把celsius=%d改为celsius=%f即可,如下:

还有一个典型的错误是引号直接把整个字符串都包括进去了,如下:

这时,编译器并不会报错,但运行的时候会出现意料之外的结果,比如:

这个printf()函数明明少了两个参数,为什么还能运行出(虽然是不正确的)结果呢?

要解释这一点,需要理解堆栈和printf()函数的调用方式,有兴趣的可以自行搜索一下,结果一定会让你收获满满。

(8)scanf()的常见错误

与printf()类似,scanf()是格式化输入,函数的第一个参数和printf()的第一个参数类似,用于给出输入字符串的格式,后面的参数用于指定格式化输入的数据存储的位置。

在这个函数的使用过程中,会有不少常见的错误。

第一点和printf()一样,就是前面的%所表示的类型和后面存储数据的变量类型要一致,否则就会出现类似的数据类型解释出错。

第二个错误和printf()也一样,就是引号把整个字符串都包括进去。这种情况编译器也不会报错,但运行结果会出错。要解释这一点,同样需要理解堆栈和scanf()函数的调用方式,有兴趣的可以自行搜索一下。

第三个典型错误就是少写了取地址运算符&,比如:

这种情况编译也不会出错,但运行程序的话很多时候就直接弹窗报错。为了理解这一点,有必要了解一下&的含义。

我们用int fahr;定义变量的时候,要为这个变量在内存中分配一块存储空间。scanf()表示从键盘输入一个整数,然后放到fahr所在的位置去,因此scanf()需要我们告诉它fahr变量的门牌地址。取地址操作符&就是用于获取fahr的地址的。&操作得到的是一个地址,本质上也是一个整数,而fahr本身表示取fahr变量的内容,其值也是一个整数,因此编译不会报错。但显然,如果不用&,我们输入的数据会放错位置,并没有放到fahr变量的地方,而是会放到一个我们意想不到的地方。很多时候,这个位置是不允许写入的地方,从而会触发操作系统的保护机制,终止程序的运行。

第四种典型错误就是在scanf()的第一个字符串中写了普通字符,但输入时没写。

比如上面的代码,运行时比如输入“80,100″,就能正确输入,但如果输入”80 100″,那结果就不是预期的。

其原因在于scanf()的第一个字符串指定了输入的格式,里面如果有逗号,我们在输入的时候也要原封不动地输入。

反过来也会产生错误。如果程序里是scanf(“%d%d”, &lower, &upper);,但输入时多了个逗号,变成” 80, 100″,那输入数据就不对了。

所以,使用scanf()输入时,输入数据必须和格式化输入字符串严格匹配。

(9)==和=不分

这个是编程时常见的一个逻辑错误,而且很隐蔽。

比如下面这段代码,如果输入8 3, 输出会是什么?

如果认为输出为8/3=2,那就错了。

因为b=0中的=并非是关系运算符,而是赋值运算,也就是执行if(b=0)后,是把0赋值给b,并且这个赋值表达式 b=0 的值就是b的值,为0。因此,这个条件不成立,那会执行else里的打印语句。

可问题是,为什么不输出8/3=2呢?

这是因为此时b已经等于0了, a/b执行的是8/0,显然会出错。

修改办法当然很简单,就是把b=0改为b==0即可。

(10)for语句有关的错误

第一个错误是for后面直接加分号。

比如,运行下面的程序,会得出1+2+…+100=101的结果。

为什么呢?就因为在for后面加了分号。之前讲过,分号表示一条语句的结束。因此,sum=sum+i就是for语句执行结束之后再执行的一条语句。

上面这条语句的i++会执行100次,但循环体为空,也就是只更新循环变量,但什么实际工作都不做。等到它结束时,循环变量i的值为101,因此最后会输出101。

另一个典型的错误是for语句的括号里分号用逗号,类似于这样:

幸运的是,这个编译器会报错,如下:

所以,对于for语句来说,小括号里的两个分号不能少,小括号最后的分号要谨慎(除非就是想放循环体为空的语句)。

对for语句小括号里的三条语句而言,每一条都可以空着,但分号不能少。比如下面的,初始化i=1可以在循环体外面做,更新循环变量的i=i+1也可以在循环体里面做。

(11)使用没有初始化的变量

局部变量如果没有初始化,有些编译器会默认初始化为0,有些编译器则不会初始化,从而变量存储的是一个随机值,所以要万分小心。但很遗憾,很多时候我们注意不到,导致结果可能与我们预期的不一致。

比如如果运行下面的代码,很可能结果输出为0,而不是我们预期的10!=362880。其原因就在于我们没有对product初始化,如果编译器将product初始化为0,那么结果就一直是0。

修改很简单,在使用前将product初始化为1即可。

(12)越界

同样是上面的程序,如果我们计算的是30!而不是10!,那会怎样?

运行程序,会发现出现了负数的结果,这显然不对。

这个原因就在于product被定义为一个int类型,而这个数据类型是32位的,它的表示范围为-231~231-1,显然30!超出了这个范围。

这个问题我们只能部分予以解决,比如把product改为double类型,再运行这个程序就得到了下面的结果。当然,double类型也是有表示范围的,运算结果超出了其表示范围就会出错。

(13)不是错误的错误

使用集成编辑环境编译和运行程序时,还有一个经常碰到的错误提示,如下:

这个提示信息告诉我们,不能打开某个.exe的输出文件。出现这个错误是因为之前运行这个exe可执行程序还没有运行结束,窗口也没有关闭。因此,这个exe文件已经被打开了,而现在再次编译源程序的时候,试图去写这个exe文件,这个时候就会出现Permission denied的错误。因为操作系统不允许去写一个正在被打开的可执行程序。

直接关掉上一次未完成的运行窗口,再编译这个程序,就不会有错误了。

总结一下:

(1)计算机是很笨的,它没有半点弹性,只会严格按照规范来。

(2)为了能和计算机和谐相处并驾驭它,我们得适应计算机的脾气和逻辑,而不是让它来迎合我们。

(3)为了最大程度提升编程能力,每次出现错误后,不是急于去修改代码,而是先去理解为什么计算机会给出这个错误的结果。

(4)计算机一定是有理由的。

(5)英语还是要懂一点。

都看到这了,点个赞和在看,再动动手指分享给需要的朋友呗。

(全文完)

作者:昍爸,中科院计算机博士,大学教授,博士生导师,曾获初中和高中全国数学奥林匹克联赛一等奖,江苏赛区第一名,高考数学满分。著有畅销书《给孩子的数学思维课》与《给孩子的数学解题思维课》。

经过几年的打磨和实践,昍爸的思维课终于上线了,扫码即可试听或购买。更多课程介绍参见《》

公众号创立6年多,为大家整理了50篇必读文章收藏版,欢迎大家翻阅转发!不想看网页的可以直接文末扫码购书。

发表回复

后才能评论

本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。

最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。 若排除这种情况,可在对应资源底部留言,或联络我们。

对于会员专享、整站源码、程序插件、网站模板、网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。

如果您已经成功付款但是网站没有弹出成功提示,请联系站长提供付款信息为您处理

源码素材属于虚拟商品,具有可复制性,可传播性,一旦授予,不接受任何形式的退款、换货要求。请您在购买获取之前确认好 是您所需要的资源