文章作者:无锋之刃[E.S.T顾问团]
信息来源:邪恶八进制 中国
章1 C的初体验
节1.1 第一次亲密接触
95年的时候我刚上初二,学习并不太紧,课余的闲暇时间很多。为了打发掉一些时光,经常会跑去书城买点计算机类的书来啃。也许是命中注定,我买本谭老前辈的《TC程序设计教程》,至此成为地地道道的Cer。而我的C体验,也是从此开始的。
谭老的书写得实在是四平八稳,滴水不漏,有章有法(最难得的是十数年不变,当工具书用可以,当读物不行)。那时候我的知识结构还很简单,本来这样的书是决计看不懂的。但初一的时候恶补过一阵子BASIC,再加上莫大的好奇心,居然愣是在七天内把整本书给啃完了。有人会说吹牛也不用这样,但我真正想要表达的观点是,一周内看完一门编程语言的语法的确不难,问题是能看懂多少?
很多人在与C进行第一次亲密接触的时候,大都会被C的简洁与强大所折服,也大都会想要努力把C学习好。可是真正把C搞明白(只是明白,不算熟悉的)的人太少了。原因在于C的语法容易看,想搞懂却不是那么简单的。特别是指针,更是百转千回,把人绕晕了也不见分析得清楚。
孔老人家曰“学而不思则惘,思而不学则殆”,很有道理。所以我看计算机书籍的方法与别人不太一样,喜欢把自己假设成计算机,按计算机的思路去思考问题。这就是我看C又快又明白的原因。除了花时间在“看”上面,还会根据代码的结构,在脑子“想”这些代码的意思(语义)是什么?相互关系如何?编译器如何会处理这些代码?等等等等。通过把自己代换成编译器,从而把学和思结合,就能顺利地弄清楚上面的各种问题。虽然有点奇怪,但真的有效,呵呵。
学和思结合固然重要,更关键的问题在于多动手练习。看完不代表懂,懂不代表会用,会用不代表熟练,熟练不代表能赚钱。所以学习C的初级阶段,主要还是通过动手编码来熟悉语法,洞悉语义,达到看一能及二甚至推三的程度,才算小成。多数C学习者过于重视看书,却忽略了练习,实在是大大的不该。
练习的方法也不应该是死做书上的习题。习题的目的是帮助学习者巩固语法知识,便于其熟练使用而已。学习者做完了习题最多是懂得怎么用语法,但还没有到懂得何时用什么语法的程度。要想达到自由地编程,或者是下意识地编程的程度,必须是分析实际的功能需求,仿照已有的程序来编码才可达成。比方说一个菜单,看的人大概就是会用,但程序员应该从编程的角度去看这个菜单。有目的地思考“我如何实现这个菜单的功能”之类实际问题,更能锻炼出真正的编程能力,而不是简单地应试。换句话说,就是先懂得分析,然后才懂得设计,最后是懂得编码。编码人人都能懂,但分析设计却不是个个都会的。这也可算是编程爱好者与程序员的本质区别了吧。
节1.2 学习顺序简论
我的学习顺序,比较喜欢安排成这样:
1. 先看一遍语法;
2. 用语法把想实现的软件功能实现出来;
3. 回头再看一遍语法;
4. 考虑此语法上的高层结构,比如建模。
看第一遍语法,主要是为了熟悉语法结构、语言要素等等基本知识。学习过其它语言的人可以在这个阶段进行语法比较。第二步则是练习阶段,主要是巩固语法的使用。而看第二遍语法是复习语法,补充细节,把没有来得及看或者尚未理解的细节知识纳入知识结构之中。最后一个阶段就进入到高层面进行抽象,即如何使用此语言来对问题建模。
这个顺序的前提假设是读者已经具备一定的语言基础。如果是初学者,那么可以在第一步中加入习题练习,即语法学习与实践练习交叉进行,但花费时间比较多。但初学者容易在这个比较漫长(甚至反复)的过程中失去信心,这就需要初学者具备一定的心理素质了。C语言不难学,难的是人的心:)。
当然这个顺序不单只是应用在C语言的学习上,也可以应用在其它方面。其实顺序不是问题,最关键的是要有信心、恒心和耐心。
1.3 经典C代码
几乎每本C教程的第一个代码片段都类似下面的代码(可以在任何C编译器上编译通过,如果不能的话,把你的编译器扔了:):
#include <stdio.h>
int main(int argc, char **argv)
{
printf(“hello world!\n”);
return 0;
}
很简单的代码段,但已经蕴涵了不少C的语法结构。只是大家都已经司空见惯,没什么感觉而已了。其实仔细看看,还是有点分析的味头。
首先应该看出的是C语言采用的“头文件/实现文件”结构。其中头文件存放预处理指令(preprocess instruction)、声明(declaration)、枚举/结构/联合定义(enumerator/structure/union definition)、内联函数定义(inline function definition)、类型定义(type definition)等公共的、可以重复包含的内容;实现文件存放预处理指令、静态/全局变量定义(static/global variable definition)、函数定义(function definition)等不可重复包含的内容。 不同的代码开放层次可以开放不同的代码文件(比如在分放代码时可以只提供头文件和Lib文件,而开源时则可以再附加上实现文件)。
其次应该注意的是main函数。正如进入一个单位办事必须先从大门进入一样,C程序中的逻辑入口点是main函数。此函数的作用有三个。第一个是为操作系统向程序提供的参数保留占位符;第二个则是程序向操作系统提供的返回状态保留占位符;最后一个是为操作系统替开辟此程序的新进程提供进入点。每个C工程都必须有唯一一个main函数(保存在某个实现文件中)。
很多人不太在意main函数的写法,经常写成如下形式:
void main()
其实这是不对的,因为这不是标准C中规定的写法,因此是不可移植的。以下两种形式才是具备移植能力的标准写法:
int main();
int main(int argc, char **argv);
最后值得注意的是C语言的“按功能分离代码形成模块”的设计原则。使用此原则可以较好地组织代码,形成良性结构。比如将所有标准的输入/输出代码写入不同的实现文件中,再由一个统一、包含了所有输入/输出函数原型的头文件来对外提供访问信息。读者应该严格按这个原则来进行模块划分和代码编写。
以上就是我们可以从极小化的经典C代码中看出的一些东西。不过每一个东西都足够让我们研究好长一段时间了(主要是“意会”的时间太长了:()。Let us go!