这几年在公司一直带徒弟,每次必教的内容就是C++。在我看来,C++已经有非常好的教材了(注1),实在没有必要从头教起。自学就可以了,可是结果总是不尽人意。

不想再重复一次“把C++当成一门新语言来学习”,自己直接教吧。

总论

C++是一门实践的编程语言,它由数十位工业界的大佬们共同设计出来,它是一种至力于解决问题的语言。我们在学习的过程中,同样也不应纠结于细节,而是专注于如何优雅的解决问题。

C++要解决的基本问题有两个,一是如何处理好int类型;二是如何处理好vector类型。在解决这两个问题的时候,C++的设计者们遇到了相当多的细节问题,不过它们都已经被记录在了C++ programming language一书中。幸好我们不用设计语言,这些问题我们不用再去思考,只需要知道如何做最好(best practice).

在一切开始之前,我们先明确什么是类型(type)?

类型可以粗略的理解成一个概念,比如自然数,动物或宇宙。概念可以由一系列实际的物品举例,但很完全例举。我们说1,2,3,4等都是自然数,但不能把所有自然数都例举出来。这些实例我们称为类型的值。我们可以说1,2,3等大于-32768,小于32767的整数都是int类型,也可以说所有一维有序的数列都是vector类型。同样,可以说int类型的值是所有大于-32768,小于32767的整数。

类型说明这些值之中包括一些关系,计算机科学上也称为操作,比如1+1=2。int类型可以包括算术操作,位操作等等。

计算机中,值都是以内存中的bit来表示,一片保存了值的内存,我们可称为一个对象,为了方便使用,我们为对象取名,以说明它保存了什么用途的值,这个有名字的对象,我们叫变量。

对于有经验的程序员可以关注一下以下名词,来自于A tour of C++。

  • 类型(为对象)定义了一组可能的以及一组可能的操作
  • 是一组bit的组合,其含义由类型来解释。
  • 对象是一片内存,保存了某个类型的一个值。
  • 变量是一个有名字的对象。 

其次我们需要了解什么是编程?

解决问题的一种方式是依次执行一系列步骤。计算机解决问题正是这种方式,不过它有一些限制。首先,它的每个步骤必须已经定义,我们称为这些已经定义的步骤为基本操作。其次,它的步骤必须有限,不能无穷多。

编程的核心内容就是把问题用有限次的基本操作解决。这是一个很难的工作,同时具有工程特点和艺术性。

在一切编程之前,我们先要定义一个基本操作集合,它可能是一个CPU的指令集,也可以是C++的运行时环境。

如果有这样一个计算机,它除了可以进行整数运算外,还可以接收一个数值n,输出一定数量的1分、2分、5分的硬币,并且数量足够多,以足成n分钱。我们可以这样解决这个问题(注2):

int five-cent-count = n / 5;
output-5-cents(five-cent-count); int two-cent-count = (n - 5*five-cent-count) / 2;
output-2-cents(two-cent-count); int one-cent-count = n - 5*five-cent-count - 2 * two-cent-count;
output-1-cents(one-cent-count);

上面是一个有效C或者C++程序的主体部分,中间部分步骤以int开头,它说明了随后是一个变量,其类型为int。

我们还可以定义这样的一个计算机,它的类型Node的值,包括两个部分:data和 ptr。data为int类型,ptr为另一个Node类型的对象位置(指针)。除了int类型的操作外,我们可能的操作还包括:

  • cons(data, ptr) : 由data和ptr来构成一个Node类型的值,并返回对象的位置。
  • first(node): 取node的data部分的值。
  • rest(node): 取node的ptr部分的值,即指向另一个Node对象的位置。

这个神奇的计算机与我们常见的有像大海一样连续内存的计算机不一样,它的数据像是保存在海岛上,你需要一张机票才能到达。但是,使用这样的计算机编程并没有什么不同,只不过基本的操作不同。

假设有一天,计算机已经相当发达,说明定我们会遇到,能走路,说话,会推理的计算机,但编程不会发生变化,同样只是基本操作不同。

我们了解一下什么是计算机程序?

