自学编程,从此开始

上第2学堂,听有趣的编程课

课文: 《你适合学习编程吗?》 (点击查看完整内容:视频+评测+讨论+……)

作者:第2学堂

学好编程,不一定要英语好数学棒。真正重要的是你的逻辑思维强弱和动手能力高低。 请跟随视频,完成你的第一段C++程序,感受编码的过程,并证明你的动手能力。

课文题图

 

你适合学习编程吗?

上一节课我们提到一个问题:编程也是挑人的,有些人适合干编程,有些人不太适合,你适合吗?

英语水平一般,也能学好编程

英语水平不好同样可以学会编程。

英文好有利于阅读英文编程资料,自然对编程有帮助,比如以下英文编程资源:

一二十年前,国内原创编程资料极度贫乏,翻译资料不仅也少,在时间也滞后;因此英文能力对编程学习的影响较大。随着这些年来我国IT行业的快速发展,国人原创或翻译的编程资料极大丰富;因此从入门材料来看,英文差完全不再是拦路虎。

另一个非常普遍的担心是:编程写的代码,不都是英文吗?比如:

#include <iostream>

int main() 
{
     std::cout << "Hello world." << std::endl;
}

似乎满屏的英文单词,但实际学后会发现更不是问题。

编程的语言本身要求的英文单词,数量上都不多。C++语言的关键字算是多的,但也不超过70个,日常常用的更少,也就20来个;一个完全没英语的人,多写几段代码也能记住;何况多数同学并非完全的英语盲。

小提示:

有意思的是,编程时间长了,还能倒过来提高编程学习者的英语水平。当然,这是特指原来英文水平不好的学习而言。因为尽管你可以坚持使用拼音写代码中非关键字之外的内容,但我们的建议是尽量用英文单词。比如想要表达某个“年龄”,我们会要求写“age”,而不是“nian_ling ”;现在电子翻译技术如此发达及方便,碰上不会的单词查一下完全不是问题。出了校门之后,再去背单词确实很难,但一旦在代码中用上,单词的记忆反倒成了一个有趣的,不知不觉的副作用。

数学水平一般,也能学好编程

如果你原本在现实生活中可以解决的问题,并不需要高级复杂的数学知识,那么多数情况,你使用编程以求更好地解决它,也不需要使用复杂高级的数学知识。甚至,还会借助计算机程序,还有可能缩小因数学能力高低造成的影响。

比如:都在读小学的高斯和小明做一道题:1+2+3+……一直加到100。高斯同学数学能力强,轻松写下:

(1+100) × 50 = 5050

用时不到10秒。小明就惨了,一个个加上去,累死累活,中间还数次算错,花了1小时才搞定。如果这件事情使用程序解决,或许计算机算出(1+100)×50当然还是要比累加1到100快很多,但只计算一次的话,二者的时间差已非人类所能感受(都能千分之一秒内完成)。更为“神奇”的是,就算小明的代码写的是1+2+3+……这样的笨方法,比如:

    /*
        暂时还不懂任何编程语言的同学,只需了解,这是一段通过循环(重复)实现累加1到100的代码。
    */
    int sum = 0;

    for (auto i=1; i<=100; ++i)
    {
        sum += i;
    }

像C++这样 “高智商” 的编程语言,如果得到允许,那么它在“看到”这样的代码时,“心中”可能要蔑视一下代码的作者,“手上”却会默默地将它改成 int sum = 5050, 这背后意思是:借助程序,小明战平了高斯。

编程确实经常需要用到各种数学知识。那么,如果我的数学储备只余初中所学,是不是我写的程序也只够用以解决初中水平的数学问题吗?——纵然这里回答“是”,其实我们也知足了,因为初中数学其实已经足以解决生活中90%以上的问题了——何况答案其实是“NO”。因为很多复杂的数学算法,都已经在程序库写好了,我们只需懂基本用法与原理,就能调用它们以解决更复杂的问题。

