| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 7663 人关注过本帖, 3 人收藏
标题:读程序的一个方法
只看楼主 加入收藏
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
结帖率:100%
收藏(3)
 问题点数:0 回复次数:47 
读程序的一个方法
程序代码:
# include <stdio.h>


 void max(int a,int b)

 {
   if (a>b)
    printf("haha!\n");
   else
    printf("jiji\n!");

 }


 int main(void)

 {
    int i,j;
    scanf("i=%d,j=%",&i,&j);
    max(i,j);

 
   return 0;

 }

 


上面是一个简单的C程序,麻雀虽小,然而五脏俱全,下面讲解一下如何读程序。

用C代码写的程序,必定有一个程序的入口点,一般的编译器统一为叫main()的函数,所以我们首先要找到这个入口点,即在代码中寻找main()函数。

现在我们找到了,它在代码的后部,被声明为int main(void)。这个声明的意思,表示这是一个函数,它将会返回一个int数据给调用者(因为是程序的入口点,调用这个程序的必定是操作系统,故这是返回给操作系统的东西,如果不是涉及操作系统特殊功能的程序,操作系统得到这种返回数据是没有什么用的。什么情况下有用呢?在DOS的批处理流程中,可以编写批处理程序根据命令的返回值执行后续命令。这种批处理程序,在Windows中被称为脚本),括号扩着的是这个函数的参数列表,void是没有的意思(既可以void参数,也可以void返回值)。

函数声明之后,必然有一对花括号,把这个函数的所有代码都括住,这样一段范围之内的代码,被称为一个代码“块”(也叫“函数体”),是一个局部的整体,执行相对独立的程序功能。先扫一眼这块代码大致从哪里到哪里。按照推荐,书写良好的代码块,不应该太长,执行太多的功能。

C语言的函数体,开头处通常是变量声明。在这里,我们看到int i,j的声明语句,意思是告诉编译器,在这块程序代码中,将会使用两个变量,分别叫i、j,它们都是int类型的数据,如果你(此处的你指编译器)在读入下面代码块的时候,碰到某个单词,是i或j的话,就把它视为int类型的变量处理。换句话说,如果碰到没有被声明的单词,又不是C保留字的话,则是不允许的,此时你要报告出错,停止编译,让程序设计者重新书写代码(不是任何语言都必须这样的,有些弱类型语言,就允许未经声明的变量直接使用,如BASIC)。C之所以作这样的强制类型检查,是怕程序员输入代码时的拼写错误,他可能一直都写char,但某处偶然多写了一个s,拼成chars,这种机制就能给程序员纠正错误的机会,但BASIC等不会这样做,它会视这是一个不同的变量,此时运行结果可能与设计初衷大相径庭(因此,现代VB新出现的语法机制,可以设置开关,强制变量声明)。在这里有一点是必须注意的:C是大小写敏感的语言,i和I是两个不同的变量!

继续往下看,那是一条接受输入的语句。scanf()函数不是C的标准函数(但main()是),它是在外部的、被称为库(LIB)的地方取得的一个函数,这种函数是大量程序员为丰富C程序的功能而编写的,所以这样的函数各有各的特色,不会完全一样的——MSC提供的scanf()和Turbo C提供的scanf(),在内部代码可能是不同的,甚至有不同的副作用。有些功能相同的函数,连函数名都不同。这样的库函数,必须查阅书写该函数提供者的资料,才能知道其语法、用法。C的强大功能,很大程度上是众多程序员提供了丰富的代码形成的,类似于Unix的强大,也是因此而来。这些先不谈,现在看到scanf()函数,就是在标准流文件上读入数据的函数,所谓“流文件”,先搁置一边,但要先知道,凡是使用涉及流文件的函数,都要在程序包含stdio.h的头文件,此时,我们要检查是否包含了这个文件,即程序最开始处的#include <stdio.h>,没有这个东西,编译器就不会把外部库函数编译进来,于是程序就找不到scanf()函数的二进制代码,无法运行(这就是非标准C函数的特性,必须连编外部LIB文件)。

用scanf()读入两个变量i、j的值。此处,我们看到先前声明的变量确实用到了(如果有的变量被声明之后从来没用过,编译器会出警告信息,提示你是不是漏了什么代码,为什么明明说好会出现的东西最终没出现,那通常来说是不正常的)。