通常说计算机程序是一个可执行的文档。可执行有两方面的意思,一是计算机认识,二是有效的基本操作序列。C/C++程序一般是原生程序,原生是指它由CPU直接认识,它的有效基本操作序列是CPU的指令集。CPU执行程序的过程是:

         读入指令-->执行操作-->输出-->再读入...

我们编程完成的源代码,还不是一个可执行的文档,它要通过编译,把文本变成CPU指令,再连接,连接C++的运行时环境对应的CPU的指令集。

源代码---(编译)-->目标文件---(连接C++运行时环境对应的CPU指集)-->可执行文档。

程序的执行过程一般是:

         读入一些数据-->执行操作-->输出--回到开始的状态。

注意到这个过程和一个原生程序的执行过程非常类似,一个程序可以视为一个虚拟机,只是它的基本操作非常有限。图形化程序的输入可以认为是鼠标和键盘的操作。虽然,图形化操作已经非常类似编程。由于这些操作系列不满足有限,因此还不能说图形化操作也是编程。

我们如何设计一个计算机程序?

这个问题等同于“如何用计算机解决一个具体问题?”。简化的步骤如下,

  • 首先,把问题已知和未知用计算机形式设计出来,也就是明确它的类型。
  • 其次,分析最简单的情况来,找到可能的解法。
  • 然后,试图在一般的情况解决它,这里可能需要补充一些中间类型的值。
  • 接着,证明解法正确,且在有限的步骤内可以完成。
  • 最后,用计算机编程语言来描述它。

例如,输出以下由空格和星号组成的图形,图形的高度小于1000行。

   *
  ***
 *****
........

 

计算机的表示

这个问题的已知是一个高度n,小于1000,所以类型可以是int.

输出是一个基本操作,打印一行文字,共有a个空格和b个星号,我们记作put-stars(a, b)

未知是n行输出。

从简单的情况来看:

n=1时,有1行输出a=0, b=1;

n=2时,有2行输出,第1行a=1,b=1, 第2行a=0,b=3

n=3时,有3行输出,第1行a=2,b=1, 第2行a=1,b=3,第3行a=0,b=5

结合图形的观察,我们可以猜测,n行中每行的a和b都是一个固定序列的第i项。b比较容易看出来,它的通项是2i-1;a可能略难,不过从图形上可以看出,它是n-i。

从一般情况下来看:

当我们知道第n-1行的a=1,b=2(n-1)-1时,不难知道下一行是a=0,b=2n-1。

正确性证明

从图形上来看,每行空格比上一行少一个,星号多两个,可知a序列满足要求,b序列也满足要求。同时,最多需要n次输出操作就可以完成。

最后用计算机语言来实现它:

void draw(int n)
{
for (int i = 1; i <= n; ++i) {
put-stars(n-i, 2*i-1);
}
}

以后,我们不讨论具体如何分析和设计,只考虑在已知算法的情况下,如何来实现它。比如:C++的习惯上,计数项从0开始到n-1结束,我们可以重新写通项为n - i - 1和2 * i + 1。代码实现为:

 1 void draw(int n)
2 {
3 for (int i = 0; i < n; ++i) {
4 put-stars(n-i-1, 2*i+1);
5
6 }
7 }

注1:我认为好的教材有几种:有些经验编程的同学可以用简单明了的Essential C++;经验较少的同学可以用事无巨细的C++ Primer;对于零基础的初学者,按部就班用Programming:principles and practice design using C++更好。

注2:整数除法运算时,小数部分会直接丢弃,而不是通常的四舍五入。