可是,为什么我们经常说,数学对编程很重要呢?这个说法很正确,分析如下:

  1. 历史上,编程曾经长期高度直接地依赖数学知识。在第一节课我们就已知道,计算机一开始出现时,基本就是用于解决科学计算问题。这种情况下,如果不懂数学,往往意味着连待解决的问题都不懂,还编什么程序?然而,正如祖师爷“阿达”所预测的,计算机所能解决的问题领域越来越广泛,数学在计算机应用中慢慢地成为底层支撑问题,因此现在程序员不用再是数学家,甚至数学知识一般般也可以大有作为。
  2. 水涨船高的原理:一个人掌握的数学知识越多,数学水平越高。某种意义上,你的数学能力高低,会成为你写的程序所能解决的问题的复杂度的上限。比如,为什么我在这里写教程,而不是在酒泉帮忙写一些神舟发射的程序?很重要的一个原因,就是因为虽然我熟读唐诗三百首,并且还从郭德纲那学到许多太平歌词,但却把高数、线代等知识忘得一干二净。我们不能做科研,就因为我们数学差——听起来似乎有些悲伤。真实情况是:我们只是和天底下大多数程序员一个样,既不是科学家,也不为科学家(包括数学家)写程序;但我们可以为芸芸众生写程序。
  3. 想要学好编程,无论如何,你得有好的数学思维。

第三点是本课的第一重点。想要学好编程,你要有好的数学的思维。

什么叫“数学思维”?我们讲讲其中最重要的: 抽象与归纳。先复习上节课的一个笑话:

老师问一年级的小明同学一个问题,小明陷了久久的沉思中,最后求老师能不能把问题再说一遍。老师说:“家里原来没有白菜,妈妈买回一斤白菜,爸爸也买回一斤白菜,问家里现在一共多少斤白菜?”小明听完直拍大腿:“我说怎么一直算不出来!刚刚我一直按萝卜算来的”。

“一颗白菜加一颗白菜”,和“一个萝卜加一个萝卜”背后是同一个数学模型。剥离其中的具体的“白菜”,“萝卜“,得出计算式 "1+1",这就是一个抽象过程。抽象能力对编程非常重要。

再如高斯的例子,懂得1累加到100使用“(1+100)×50 ” ,那么:

如果你能因此推导出等差数列求和的公式:Sn=n(a1+an)/2,这就是一种归纳能力的体现。归纳能力对编程非常重要。

结论是:没有学好甚至没学过高数、线性代数等等也可以学好编程,但如果你缺少数学思维能力,特别是不懂得抽象不懂得归纳,学习编程就容易“卡住”。

做一个讲逻辑的人

编写程序,很大程度是考验一个人的“组织”能力。如果你需要组织十个人共同完成某事,你可能需要有“威望”,否则人家不听你的。幸好,编程在很大程度上,就是依据特定的逻辑,将一堆相对简单的功能组织起来,形成一个操作流程,以图解决一个相对复杂的功能。如果你平常生活中是一个“不讲逻辑”的人,那你学习编程就会带有先天性的困难。

有一个笑话说:

老婆给当程序员的老公打电话:下班顺路买一斤包子带回来,如果看到卖西瓜的,买一个。当晚,程序员老公手捧一个包子进了家门…老婆怒道:你怎么就买了一个包子?!老公答曰:因为看到了卖西瓜的。

看到这个段子可不可笑,就取决于你是否知道程序员 “超级讲逻辑” 这个梗。如果角色互换,任何一个当程序员的老公在交待老婆同样的事时,必然会更加严谨地说:“下班顺路买一斤包子带回来。另外,如果看到卖西瓜的,买一个。”

怎么? 你看了好几遍,还是不能理解为什么老公只买回一个包子?我直言哦:你这逻辑能力是否适于当程序员,有点令人担心呢。

