“Hello World”在编程的世界里是个“梗”,说的是所有教编程的老师在第一节课都会让学生们在计算机屏幕上输出一个“Hello World!”。
瑞问:“为什么第一节课都要学‘Hello World!’?”
其实,在计算机屏幕上输出一个什么东西,并不是编程语言天然该有的功能。因为计算机发明的最初目的,只是能够快速运算,所以,C 语言发明的时候,也将注意力放在如何运算上。但很快,人们就发现,计算机运行了程序、做了运算,却不知道如何将结果告诉我们。这就意味着,无论运算能力有多强大,如果不能把结果告诉我们,那么这个运算都毫无意义。于是,让计算机把运行结果显示出来,就成了编程的首要任务。
瑞问:“有道理!那么,计算机到底怎么在屏幕上显示内容呢?”
计算机发展的早期,有过很多显示方案,最终人们发现,显示器是最棒的输出设备。然而,把内容显示到显示器上,并不容易。显示屏上密密麻麻地布满了点,我们称其为像素点。这些像素点的亮与灭形成了显示器上的图案,比如,我们要显示“5”,在显示器上显示的是 5 的图像点阵。将 5 这个数字转换成图像点阵,是一个复杂的过程。
然而,把要显示的内容传输到显示器上,这个过程更复杂。我尝试着将这个过程简单地描述出来:显示器上的像素点,是和存储器的某个区域对应的。存储器其实分为两个类型,有一类存储器处于计算机最核心的位置,称为内存。程序操作内存很容易。将需要显示的内容放在内存里,计算机里的一个硬件装置叫显卡,它负责将那段内存区域的内容转移到显示器对应的像素点。
在计算机发展的早期,人们要显示的内容比较简单,现在变得越来越复杂了,我们不仅要输出给显示器,还有打印机、耳机,未来肯定会出现更多输出设备。当时,每增加一个输出设备,就要修改计算机硬件设计,专门支持新设备,这太麻烦了,所以人们想到了更好的办法。计算机只需将信息从内存送到外边,这个操作统称为输出。在设计计算机的时候,所有的输出设备一视同仁,不针对具体设备进行专门的设计,新发明的输出设备自己想办法用合适的方式显示,这样计算机的设计就简化了下来。输入设备也用了同样的设计方案,组合在一起简称 I/O(Input/Output)。
瑞说:“听起来相当复杂,不好理解。”
把东西显示到屏幕上,很复杂,需要几百行的程序,初学者根本不可能完成这样的任务。好在有编程的前辈把那一大堆程序统一成一个叫 printf()的程序。我们只要在程序里写“printf()”,就能将结果输出到显示器上。而至于这几百行程序在处理什么,以及其间发生什么事情,我们不需要关心。
瑞问:“printf 后面有两个小括号,那是干什么的?”
printf 告诉计算机即将显示东西,而括号中的信息就是我们需要显示的内容。小括号是个不错的设计,看上去像是填空题,例如,运行 printf("Hello World!"),就能在显示器上显示出“Hello World!”。另外,还有一点需要提醒,printf()不是C 语言自身的功能,所以你还需要再写一句话“#include<stdio.h>”,告诉程序:我需要使用 stdio.h 里面的输入输出功能。
还有一些细节,我需要进一步解释一下。在 C 语言中,单词拼写正确、大小写正确,十分重要。在严谨的计算机中,“A”和“a”是完全不同的东西。编程语言的初学者,常常会在大小写上出错。为此,有些编程语言人性化地不区分大小写,但是这个“人性化”会增加计算机的计算负担,在 C 语言被发明的年代,计算机硬件性能完全不足以提供这样的“人性化”。
瑞问:“stdio.h 是个名字吗?”
#include 可以解释成“我需要使用别人的程序”。需要使用的程序放在<>中。stdio.h 仅仅是一个名字。但是你能看到一个优秀的程序员在起名字的时候,会尽可能让别人一眼看懂,如 std 是英文 Standard(标准)的缩写,i 和 o 分别代表 Input(输入)和 Output(输出)。
还记得我前面解释程序是什么的时候说过,给人一张纸,上面写了很多命令,人会照着去做。人的习惯是从纸的第 1 行开始向下看,而计算机不是这样的,它会寻找一个特定的位置执行你所写的程序。我们将这个位置称为程序的入口。
瑞问:“程序入口怎么写?是规定好的吗?”
我们买回家的计算机,本身已经包含了一些程序,其中最重要的程序就是操作系统。我们使用计算机时下达的每条命令,都会被操作系统获取并翻译成由计算机硬件执行的一系列动作。而我们编写的程序,也是运行在操作系统这个程序之上的。可以这么理解:操作系统就是一个太空的空间站,我们所编写的程序是要到达这个空间站的飞船;无论是哪个国家的飞船,无论是货运飞船还是客运飞船,都需要和空间站连接在一起。
要连接,就需要一个接口。C 语言所编写的程序和操作系统之间的接口的名字叫作 int main(){},这是一个标准的写法,因为接口就是这么定义的,你会看到其中也有一对小括号。随着学习越来越深入,你会发现 C 语言里有一些规则,有助于我们触类旁通地去理解另外一个地方出现的相同符号。这里的小括号也是允许你填写信息的。现在我们并不需要填什么,但是即便什么都不填,小括号也必须写。
后面还有一对大括号,你跟计算机说的话、编写的程序都放在这对大括号里。思考一下,如果由你来设计 C 语言,是否有更好的方案?其他的编程语言确实也有不同的做法,不过不同的做法各有优缺点,{}的设计其实还不错。
瑞说:“接口为什么要有小括号?我还是不明白。”
这个目前先当成固定写法记住,时间久了才能理解。
我们现在的任务就是在屏幕上显示“Hello World!”,那么完整的程序是这个样子的。
#include <stdio.h>
int main()
{
printf("Hello World!");
}
瑞问:“看起来怪怪的,一定要按照这样的格式写吗?”
这个程序写了很多行。把它们全部都写在一行中,计算机是认识的,但是这样看上去不够优雅。虽然对于计算机来说,优雅并不重要,但是优秀的程序员会遵循一些规则,努力地把自己的程序写得优雅。
你会发现,printf()后面有一个分号,分号代表我们跟计算机说的一句话结束了,这是必须写的。其他几行末尾没有分号,是因为那些行的语句都是编写这个程序的准备动作,而不是真正的指令。还记得编译器吗?分号对编译器而言非常重要。编译器在“翻译”时是一句话一句话地处理的,分号是一句话结束的标识符,是需要让编译器识别的。
前面说过,printf 后边的括号里放的是我要输出的内容,今天我要输出的“Hello World!”对于 C 语言来说是一句话。而一句话需要放在英文的双引号里。放在双引号里的内容,称为字符串。这样就会让编译器处理成在显示时将原文输出。
瑞问:“哦!我明白了,都不能写错,问题是程序怎么能写到计算机里呢?”
现在,你需要想办法将这段程序输入计算机。所有的文本编辑器都可以用来输入程序,计算机自带的记事本就能完成这个工作。而 Word 并不是一个标准的文本编辑器,因为它提供了太多的功能。程序输入的“标准范式”,就是要使用纯文本编辑器。
瑞问:“我写完了,前面说过的编译器,计算机里有吗?”
瑞说:“现在可以开始写程序了,我写的程序也应该有个名字吧?”
瑞问:“C 语言的扩展名是什么?”
瑞问:“控制台又是什么?”
瑞问:“编译好了怎么运行呢?
。。。。。。
以上来自一位从未接触过计算机编程的小学生提问,作者尝试站在编程语言发明者的角度来回答,提问有趣活泼,从不懂计算机编程到能参加信息学奥林匹克比赛;回答清晰深刻,描述正确的编程思维并能学以致用!
作者把孩子带到发明C语言的年代,与孩子一起面对计算机科学发展道路上遇到的一个个难题和挑战,假设我们就是当年的计算机科学家,思考我们会如何解决这些问题;讨论假如C语言是我发明的,我是否还会发明这些规则。
这本书并没有简单地迎合孩子想要的趣味案例,而是针对C语言和计算机科学进行深入的探讨,给孩子带来好奇心的满足和成就感,这样的引导会让孩子更高效、深入地理解C语言,为未来学习更加复杂的算法打下坚实的基础,助力孩子攀登信息学奥林匹克竞赛高峰。
每一个孩子都该学习编程,信息学奥林匹克竞赛是对学有余力孩子的智力挑战,孩子是否有这个方向的天赋,需要通过机会尝试一下。
这本书有非常好的可读性,完全可以送给孩子享受驾驭计算机的快乐!