读到两个变量值之后,到max(i,j)这一行。很明显,这也是一个函数,它叫max,并且带两个int类型的参数,这时,我们可能会发现,stdio.h头文件中没有声明过这样的函数(这要求我们对各种库函数的名字比较熟悉,所以库函数参考手册是必不可少的,如果没有参考手册,就直接阅读stdio.h头文件),必须找到这样的函数是怎么来的。但先别急,main()函数的代码块还没读完,不用急着找这个函数,先放在脑子里,等会再找(这就是代码块不要太长的原因,人的脑记不住太多这种悬着的东西)。

幸好,马上就到了代码块的结尾处,return 0,回应main()的函数声明,兑现了有返回值的承诺(如果没有返回值,编译器也会提醒你,承诺了东西必须做到,这是好品性,写程序如做人)。一个函数的代码块,只要执行到return语句,就会从函数体中跳出,那么这条语句后面的代码就都是废的,不会执行(我们会碰到从各种if结构中跳离函数的情形)。

先歇一会,喝壶茶,再接着说。

[ 本帖最后由 TonyDeng 于 2011-7-29 21:05 编辑 ]
搜索更多相关主题的帖子: 方法 
2011-07-29 20:54
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
main()函数体读完了,我们记得还有一个悬而未决的问题。先整理一下main()函数到底干了什么:读入两个int数据的值,然后调用max()函数处理这两个数据,仅此而已。我们很清楚scanf()函数的行为,但对max()则一无所知,因此,要寻找max()函数到底是干什么的。浏览整篇程序代码,在程序的前部,我们发现了max()函数的代码。

void max(int a, int b),这就是max()函数的声明。类似读main()的办法(这种办法将是我们一直使用下去的),读出如下信息:max()函数没有返回值,它需要两个int类型的参数,分别命名为变量a、b。

在这里声明的a、b,相当于在max()函数体中作类似于main()里面声明i、j的作用。对比一下调用处,写的是max(i,j),而在实现处,写的是max(a,b),也就是说,max()函数中的a等于main()函数中的i,max()中的b等于main()中的j。值是一样的,但变量名不同。写在函数声明中,不过是宣布参数的同时注册了两个变量名。

max()函数体是这个函数的实际动作:首先判断a、b的关系,如果a>b,则输出haha字符串,否则,就输出jiji字符串。这就是它的全部动作。函数到此结束。

现在返回来解决main()中遗留的问题,原先不知道max(i,j)干了什么,现在知道了:就是视i、j的关系不同而输出不同的字符串。所以,整个程序的行为就是:读入两个int数据,根据它们的大小关系输出不同的信息。

整个程序就这样读完了,也了解它到底干什么了。但是,它写得如何呢?有什么问题呢?

授人以渔,不授人以鱼。
2011-07-29 21:53
a9517495424
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:305
专家分:139
注 册:2011-7-20
收藏
得分:0 
   打了那么多字,要顶。
            
2011-07-30 13:05
cm61551187
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2011-7-30
收藏
得分:0 
楼主写得好
2011-07-30 13:25
iegmyxcd
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-7-30
收藏
得分:0 
不错!!!
2011-07-30 13:44
laoyang103
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:内蒙古包头
等 级:贵宾
威 望:19
帖 子:3082
专家分:11056
注 册:2010-5-22
收藏
得分:0 
顶起

                                         
===========深入<----------------->浅出============
2011-07-30 15:44
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
既然有人顶,就继续写。

main()是程序的主控函数,如前所述,我们知道它做了两件事,一是读入两个整数i、j,二是根据这两个整数的大小比较关系输出不同的信息。然而,现在开始问问题了:根据函数max()的名字,它应该是比较若干数据查找其中最大者的,从命名反映,它只应该进行比较,把比较的结果告诉调用者,除此之外,不应该有多余的动作。现在,max()作了两件事,它确实有比较,但多做了输出动作,这叫“名实不符”。

