第一章 关于编程自学/教学的一点建议


该系列文章献给计算机语言初学者


建议一:实操第一

        计算机是一门实践性很强的学科,和绘画、实验物理一样强调动手能力。仅仅是看书、听课,是远远不够的,一定要自己写一写、做一做,尤其是丢开书本来敲代码。当你自己写的时候,你会发现,即使是输出一句简单的“Hello World!”都不是一件随随便便就能一下子做好的事。

#include<stdio.h>
int main()
{
	printf("Hello World!\n");
	return 0;
}

        Hello World 程序,是大多数程序员入门学的第一个程序。在 C 语言里,它只有短短五句话,但是对于小白们来说却依然是一件会漏洞百出的问题。比如,将头文件名错写为studio.h,亦或者main()函数少些了括号,再者Hello World!大小写不对、或者忘记写感叹号!最容易犯错的,即使是写了有数千行代码的老朋友偶尔也会犯错的就是,printf()语句后面忘了加分号“;”。除此之外,或许还有更多的错误花样,有待每一个新手的开发😄

        虽然这些错误都是些小错误,但是就是这些小错误,却使得程序无法通过编译,更无法运行。我在刚学 C 语言的时候,即使照着书抄,都会抄错。要么抄错英文单词,要么漏抄标点符号,要么……可以说,在你自己动手写代码之前,你永远不会知道自己会犯什么错误。(ps:这里所举的例子,都是语法错误类型的错误)

        学习编程,千万不要以为看一看、听一听就够了,一定要动手写一写。只有动手写了,才会知道自己会犯什么错误。也只有动手写了,才能纠正自己的错误。当代码写多了,像我前面所列举的低级错误,就不会再轻易犯了。

        有一句话叫作,“专家就是那些在一个领域里犯了比别人更多的错误的人”。把这句话用在编程学习上再适合不过了。刚入门的时候,我们要多动手,不要害怕犯错,要勇于尝试。犯错,纠正,再犯错,再纠正。通过一次次的犯错来锻炼自己。错误犯多了,就能更好地规避错误。

        虽然说在初级阶段,鼓励大家犯错,但本质目的还是希望能少犯错,尤其是少犯低级的错误。而对于那些高级阶段的大佬来说,“犯错”却成为刻意为之的事情了。他们通过有意的错误操作来比较各种工具,来深入学习语言。有时候,他们也会通过可控的错误来检测程序的健壮性(robustness,有些人喜欢用其音译——鲁棒性,但是我觉得用其意译更便于迅速理解)。

        关于大佬还会用“犯错”做什么,我就不知道了,因为我犯的错误还不够多。欢迎每位读者自己去探索😙


建议二:循序渐进

        计算机是一门内涵丰富的学科,我们在学习的时候,同样遵循着螺旋上升的规律。围绕着同一个对象,在不同的阶段,我们会解读出不同的内涵。比如,在上面的程序里,#include<stdio.h>是什么意思?头文件是什么?库文件呢?这对于初学者来说绝对是令人头疼的问题。所以在学习编程的时候,切莫急功近利、也不要钻牛角尖。学习,需要一股钻研精神,做学问、搞科研更是如此,但是时而的“不求甚解”却是很重要的技能。

        这与读书是同样的道理,而对于受过九年义务教育的大多数人来说应该很熟悉。没错,这就是阅读里的 skimming & scanning。前者抓文章主旨大意,后者找文章重要细节,都讲求有所取舍。对此,鲁迅曾谈过其读书心得,“若是碰到疑问而只看到那个地方,那无论看到多久都不会懂。所以跳过去,再向前进,于是连以前的地方也明白了”。老舍亦有类似的表达,“不懂的放下,使我糊涂的放下,没趣味的放下,不客气”。

        我们学习计算机,也要有老舍这种“不客气”的气魄。不影响程序编译成功的难题,一时解决不了,不必担忧,日后学了更多知识自然就会懂得。学写.c.cpp的源文件 source file,不必纠结.h的头文件究竟是什么,只需要知道如何用就好了。知道,用什么哪些函数需要 include 什么头文件就好。比如,当你想求 2 的平方根,你可以使用sqrt()函数。而想要使用这个开方函数,则需要在程序的头部 include<math.h>文件。