如何用C++语言编程(How to program in C++)的更多相关文章

  1. 华为C语言编程规范

    DKBA华为技术有限公司内部技术规范DKBA 2826-2011.5C语言编程规范2011年5月9日发布 2011年5月9日实施华为技术有限公司Huawei Technologies Co., Ltd ...

  2. Linux下安装MySQL数据库以及用C语言编程存取数据库

    ubuntu下安装软件相当简单,一条简单的 apt-get install 就可以解决,相比源码安装方式唯一的缺点就是,你无法自定义软件的安装目录.不过这也不是什么太大的缺点.下面我们就用 apt-g ...

  3. C语言编程规范

    C语言编程规范 6 函数与过程 6.1 函数的功能与规模设计 函数应当短而精美,而且只做一件事.不要设计多用途面面俱到的函数,多功能集于一身的函数,很可能使函数的理解.测试.维护等变得困难. 6.2 ...

  4. C语言编程规范试题

    C语言编程规范试题 [说明]: 1.本试题中不考虑头文件引用问题(假定已经包含正确的头文件),C语言的标准函数都可用: 2.如果不特别说明,假定程序运行环境为:操作系统Windows 2000, VC ...

  5. C语言编程实现Linux命令——who

    C语言编程实现Linux命令--who 实践分析过程 who命令是查询当前登录的每个用户,它的输出包括用户名.终端类型.登录日期及远程主机,在Linux系统中输入who命令输出如下: 我们先man一下 ...

  6. 个人c语言编程风格总结

    总结一下我个人的编程风格及这样做的原因吧,其实是为了给实验室写一个统一的C语言编程规范才写的.首先声明,我下面提到的编程规范,是自己给自己定的,不是c语言里面规定的. 一件事情,做成和做好中间可能隔了 ...

  7. Linux下C语言编程实现spwd函数

    Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...

  8. 混合语言编程:启用CLR(公共语言运行时编译)让C#调用C++

    前言 关于混合C#和C++的编程方式,本人之前写过一篇博客(参见混合语言编程:C#使用原生的Directx和OpenGL),在之前的博客中,介绍了在C#的Winform和WPF下使用原生的Direct ...

  9. Linux基础与Linux下C语言编程基础

    Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...

随机推荐

  1. 10个实用的PHP正则表达式 (转)

    http://www.iteye.com/news/23231 1. 验证E-mail地址 这是一个用于验证电子邮件的正则表达式.但它并不是高效.完美的解决方案.在此不推荐使用. $email = & ...

  2. 在ACCESS中创建数据库和查询(ACCESS 2000)

    备份还原数据库 备份.还原 —— 复制\粘贴 压缩修复数据库命令 —— 复制该文件并重新组织,并重新组织文件在磁盘上的储存方式.压缩同时优化了Access数据库的性能.(工具——实用数据库工具或者工具 ...

  3. android studio修改新项目package名称

    android项目生成APK发布必须保证package唯一.新项目在已有项目基础上修改就必须修改package名称. 操作如下: 1) 在模块(module)上右键选择Refactor->Ren ...

  4. ArcGlobe点击IGlobeServerLayer图层读取信息

    ArcGISServer将点图层发布成Globe服务,AE开发中自定义识别工具,读取点数据信息. 1) 通过Locate方法获取图层对象,图层对象中的SearchOID就是你点中的要素Objectid ...

  5. ajax读取json数据

    首先建立json.txt文件 { "programmers": [ { "firstName": "Brett", "lastNa ...

  6. ylb:创建数据库、表,对表的增查改删语句

    ylbtech-SQL Server:SQL Server-创建数据库.表,对表的增查改删语句 SQL Server 创建数据库.表,对表的增查改删语句. 1,ylb:创建数据库.表,对表的增查改删语 ...

  7. mysql Access denied for user \'root\'@\'localhost\'”解决办法总结,下面我们对常见的出现的一些错误代码进行分析并给出解决办法,有需要的朋友可参考一下。

    mysql Access denied for user \'root\'@\'localhost\'”解决办法总结,下面我们对常见的出现的一些错误代码进行分析并给出解决办法,有需要的朋友可参考一下. ...

  8. Java 分割文件 注意事项

    public static void main(String args[]) throws Exception { if (args.length < 1) { System.exit(0); ...

  9. win7 提示"Windows 无法连接到System Event Notification Service服务......"的解决办法

    登录win7系统,突然出现如图1的提示,无线网络中断,不能上网,多次插拔无线网卡问题依然. 图1 解决过程如下: 1.检查网卡硬件状况,在设备管理器中查看网卡现象正常,排除网卡硬件故障. 2.查看服务 ...

  10. scala 连接 mysql

    code: import java.sql.{ResultSet, DriverManager} import com.mysql.jdbc.Connection object hoursAvg { ...