这样有什么问题呢?返回调用处看吧。程序的代码文本,是给人看的,它就如一本书、一篇文章,阅读者应该从文字上获得准确的信息。看看main()的文本,scan是读,很清晰,max是比较,那么我们获得的信息就是读入两个数之后取其最大者的,仅此而已,然而事实上不是,文本之外还有我们意料之外的行为,它有输出!这是从原文中读不到的东西,于是,整个行事的逻辑和流程就混乱了。想象一下,如果scanf()函数也像这样我行我素,读入数据之外还顺带给你的计算机种点木马,给你源代码你也看不出来,因为scanf()函数是人家写好了提供给你的,已经编译成机器执行代码,除非你分析机器码,否则你不可能知道它除了明白告诉你的之外到底还干了什么。如果每个人写程序的人都没有规矩,都这样写程序,那谁还敢用别人提供的资源?所以,这是程序员的规矩:良好的命名、名字反映实质、尽量减少副作用。

所以,1楼程序的代码,应该修改。max()函数只要返回谁大谁小的信息即可,获得这个信息之后如何处理,是调用者的事,不用它管。main()函数显式处理,那段输出代码应写在main()函数体内,不应到处拉屎。只有这样,阅读者(包括作者自己)才能读得明白程序到底是干什么的。

尝试一下,把max()函数的代码写在另外的.c文档中(就如scanf()一样写在.LIB中),再看这个程序,会想象得到它居然会有输出?

授人以渔,不授人以鱼。
2011-07-30 16:07
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
一个程序代码,就是一篇文章。人们一般从头读起,所以main()函数是应该位于开始处的,现在这样颠倒过来,就很别扭。

想过一开始的#include <stdio.h>是干什么的吗?有兴趣的人,不妨把这个文件找出来看看。它主要是一大堆函数的声明,其中,你将能找到scanf()函数的声明,只有声明,没有代码。我们知道,#include指令是把文件的内容的插入到程序中的,插入的内容取代#include行,#include在哪里,插入的内容就在那里。#include在main()前面,所以scanf()函数的声明在main()前面。也就是说,凡是main()将要用到的函数,事先都要声明。

现在的max()函数,没有事先声明,为了编译器在编译main()代码的时候知道从哪里找到max()函数的代码,则max()函数的代码必须在main()之前出现,现在1楼的程序就是这样做的。但这与人的阅读习惯不符。C++为此作了调整,在使用之前,必须给出函数原型声明,编译器自己去寻找代码,代码就可以摆在后面,这样符合人的阅读习惯。

1楼的程序需要作另外一种修改。把max()函数的代码搬到main()的后面,然后将void max(int i, int j);写在main()的前面(位置与#include相同,事实上#include进来的就是这类东西),这样,人阅读时就知道max()是本程序自己写的东西,不在库函数中,然后一眼就看到main(),马上了解程序要干些什么,只要在需要深入查看max()的实现机制时,才会找到它看一看,否则,依照名实相符原则理解即可。

C允许不声明函数原型(可以有也可以没有),如果不声明,就必须把函数写在前面。C++建议使用函数原型,看起来多余,但是有道理的。这就是C++最早是作为C的增强版出现的原因,也是我建议大家最好向C++靠拢的原因。学C那种不规范的习惯了,很多坏毛病的。

[ 本帖最后由 TonyDeng 于 2011-7-30 16:40 编辑 ]

授人以渔,不授人以鱼。
2011-07-30 16:32
风生钧起
Rank: 4
来 自:江西
等 级:业余侠客
帖 子:383
专家分:246
注 册:2011-7-26
收藏
得分:0 
这帖  我才看到 日了!

恩大概意思明白了 void max()里面语句是我为看懂流程写进去的

我很清楚这函数void max()  额外多做了事(至少在这个代码中)

清楚了 为什么黑窗口会显示 字符串  

楼主哪人 我这有 极品 毛尖 我寄罐来你

墨一世红颜倾醉己    霁天谁与话风流

修仙``````````````````````````````````````````````
2011-08-02 13:36
风生钧起
Rank: 4
来 自:江西
等 级:业余侠客
帖 子:383
专家分:246
注 册:2011-7-26
收藏
得分:0 
重复 在看遍 顶起!

墨一世红颜倾醉己    霁天谁与话风流

修仙``````````````````````````````````````````````
2011-08-02 14:07
快速回复:读程序的一个方法
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018345 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved