Turbo C编译、连接和运行时的常见错误&C语言编程风格
一、编译时的常见错误
1. 数据类型错误。此类错误是初学者编程时的常见现象, 下面是一些要引
起注意的错误:
(1) 所有变量和常量必须要加以说明。
(2) 变量只能赋给相同类型的数据。
(3) 对scanf()语句, 用户可能输入错误类型的数据项, 这将导致运行时出
错, 并报出错信息。为避免这样的错误出现, 你就提示用户输入正确类型的数据。
(4) 在执行算术运算时要注意:
a. 根据语法规则书写双精度数字。要写0.5, 而不是写.5; 要写1.0,
而不是1。尽管C语言会自动地把整型转换成双精度型, 但书写双精
度型是个好习惯。让C语言为你做强行转换这是一种效率不高的程序
设计风格。 这有可能导致转换产生错误。
b. 不要用0除。这是一个灾难性的错误, 它会导致程序失败, 不管C
1. 数据类型错误。此类错误是初学者编程时的常见现象, 下面是一些要引
起注意的错误:
(1) 所有变量和常量必须要加以说明。
(2) 变量只能赋给相同类型的数据。
(3) 对scanf()语句, 用户可能输入错误类型的数据项, 这将导致运行时出
错, 并报出错信息。为避免这样的错误出现, 你就提示用户输入正确类型的数据。
(4) 在执行算术运算时要注意:
a. 根据语法规则书写双精度数字。要写0.5, 而不是写.5; 要写1.0,
而不是1。尽管C语言会自动地把整型转换成双精度型, 但书写双精
度型是个好习惯。让C语言为你做强行转换这是一种效率不高的程序
设计风格。 这有可能导致转换产生错误。
b. 不要用0除。这是一个灾难性的错误, 它会导致程序失败, 不管C
语言的什么版本, 都是如此, 执行除法运算要特别小心。
c. 确保所有的双精度数(包括那些程序输入用的双精度数) 是在实数
范围之内。
d. 所有整数必须在整数允许的范围内。这适用于所有计算结果, 包
括中间结果。
2. 将函数后面的";"忘掉。此时错误提示棒将停在该语句下的一行, 并显
示:
Statement missing ; in function <函数名>
3. 给宏指令如#include, #define等语句尾加了";"号。
4. "{"和"}"、"("和")"、"/*"和"*/"不匹配。 引时棒将位于错误所在的
行, 并提示出有关丢掉括号的信息。
c. 确保所有的双精度数(包括那些程序输入用的双精度数) 是在实数
范围之内。
d. 所有整数必须在整数允许的范围内。这适用于所有计算结果, 包
括中间结果。
2. 将函数后面的";"忘掉。此时错误提示棒将停在该语句下的一行, 并显
示:
Statement missing ; in function <函数名>
3. 给宏指令如#include, #define等语句尾加了";"号。
4. "{"和"}"、"("和")"、"/*"和"*/"不匹配。 引时棒将位于错误所在的
行, 并提示出有关丢掉括号的信息。
5. 没有用#include指令说明头文件, 错误信息提示有关该函数所使用的参
数未定义。
6. 使用了Turbo C保留关键字作为标识符, 此时将提示定义了太多数据类型。
7. 将定义变量语句放在了执行语句后面。此时会提示语法错误。
8. 使用了未定义的变量, 此时屏幕显示:
Undefined symbol '<变量名>' in function <函数名>
9. 警告错误太多。忽略这些警告错误并不影响程序的执行和结果。编译时
当警告错误数目大于某一规定值时(缺省为100)便退出编译器, 这时应改变集成
开发环境Options/Compiler/Errors中的有关警告错误检查开关为off。
10. 将关系符"=="误用作赋值号"="。此时屏幕显示:
数未定义。
6. 使用了Turbo C保留关键字作为标识符, 此时将提示定义了太多数据类型。
7. 将定义变量语句放在了执行语句后面。此时会提示语法错误。
8. 使用了未定义的变量, 此时屏幕显示:
Undefined symbol '<变量名>' in function <函数名>
9. 警告错误太多。忽略这些警告错误并不影响程序的执行和结果。编译时
当警告错误数目大于某一规定值时(缺省为100)便退出编译器, 这时应改变集成
开发环境Options/Compiler/Errors中的有关警告错误检查开关为off。
10. 将关系符"=="误用作赋值号"="。此时屏幕显示:
Lvalue required in function <函数名>
二、连接时的常见错误
1. 将Turbo C库函数名写错。这种情况下在连接时将会认为此函数是用户自
定义函数。此时屏幕显示:
Undefined symbol '<函数名>' in <程序名>
2. 多个文件连接时, 没有在"Project/Project name中指定项目文件 (.PRJ
文件), 此时出现不到函数的错误。
c语言编程常见错误集锦 3. 子函数在说明和定义时类型不一致。
4. 程序调用的子函数没有定义。
二、连接时的常见错误
1. 将Turbo C库函数名写错。这种情况下在连接时将会认为此函数是用户自
定义函数。此时屏幕显示:
Undefined symbol '<函数名>' in <程序名>
2. 多个文件连接时, 没有在"Project/Project name中指定项目文件 (.PRJ
文件), 此时出现不到函数的错误。
c语言编程常见错误集锦 3. 子函数在说明和定义时类型不一致。
4. 程序调用的子函数没有定义。
三、运行时的常见错误
1. 路径名错误。在MS-DOS中, 斜杠(\)表示一个目录名; 而在Turbo C 中斜
杠是个某个字符串的一个转义字符, 这样, 在用Turbo C 字符串给出一个路径名
时应考虑"\"的转义的作用。例如, 有这样一条语句:
file=fopen("c:\new\tbc.dat", "rb");
目的是打开C盘中NEW目录中的TBC.DAT文件, 但做不到。这里"\"后面紧接的分别
是"n"及"t", "\n"及"\t"将被分别编译为换行及tab字符, DOS将认为它是不正确
的文件名而拒绝接受, 因为文件名中不能和换行或tab字符。正确的写法应为:
file=fopen("c:\\new\\tbc.dat", "rb");
2. 格式化输入输出时, 规定的类型与变量本身的类型不一致。例如:
float l;
printf("%c", l);
1. 路径名错误。在MS-DOS中, 斜杠(\)表示一个目录名; 而在Turbo C 中斜
杠是个某个字符串的一个转义字符, 这样, 在用Turbo C 字符串给出一个路径名
时应考虑"\"的转义的作用。例如, 有这样一条语句:
file=fopen("c:\new\tbc.dat", "rb");
目的是打开C盘中NEW目录中的TBC.DAT文件, 但做不到。这里"\"后面紧接的分别
是"n"及"t", "\n"及"\t"将被分别编译为换行及tab字符, DOS将认为它是不正确
的文件名而拒绝接受, 因为文件名中不能和换行或tab字符。正确的写法应为:
file=fopen("c:\\new\\tbc.dat", "rb");
2. 格式化输入输出时, 规定的类型与变量本身的类型不一致。例如:
float l;
printf("%c", l);
3. scanf()函数中将变量地址写成变量。例如:
int l;
scanf("%d", l);
4. 循环语句中, 循环控制变量在每次循环未进行修改, 使循环成为无限循
环。
5. switch语句中没有使用break语句。
6. 将赋值号"="误用作关系符"=="。
7. 多层条件语句的if和else不配对。
8. 用动态内存分配函数malloc()或calloc()分配的内存区使用完之后, 未
用free()函数释放, 会导致函数前几次调用正常, 而后面调用时发生死机现象,
int l;
scanf("%d", l);
4. 循环语句中, 循环控制变量在每次循环未进行修改, 使循环成为无限循
环。
5. switch语句中没有使用break语句。
6. 将赋值号"="误用作关系符"=="。
7. 多层条件语句的if和else不配对。
8. 用动态内存分配函数malloc()或calloc()分配的内存区使用完之后, 未
用free()函数释放, 会导致函数前几次调用正常, 而后面调用时发生死机现象,
不能返回操作系统。其原因是因为没用空间可供分配, 而占用了操作系统在内存
中的某些空间。
9. 使用了动态分配内存不成功的指针, 造成系统破坏。
10. 在对文件操作时, 没有在使用完及时关闭打开的文件。
中的某些空间。
9. 使用了动态分配内存不成功的指针, 造成系统破坏。
10. 在对文件操作时, 没有在使用完及时关闭打开的文件。
C语言编程风格
第一章:缩进格式
Tab是8个字符,于是缩进也是8个字符.有很多怪异的风格,他们将缩进格式定义为4个字符(设置为2个字符!)的深度,这就象试图将PI定义为3一样让人难以接受.
理由是:缩进的大小是为了清楚的定义一个块的开始和结束.特别是当你已经在计算机前面呆了20多个小时了以后,你会发现一个大的缩进格式使得你对程序的理解更容易.
第一章:缩进格式
Tab是8个字符,于是缩进也是8个字符.有很多怪异的风格,他们将缩进格式定义为4个字符(设置为2个字符!)的深度,这就象试图将PI定义为3一样让人难以接受.
理由是:缩进的大小是为了清楚的定义一个块的开始和结束.特别是当你已经在计算机前面呆了20多个小时了以后,你会发现一个大的缩进格式使得你对程序的理解更容易.
现在,有一些人说,使用8个字符的缩进使得代码离右边很近,在80个字符宽度的终端屏幕上看程序很难受.回答是,但你的程序有3个以上的缩进的时候,你就应该修改你的程序.
总之,8个字符的缩进使得程序易读,还有一个附加的好处,就是它能在你将程序变得嵌套层数太多的时候给你警告.这个时候,你应该修改你的程序.
第二章:大符号的位置
另外一个C程序编程风格的问题是对大括号的处理.同缩进大小不同,几乎没有什么理由去选择一种而不选择另外一种风格,但有一种推荐的风格,它是Kernighan和Ritchie的经典的那本书带来的,它将开始
的大括号放在一行的最后,而将结束大括号放在一行的第一位,如下所示:
if (x is true) { we do y }
然而,还有一种特殊的情况:命名函数:开始的括号是放在下一行的第一位,如下:
int function(int x) { body of function }
所有非正统的人会非难这种不一致性,但是,所有思维正常的人明白: (第一) K&R是___对___的,(第二)如果K&R不对,请参见第一条. (:-))......另外,函数也是特殊的,不一定非得一致.
需要注意的是结束的括号在它所占的那一行是空的,__除了__它跟随着同一条语句的继续符号.如"while"在do-while循环中,或者"else"在if语句中.如下:
do { body of do-loop } while (condition);
以及
if (x == y) { .. } else if (x > y) { ... } else { .... }
理由: K&R.
另外,注意到这种大括号的放置方法减小了空行的数量,但却没有减少可读性.于是,在屏幕大小受到限制的时候,你就可以有更多的空行来写些注释了.
第三章:命名系统
C是一种简洁的语言,那么,命名也应该是简洁的.同MODULE-2以及ASCAL语言不同的是,C程序员不使用诸如ThisVariableIsATemporaryCounter之类的命名方式.一个C语言的程序员会将之命名为"tmp",这很容易书写,且并不是那么难以去理解.
然而,当混合类型的名字不得不出现的时候,描述性名字对全局变量来说是必要的了.调用一个名为"foo"全局的函数是很让人恼火的.全局变量(只有你必须使用的时候才使用它) ,就象全局函数一样,需要描述性的命名方式.假如你有一个函数用来计算活动用户的数量,你应该这样命名--"count_active_users()"--或另外的相近的形式,你不应命名为"cntusr()".
有一种称为Hungarian命名方式,它将函数的类型编码写入变量名中,这种方式是脑子有毛病的一种表现---编译器知道这个类型而且会去检查它,而这样只会迷惑程序员. --知道为什么Micro$oft为什么会生产这么多"臭虫"程序了把!!.
局部变量的命名应该短小精悍.假如你有一个随机的整数循环计数器,它有可能有"i",如果没有任何可能使得它能被误解的话,将其写作"loop_counter"是效率低下的.同样的,""tmp"可以是任何临时数值的函数变量.
如果你害怕混淆你的局部变量的名字,还有另外一个问题,就是称
function-growth-hormone-imbalancesyndrome.
第四章:函数
函数应该短小而迷人,而且它只作一件事情.它应只覆盖一到两个屏幕(80*24一屏),并且只作一件事情,而且将它做好.(这不就是UNIX的风格吗,译者注).
局部变量的命名应该短小精悍.假如你有一个随机的整数循环计数器,它有可能有"i",如果没有任何可能使得它能被误解的话,将其写作"loop_counter"是效率低下的.同样的,""tmp"可以是任何临时数值的函数变量.
如果你害怕混淆你的局部变量的名字,还有另外一个问题,就是称
function-growth-hormone-imbalancesyndrome.
第四章:函数
函数应该短小而迷人,而且它只作一件事情.它应只覆盖一到两个屏幕(80*24一屏),并且只作一件事情,而且将它做好.(这不就是UNIX的风格吗,译者注).
一个函数的最大长度和函数的复杂程度以及缩进大小成反比.于是,如果你已经写了简单但长度较长的的函数,而且你已经对不同的情况做了很多很小的事情,写一个更长一点的函数也是无所谓的.
然而,假如你要写一个很复杂的函数,而且你已经估计到假如一般人读这个函数,他可能都不知道这个函数在说些什么,这个时候,使用具有描述性名字的有帮助的函数.
另外一个需要考虑的是局部变量的数量.他们不应该超过5-10个,否则你有可能会出错.重新考虑这个函数,将他们分割成更小的函数.人的大脑通常可以很容易的记住7件不同的事情,超过这个数量会引起混乱.你知道你很聪明,但是你可能仍想去明白2周以前的做的事情.
第5章:注释
注释是一件很好的事情,但是过多的注释也是危险的,不要试图区解释你的代码是注释如何如
何的好:你应该将代码写得更好,而不是花费大量的时间去解释那些糟糕的代码.
通常情况下,你的注释是说明你的代码做些什么,而不是怎么做的.而且,要试图避免将注释插在一个函数体里:假如这个函数确实很复杂,你需要在其中有部分的注释,你应该回到第四章看看.你可以写些简短的注释来注明或警告那些你认为特别聪明(或极其丑陋)的部分,但是你必须要避免过多.取而代之的是,将注释写在函数前,告诉别人它做些什么事情,和可能为什么要这样做.
第六章:你已经深陷其中了.
不要着急.你有可能已经被告之"GUN emacs"会自动的帮你处理C的源代码格式,而且你已经看到它确实如此,但是,缺省的情况下,它的作用还是不尽如人意(实际上,他们比随便敲出来的东西还要难看- ainfinite number of monkeys typing into GNU emacs would never make a good program)
通常情况下,你的注释是说明你的代码做些什么,而不是怎么做的.而且,要试图避免将注释插在一个函数体里:假如这个函数确实很复杂,你需要在其中有部分的注释,你应该回到第四章看看.你可以写些简短的注释来注明或警告那些你认为特别聪明(或极其丑陋)的部分,但是你必须要避免过多.取而代之的是,将注释写在函数前,告诉别人它做些什么事情,和可能为什么要这样做.
第六章:你已经深陷其中了.
不要着急.你有可能已经被告之"GUN emacs"会自动的帮你处理C的源代码格式,而且你已经看到它确实如此,但是,缺省的情况下,它的作用还是不尽如人意(实际上,他们比随便敲出来的东西还要难看- ainfinite number of monkeys typing into GNU emacs would never make a good program)
于是,你可以要么不要使用GUN emacs,要么让它使用sanervalules.使用后者,你需要将如下的语句输入到你的.emacs文件中.(defun linux-c-mode() "C mode with adjusted defaults for use with the Linux kernel."(interactive) (c-mode) (c-set-style"K&R") (setq c-basic-offset8))
这会定义一个M-x Linux-c-mode的命令.当你hacking一个模块的时候,如何你将-*- linux-c -*-输入在最开始的两行,这个模式会自动起作用.而且,你也许想加入如下
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.〖ch〗$" . linux-c-mode) auto-mode-alist))
到你的.emacs文件中,这样的话,当你在/usr/src/linux下编辑文件的时候,它会自动切换到linux-c-mode .
但是,假如你还不能让emaces去自动处理文件的格式,不要紧张,你还有一样东西: "缩进" .
这会定义一个M-x Linux-c-mode的命令.当你hacking一个模块的时候,如何你将-*- linux-c -*-输入在最开始的两行,这个模式会自动起作用.而且,你也许想加入如下
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.〖ch〗$" . linux-c-mode) auto-mode-alist))
到你的.emacs文件中,这样的话,当你在/usr/src/linux下编辑文件的时候,它会自动切换到linux-c-mode .
但是,假如你还不能让emaces去自动处理文件的格式,不要紧张,你还有一样东西: "缩进" .
GNU的缩进格式也很死板,这就是你为什么需要加上几行命令选项.然而,这还不算太坏,因为GNU缩进格式的创造者也记得K&R的权威, (GNU没有罪,他们仅仅是在这件事情上错误的引导了人们) ,你要做的就只有输入选项"-kr -i8"(表示"K&R,缩进8个字符).
"缩进"有很多功能,特别是当它建议你重新格式你的代码的时候,你应该看看帮助.但要记住: "缩进"不是风格很差的程序的万灵丹.
合作:
"缩进"有很多功能,特别是当它建议你重新格式你的代码的时候,你应该看看帮助.但要记住: "缩进"不是风格很差的程序的万灵丹.
合作:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论