程序中的逻辑,是交给机器执行的,因此程序相比生活在逻辑上会更严谨。不过,如果有人在生活中就被人嘲笑“做事说法没逻辑”,那真得好好分析下是不是自己的逻辑思维确实差了些?

做一个敢动手、爱动手、善于动手的人

编程要求学习者有较强的动手能力,特别是在入门阶段,需要大量要的编码与调试练习。体现在入门课程上便是“行知”而非“知行”。即,在一知半解的尝试编码,在编码过程中反过来领悟到理论知识。正所谓能动手就动手,没事别逼逼——当然,这是在有好的课程的引导的前提下,自个儿瞎动手可能会被程序之难倒过来打到满地找牙。

学习编程动手能力这么重要,自然就会想评估一下自己的那方面的能力如何。视频中提到(为初学者设置的)三个级别的能力对比:

  1. 仿照能力
  2. 重组能力
  3. 探索能力

第一级,仿照的能力

别人做一遍。你看着跟着也能做出来,就是动手能力强,看着跟着就是做不出来,就是动手能力差。

注意,此处的模仿,不是在对事理洞若观火下的情况下的模仿,而是对事情背后的运转机制一知半解,甚至就是糊里糊涂的情况下的模仿。想一想,生活中哪些本事我们是在这种情况下学到的?非常多,比如一切运动:打乒乓球,游泳以及青春的记忆中许许多多的本不,视频中提到的“恋爱”算是当中一项相对复杂的事。

对相关事理一知半解,但还要学会,最需要的就是细心加耐心。细心最常用在观察上。比如学打乒乓球,没有几个人会一开始就去学习一块板、橡胶加一个球体之间的发力受力与速度和旋转的复杂物理学理论……但是对面那个家伙,他拍子这么一挥……居然就发出一个旋转球,然后我们就接不住……不服气,于是更加偷偷观察他的动作……这就需要细心不是?

观察了以后干什么?当然是练习啊,可是第一次照着对方的姿式挥拍时,竟然没打到球,对方发出了猪一半的笑声,你怎么办?不怕,继续尝试,这次大败以后,回家对着墙壁练习100次……这就是耐心啊。

再把事情往前推进一步:细心和耐心的背后是什么?当然是兴趣啊。这正是上一节课所讲的。如果你对打乒乓球没有兴趣,没有击败对方的好胜心……你当然既细不了心,也耐不了心啊,有这闲功夫,还不如去玩游戏呢……真是殊途同归啊。很多从一开始就完全只是为了赚钱而来学编程的,最后也去玩游戏了。为什么呢?做个对比:

打住,继续说动手能力的事。

第二级,重组的能力

一到这个级别,课程就不会再事无巨细地给出全部实现。就像给出一张拼图的图纸,图中故意抽掉一两块组成模块,通常是那些你在之前学习应该掌握的知识模块,或者是通过已知模块,你应当能推理得到的未知模块。学习者在此时产生的困难,主要有三个原因:

  1. 之前的知识学得不够扎实;
  2. 心态上还停留在第一级别:潜意识里传授方(老师或教程)继续全盘详解,自己只要模仿照搬即可;
  3. 在重组知识的的过程中,急于求成,造成每一个组成模块的质量不过关,代码在拼装的过程中,这边有错那边有误,最终蓝图完成之前就轰然崩塌。

第三级, 探索的能力

在第二级,如果课程有中遗漏什么知识点,通常是课程的作者主观设置的,但到了第三级——注意,第三级才是课程的常态——总会有一些问题,是课程无法考虑到的。此时,如何从已知点出发探索到未知的答案,就是一个大问题了。再次提醒:通常这时候的从已知到未知的探寻路径,不是理论,不是理论,不是理论;我的意思是:它不是你已知三角形内角和为180度,然后求解等腰直角三角形两个锐角几度的问题。它是——正如视频里举的例子,你写了一段代码,然后一编译,冒出一个问题,你不知道它在说什么的这样的问题。

视频中提到的问题已经简单化,实际情况会更加复杂,比如报错信息通常是:

C:/xxx/nanyu/Projects/CPP/BPChild/main.cpp: In function ‘int main()’: C:/xxx/nanyu/Projects/CPP/BPChild/main.cpp:7:13: error: ‘b’ was not declared in this scope cout << b << endl;

全是英文。不是刚刚说英文差也能学好编程吗?很多人看到这些一堆英文,就心生放弃,事实上这还是动手能力差的表现。

假设我们对上述报错信息中的英文一个单词都不懂,使用在线辞典将它们全部翻译一遍,我计时后发现用不了2分钟:

C:/xxx/nanyu/Projects/CPP/BPChild/main.cpp: 在 函数 ‘int main()’ : C:/xxx/nanyu/Projects/CPP/BPChild/main.cpp:7:13: 错误: ‘b’ 没有声明在这个范围里 cout << b << endl;

看懂了出错信息,理解了问题,结合上下文和课程所教通常就近乎找到了解决方法。但是,就让我们假设还是不懂,此时可以回到英文,在网上百度搜索以下关键词的组合: C++ 程序 no declared in this scope。结果如下:

看,有中文有英文,往下拉甚至能翻到十年前的……真是古今中外很多文章能帮到你。

“老师,我搜索了,可是就是找不到答案”——丁小明苦着脸说。他这一说,满屋子的同学都笑了。因为大家看过视频,都猜出他是的 “main.cpp“ 和”7”这两个关键字。

我的第一段C++程序

想在在自己家的机器上编写代码,通常需要安装、准备好相关的编程环境(就像你想写DOC文档,通常需要安装微软的Word或WPS等软件)。 想要写C++程序,需要安装的东西更多,编辑器、编译器、调试器等等。此时 “Hello world” 程序的作用,就用于检查以上软件是否安装成功。第一节说过,有些人会因此而阴沟里翻船,本想一把跳进编程的海洋搏击风浪,未断在下载、安装、配置相关软件时,就丧失编程的兴趣或丧失学好的信心。

我们承诺过,一开始不用去安装这些东西——尽管你早晚需要也早晚能够学会——但就像谈恋爱——我也不懂为什么一比喻就是谈恋爱——没有道理在双方还只是普通朋友时,就让你跑去为“丈母娘”扛煤气罐、扛桶装水、扛大米……

受益于技术的发展,现在有许多在线编码及编译系统。其原理说起来也很简单:我们先不要在自家的电脑上安装东西,我们就在网页上写代码,然后将代码上传到别人家的电脑(服务器)上,让它帮我们编译并执行,再把结果发回来,在网页上展现。

这样的网站有很多,支持C++的就有:

当然,将来真正要学习及书写C++程序,仍然需要安装本地环境,此类在线工具通常仅用于感受及简单测试。

动手!完成你的 “Hello World”

本次测试需要完成的代码是全部内容是:

//我的第一个C++程序
//作者:丁小明

#include <iostream>

using namespace std;

int main() 
{
    cout << "你好,C++的程序世界。" << endl;
}

本节你的任务是照着视频内容,逐行逐个单词逐个字母符号,完成上述代码的正确输入、运行,看到正确的运行结果。再试着将输出内容,改为地道的,纯正的,经典的 “Hello World.”。

我看到丁小明在完成任务之后,又改一次,输出内容是 “丁小明,你真是最棒的丁小明!”。不要笑,因为我们马上就要讲出在视频里没有讲到的,学习编程在逻辑思维、动手能力之外的,第三个重要的特质要求:“自恋”。只要身为程序员,就必将自恋。至于为什么?这涉及到精神层面的追求,超出本课范畴,以后再聊吧。

回到当前练习。只要不是玩“复制/粘贴”等作弊手段,不管顺利或不顺利,也不管最后输出的内容有多自恋,最终能完成一段正确的代码,这就是学习编程的一个非常棒的开始。

下一节课,我们将逐行讲解这段代码含义。