#include<stdio.h>
#include<math.h>
int main()
{
	printf("%.8f\n", sqrt(2));
	return 0;
}

        循序渐进,由浅入深。有老师或者入门书引导很容易按部就班,但是一个人若想不甘平凡、想要出类拔萃,就需要“笨鸟先飞”。自学的时候,又该如何循序渐进呢?刘汝佳大佬说,要跟随自己的兴趣。我想这说的极是,我自己就深有体会。刚学编程的时候,并不在意什么是头文件,main()函数前面为什么要加int,程序的结尾又为什么要加return 0,不加可以吗?(ps:实验证明,即使不写return 0,入门阶段的程序也能正常运行)……

        没考虑那么多,也不想考虑。这一切对我来说都是背景,舞台上的主角是像printf()sqrt()这样的函数,以及 if-else 、for 、do-while 等控制结构,等等,可以让我解决一个个像求 2 \sqrt{2} 2 ,打印杨辉三角,求斐波那契数列这样的具体问题的工具。

        而当我学了 Java 之后,看见了不一样的主函数之后,就开始思考 C 语言的main()函数为何非要那么写了。Python 在程序开头有时需要 import 库函数,而 C 在开头则是必须 include 头文件,那么库函数和头文件又有什么异同呢?C++ 里还有写using namespace std,这又是为什么呢?

        当见识的多了的时候,疑惑就会产生,而兴趣也随之被激发。而在兴趣的指引下,阅读了更多的文献、做了更多的实验,渐渐地也就明白了。这里有一个小技巧来帮助我们循序渐进地学习——多看看别人的学习心得和经验分享,参照别人的学习历程来调节自己的进程。不过,一时很难看懂的文章,大可不必苦究。过于晦涩,就表示它超纲了,不适合当前的自己。

建议三:强化基本功

        对于非英语母语的程序员来说,需要做好两门基本功。一个是英语,一个是数学。

        编程是一门入门门槛很低的学科,掌握一点英语基础,数学会点四则运算、外加求余,以及基本的逻辑运算“与或非”,就可以学习编程了。所以,现在市面上爱鼓吹什么“小学生学编程”,即是源于其门槛低、好上手的缘故。但是,编程要想深入、拔高,却是一件极难的事。

        要想成为大佬,就必须夯实基本功。由于,程序语言的控制语句、关键字、函数都是用英文写的,而且编译器都是英文版的,即使有汉化版,却也只是部分汉化,所以,英语基本功必须得掌握。英语好了,既方便敲代码,也方便使用编译器,更有助于查看编译器的错误提示,从而使编程实践练习更加高效和顺心。如果连使用工具都是一件麻烦的事,那么谁还能保持热情,把精力放在重要的程序编写上呢?

        另外,除了自己练习需要英语,在学习他人的先进成果的时候也经常需要英语。因为有很多优秀教材都是英文写作的,比如 C 语言之父,丹尼斯·里奇(Dennis Ritchie)的《C 程序设计语言》。当然像这种经典中的经典,也有比较好的汉译本,不过更多的书,尤其是比较近期出的新书,读原版会更好些。

        你可能会说,刚入门,先把基础的,或者说是经典的学好,再去学前沿的、新潮的不就好了吗?那些新书翻译的不好,那就读老书呗。如果,你这么想,那就大错特错了。编程语言是发展很快的,在发展之中有些表达方式,或者专业点说函数,会被舍弃,或修改,并且会有新的函数被添加。一些经典的教材,它所使用的语言版本会比较老,里面的许多程序很有可能无法在现在使用的编译器里运行。而根据早期工具,研制的复杂算法,在现在或许一两个函数就可以实现。如果你还使用老办法,就会十分笨拙和低效。

        编程语言是活的,我们必须要与时俱进地学习它,不然就会像用“之乎者也”和现代人交流一样,搞得云里雾里、不知所以了。

        然后数学,我想就不用我多说了。计算机被发明就是为了做“计算”的,从名字来看就能够一目了然。计算机得已被发明,也是源于数学上的进步。还有,在编程学习中,练习的许许多多题目,都是数学方面的题目。比如,前面所提的,杨辉三角和斐波那契数列。所以,数学是特别重要的基本功。

        编程数学入门,建议先学习线性代数的矩阵部分,然后再学习离散数学。离散数学,先学排列组合,再学数论,然后是图论,最后是数理逻辑。先按这个顺序把各个分支的基础学好,学完一轮,然后再根据个人情况逐步推进深入学习。提高阶段,不必按照基础学习时的顺序,可以根据做题练习需要自己设定计划。

        最后给大家推荐几个比较热门的编程学习网站。正在使用的 CSDN 肯定首当其冲,然后就是博客园、再就是菜鸟教程,最后是 Github。最后一个,是全球性的交流平台,对英语水平有一定要求。不过,它有一个中文论坛,有精力的朋友可以探索一下。

        然后,要购买计算机方面的参考书的话,像机械工业出版社的华章系列、人民邮电出版社的图灵系列,以及清华出版社的书都不错。基本上大家买的书,都是这三家的。另外,图灵那个有一个社区,里面也有关于编程的一些经验交流。

        祝每一个学习计算机的朋友,都能从计算机中体会到快乐。在此,以陈立杰大佬的一句话作结,“如今,我的朋友们跟女同学都过着幸福的生活,不过我觉得我跟我的电脑过得比他们更幸福”。当然和电脑幸福生活,与和对象幸福生活,并不是互斥关系😏

更多推荐

关于编程自学的建议