[免费下载 c语言深度解剖[1]-第18章
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
{
for(condition)
{
Statement2;
}//end
“for(condition)”
}
else
{
statement3;
}//”end
if
(condition)”
statement4
}//end
“while(condition)”
【规则6…6】修改别人代码的时候不要轻易删除别人的代码,应该用适当的注释方式,
例如:
while
(condition)
{
statement1;
//////////////////////////////////////
//your
name
;
2008/01/07delete
//if
(condition)
//{
//
for(condition)
//
{
//
Statement2;
//
}
//}
//else
//{
//
statement3;
//}
////////////////////////////////////////
///////////////////////////////////////
//yourname;2000/01/07
add
…
new
code
…
///////////////////////////////////////
statement4
}
【规则6…7】用缩行显示程序结构,使排版整齐,缩进量统一使用
4个字符(不使用
TAB
缩进)。
每个编辑器的TAB键定义的空格数不一致,可能导致在别的编辑器打开你的代码乱成一
团糟。
【规则6…8】在函数体的开始、结构/联合的定义、枚举的定义以及循环、判断等语句中
的代码都要采用缩行。
【规则6…9】同层次的代码在同层次的缩进层上。
例如:
提倡的的风格不提倡的风格
void
Function(int
x)
{
//program
code
}
void
Function(int
x)
{
//program
code
}
struct
tagMyStruct
struct
tagMyStruct{
{
int
a;
int
a;
int
b;
int
b;
int
c;
int
c;
};
};
if
(condition)
if
(condition){
{
//program
code
//program
code
}else{
}
//program
code
else
}
{
//program
code
}
【规则6…10】代码行最大长度宜控制在80个字符以内,较长的语句、表达式等要分成
多行书写。
【规则6…11】长表达式要在低优先级操作符处划分新行,操作符放在新行之首(以便突
出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。
例如:
if
((very_longer_variable1
》=
very_longer_variable12)
&&(very_longer_variable3
0)
{
fun(i/2);
}
printf(〃%dn〃;i);
}
intmain()
{
fun(10);
return0;
}
问:输出结果是什么?
这是我上课时,一个学生问我的问题。他不明白为什么输出的结果会是这样:
0
1
2
5
10
他认为应该输出
0。因为当
i小于或等于
0时递归调用结束,然后执行
printf函数打印
i的值。
这就是典型的没明白什么是递归。其实很简单,printf(〃%dn〃;i);语句是
fun函数的一部
分,肯定执行一次
fun函数,就要打印一行。怎么可能只打印一次呢?关键就是不明白怎么
展开递归函数。展开过程如下:
voidfun(inti)
{
if
(i》0)
{
//fun(i/2);
if(i/2》0)
{
if(i/4》0)
{
…
}
printf(〃%dn〃;i/4);
}
printf(〃%dn〃;i/2);
}
printf(〃%dn〃;i);
}
这样一展开,是不是清晰多了?其实递归本身并没有什么难处,关键是其展开过程别弄错了。
6。4。2,不使用任何变量编写
strlen函数
看到这里,也许有人会说,strlen函数这么简单,有什么好讨论的。是的,我相信你能
熟练应用这个函数,也相信你能轻易的写出这个函数。但是如果我把要求提高一些呢:
不允许调用库函数,也不允许使用任何全局或局部变量编写
intmy_strlen(char*strDest);
似乎问题就没有那么简单了吧?这个问题曾经在网络上讨论的比较热烈,我几乎是全
程“观战”,差点也忍不住手痒了。不过因为我的解决办法在我看到帖子时已经有人提出了,
所以作罢。
解决这个问题的办法由好几种,比如嵌套有编语言。因为嵌套汇编一般只在嵌入式底
层开发中用到,所以本书就不打算讨论
C语言嵌套汇编的知识了。有兴趣的读者,可以查
找相关资料。
也许有的读者想到了用递归函数来解决这个问题。是的,你应该想得到,因为我把这
个问题放在讲解函数递归的时候讨论。既然已经有了思路,这个问题就很简单了。代码如下:
intmy_strlen(constchar*strDest)
{
assert(NULL!=
strDest);
if
('0'
*strDest)
{
return0;
}
else
{
return(1+my_strlen(++strDest));
}
}
第一步:用
assert宏做入口校验。
第二步:确定参数传递过来的地址上的内存存储的是否为
'0'。如果是,表明这是一个
空字符串,或者是字符串的结束标志。
第三步:如果参数传递过来的地址上的内存不为
'0',则说明这个地址上的内存上存储
的是一个字符。既然这个地址上存储了一个字符,那就计数为
1,然后将地址加
1个
char
类型元素的大小,然后再调用函数本身。如此循环,当地址加到字符串的结束标志符
'0'时,
递归停止。
当然,同样是利用递归,还有人写出了更加简洁的代码:
intmy_strlen(constchar*strDest)
{
return*strDest?1+strlen(strDest+1):0;
}
这里很巧妙的利用了问号表达式,但是没有做参数入口校验,同时用
*strDest来代替('0'
*strDest)也不是很好。所以,这种写法虽然很简洁,但不符合我们前面所讲的编码规范。
可以改写一下:
intmy_strlen(constchar*strDest)
{
assert(NULL!=
strDest);
return('0'
!=
*strDest)?(1+my_strlen(strDest+1)):0;
}
上面的问题利用函数递归的特性就轻易的搞定了,也就是说每调用一遍
my_strlen函数,
其实只判断了一个字节上的内容。但是,如果传入的字符串很长的话,就需要连续多次函数
调用,而函数调用的开销比循环来说要大得多,所以,递归的效率很低,递归的深度太大甚
至可能出现错误(比如栈溢出)。所以,平时写代码,不到万不得已,尽量不要用递归。即
便是要用递归,也要注意递归的层次不要太深,防止出现栈溢出的错误;同时递归的停止条
件一定要正确,否则,递归可能没完没了。
第七章文件结构
一个工程是往往由多个文件组成。这些文件怎么管理、怎么命名都是非常重要的。下面
给出一些基本的方法,比较好的管理这些文件,避免错误的发生。
7。1,文件内容的一般规则
【规则
7…1】每个头文件和源文件的头部必须包含文件头部说明和修改记录。
源文件和头文件的头部说明必须包含的内容和次序如下:
/************************************************************************
*
FileName
:
FN_FileName。c/FN_FileName。h
*
Copyright
:
2003…2008XXXXCorporation;AllRightsReserved。
*
ModuleName
:
DrawEngine/Display
*
*
CPU