第一个C++程序C++编程毫无可怕之处——不骗你!像所有其他程序设计语言一样,它只是一种方法,可以把一连串逻辑精确的指令下达给计算机。
C++的复杂程度可能和你预想的一样,但学习它的捷径是用它去解决各种基本的编程任务。本书要走的正是这种捷径。
在本章前几节里,我将向大家介绍一些有关编程的基本概念。如果你曾使用某种语言编写过程序的话,你完全可以跳过这些内容。但如果你有兴趣就从这里开始,我保证不会耽误你太长的时间。
1.1像程序员那样思考
编写程序可能与你以前曾经从事过的任何活动都不一样。简单地说,你是在下达各种指令——但必须以一种逻辑的、系统的方式来做。
计算机只能做你要求它做的事
计算机只能做你让它们去做的事:这是本书里最重要的一条法则,尤其是在你刚开始学习编程的时候。通过使用一种计算机语言,例如C++、VisualBasic、ascal或FORTRAN,你把一系列应该去做的事情写成一份清单并下达给一台计算机;这份清单就是所谓的程序。
当然,计算机需要信息——也就是所谓的数据。但它还需要知道应该对这些数据进行怎样的处理。告诉它如何去做的指令称为程序代码。
确定程序的用途
这么说吧,要想让计算机做件事,就必须精确地告诉它应该做什么事。
到目前为止,通过运行别人为你编写的程序,你应该使用过计算机。从这个意义上讲,你已经是一位最终用户(简称为用户)了。
通过自行编写程序,你将把自己提升到计算机用户群体中更高一级的梯队里。现在,你将决定一个程序要干什么并控制它的发展。
但计算机就像是一个极其白痴而又博学的人——其程度远超达斯汀?霍夫曼在电影《雨人》里所扮演的那个角色。它永远也猜不出你想要什么,它永远也做不出独立判断,它极端教条并只会精确地按照你说的去做,不管事情是多么愚蠢。这就要求你在表达想法时必须小心谨慎、准确无误。
你甚至无法把一条对普通人来说已足够明确的命令(如“替我把一个数值从摄氏温度换算为华氏温度”)下达给计算机。尽管这种换算非常简单,你也必须把详细步骤像下面这样写出来。
(1) 显示Enter Celsius temerature:消息。
(2) 从键盘获取一个数值并把它保存到变量ctem里。
(3) 利用公式华氏温度=(摄氏温度×1.8+32)换算出华氏温度。
(4) 显示The Fahrenheit temerature is:消息。
(5) 显示变量ftem的值。
如果完成一项如此简单的任务都这么麻烦的话,为什么还要大费周折呢?答案是一旦程序编写完毕,你就可以反复多次地运行它。虽然编写程序需要花费时间,但它们执行起来往往有着闪电一般的速度。
. 写出相应的C++语句
在你确定了想让程序去干的事情之后,你就需要一步一步地写出相应的C++语句。一条C++语句大致相当于英语里的一个句子。
比如说,假设你想让程序完成以下工作:
(1) 显示The Fahrenheit temerature is:消息;
(2) 显示变量ftem的值。
你应该把这些步骤转化为如下所示的C++语句:
cout << “The Fahrenheit temerature is: “;
cout << ftem;
请记住,编程的目的是为了让计算机去完成一系列特定任务。可是,计算机只能理解它自己的语言——由1和0构成的机器码。倒退到20世纪50年代,那时的程序员确实是用机器码来编写指令的,但那非常困难,也很花费时间。
为了让事情变得更简单,计算机工程师开发出了各种程序设计语言,如FORTRAN、Basic和C语言等,用它们编写出来的程序与英语至少有了一些相似之处。
在编写程序时,你也许需要从编写伪代码开始,这也是我在这本书里经常用到的办法。伪代码近似于英语,但它会按照程序的逻辑流程以一种系统化的方式去描述程序的动作。比如说,下面就是一段用伪代码写出来的简单程序:
If a is greater than b
rint “a is greater than b.“
Else
rint “a is not greater than b.“
写好了伪代码之后,你离一个C++程序也就不远了。你只需要把每个动作所对应的C++语句写出来就行了:
if (a > b)
cout << “a is greater thanb.“;
else
cout << “a is not greater thanb.“;
程序设计语言的好处是它有一套不允许存在任何歧义的规则。C++语句非常精确,把它们转换为由1和0构成的机器码不会出现任何不确定的问题。
不应该对程序设计语言有着严格的语法规则这件事感到惊讶。这些规则比人类语言里的规则更严谨,往往也更简单。我将随着本书的讨论进度而对这些规则进行汇总。比如说,下面是if-else语法:
if (condition)
statement
else
statement
语法中的黑体字是关键字,它们必须分毫不差地录入到程序里去。斜体字是占位符,需要你提供内容。
把C++语句转换为机器码的应用程序叫做编译器。我将在1.3节对编译器做进一步的介绍。现在,让我们一起来学习一些重要的定义。
计算机到底有多聪明
几年以前,当我华盛顿州的塔科马市负责一个计算机实验室的时候,我曾遇到过一些很有意思的人,其中有几个是在大街上认识的。其中一位老兄是个爱戴草帽的小胖子,穿着不太合身的衣服和一双旧鞋,但总是兴高采烈地笑着。他总是随身带着一份每日赛马赔率表,就像那是一本《圣经》似的。
他每隔一天就会拿着他的赛马报纸来找我一次。“我有个好主意,”他总是这么说。“咱俩可以挣它个100万。只要我们把这些资料输入到电脑里,让它替我们选马就行了。我负责提供每日赛马赔率表,你负责编写程序。咱俩可就发财了!”可我总是笑着对他咕哝一些关于可行性的问题。
他忘记的是(或者说他根本不知道),计算机本身其实什么都不懂。它里面并没有住着一个能够回答你问题的魔法师,完全不像电影《星际迷航》里宇宙飞船上的电脑那么神奇。只是把一堆数据输入到电脑里不会让它完成任何事情。计算机首先需要的是正确的程序,即告诉它如何对数据进行传输、复制、加减乘除或者进行其他运算处理的一系列指令。
让一台计算机从参赛马匹当中选出冠军马的真正关键是,你必须有一个正确的算法,算法是按照一定顺序对数据进行处理以得到结果的过程,或者说是正确的运算公式。如果你能发明一个能准确地预测出冠军马的公式,我绝不否认它会让你发大财。如果真是那样的话,找个计算机来预测赛马结果根本不是什么难事。随便找一台计算机,只要它足以容纳必要的数据,你就可以发大财。
至于找个程序员来编写赛马预测程序这件事,只要你能让对方相信你手里真的有正确的算法,再告诉他你打算从你赌马赢来的大把钞票里分一部分给他,我相信会有一大批人排队等着跟你合作。
更好的办法是你一个人单干,用你从这本书里学到的知识,自己编写一个这样的程序。
应该知道的几个术语
我不喜欢使用专业术语,不骗你。可一旦开始学习编程,你就将进入一个到处都是新术语的世界。要想在这个世界生存下去,下面这些定义是你必须知道的。
应用程序和程序差不多是一回事儿,只不过是从用户的视角去看待而已。应用程序是用户用来完成某种任务的程序。文字处理器就是应用程序,网络浏览器或数据库管理器也是应用程序。甚至连编译器(见稍后的定义)也是应用程序,但它属于一种比较特殊的类型,因为它是供程序员使用的。简单地说,当编写好程序并对它进行编译和测试之后,它就成为了一个应用程序。
代码,“程序”的另一个同义词,只不过这次是从程序员的视角去看。代码这个术语的起源要回溯到程序员编写机器码的年代。每条机器指令被编码为一个由1和0构成的独一无二的组合,这些组合就是用来完成特定操作动作的计算机代码。
即使到了使用C++、Java、FORTRAN或VisualBasic等语言的时候,程序员仍在继续谈论着“代码”。(请参见“源代码”的定义。)另外,术语代码还被用来区分某个程序里的被动性信息(它的数据)与负责完成有关操作的程序部分(它的代码)。
编译器,即语言翻译器,以C++语句(也就是C++源代码)作为输入、以机器码形式作为输出。这是必要的,因为计算机[它的CU(中央处理器)]只能理解机器码。
数据是供某个程序进行处理的信息。在它最基本的级别,这些信息由单词和/或数值构成。
机器码,CU的“母语”,每条计算机指令就是一个由1和0构成的独一无二的组合(或代码)。时至今日,使用机器码来编写程序仍是可行的,但这需要逐条核对每一条指令,还需要对CU的体系结构有深入细致的了解。
诸如C++之类的程序设计语言为人们提供了一种方式,即以近似于英语的形式编写程序,再以足够的逻辑精确性把程序转换为机器码。
程序是由计算机加以执行的一系列指令以及相关的初始数据。如前所述,编写程序需要花费时间,但一旦完成,它通常能以闪电般的速度返复执行。
源代码是以C++等高级语言编写的程序。源代码必须先被转换为机器码才能在计算机上运行。机器码通常以十六进制(逢16进1)表示,它们看起来像下面这样:
08 A7 C3 9E 58 6C 77 90
很难看出这是在干什么,对吧?如果不把它所代表的指令都核查出来,这样一种程序是很难理解的——这也正是为什么现在几乎没人使用机器码来编写程序的原因。与此形成对照的是,源代码至少和英语有几分相似。下面的C++语句的含义是,“如果salary小于0,则显示出错消息”:
if (salary < 0)
rint_error_message();
语句,一条简单的语句通常对应着C++程序里的一行代码,它以分号作为结束标记(就像一个英语句子以句号作为结束标记那样)。但C++还支持复合语句,这也同英语类似,复合语句可以延续好几行。绝大多数C++语句只完成一个动作,只有几个可以完成多个动作。
用户是运行程序的人,也就是使用计算机去完成一项有用的工作(如编辑文本文件、阅读电子邮件、上网冲浪、核对财务收支情况等)的那个人。用户的更正式称呼是最终用户。
回想我在微软公司的那几年,所谓用户就是这个世界上惹麻烦最多的那种人,但同时也是给我们送来钞票的那种人。尽管这种假想中的人也许只是一个完全不懂技术的“门外汉”,但如果没有用户购买产品的话,微软公司恐怕早就不复存在了。因此,当你开始设计重要的程序时,千万要认真考虑用户的需求。
1.2C++有什么与众不同之处
我刚才说的关于C++的那些话大部分也同样适用于其他程序设计语言,如ascal、Java、FORTRAN或Basic,等等。它们都属于高级语言,意思是它们看起来与机器码没有多少相似之处,在编程时需要使用更类似于英语单词的关键字(例如if和while编写代码)。
每一种程序设计语言都是为了某种不同的目的而研发出来的。Basic的设计思路侧重于易学和易用,所以对语法的要求不那么严格,从而比较容易养成一些不良的编程习惯。尽管如此,微软公司还是把VisualBasic发展成了一种强大、方便、快速的Microsoft Windows应用程序开发工具并摒弃了它的一些松散之处。
ascal是为学术环境而研发的,非常适合用来讲授复杂的编程概念。虽然ascal比Basic更为严谨和细致,但你用C或C++能做到的某些事情,ascal不一定能做到。
计算机界的传奇人物DennisRitchie设计C语言的初衷是为了帮助自己编写一个新的操作系统。它是一种精炼的程序设计语言,用它编写出来的程序往往更加短小精悍。C语言有着简明但全面的语法,这为它赢得了全世界程序员的喜爱。C语言的另一个优点是它的限制比其他程序设计语言少。
C++又有什么与众不同之处呢?
C语言和C++之间的主要区别是C++增加了面向对象的编程能力。这种能力非常适合用来解决复杂的问题,比如涉及图形化用户界面和网络环境之类的编程任务。作为面向对象的程序员,你必须回答以下3个问题。
(1) 你将要解决的问题里的数据(也就是信息)可以划分为几种?
(2) 应该为每种数据定义什么样的操作?
(3) 数据对象彼此之间如何交互?
根据我本人在学习面向对象编程技术时的体会,如果你已经掌握了基本的语句语法,学习起来就会很容易。因此,在第11章之前,我将不把讨论重点放在面向对象的编程技术上。
在本书的开始阶段,我会把一些对象(能够对操作作出响应的数据)介绍给你。比如说,我在这一章里用到的cout就是一个不属于C语言的数据对象。在C语言里,信息的显示是通过调用一个函数来完成的。所谓“函数”简单地说就是一组预先定义好的语句。但在你使用cout的时候,是把数据发送给一个对象,而那个对象知道应该如何显示发送给它的信息。
这无疑是一种解决问题的绝佳办法:cout知道如何显示各种类型的信息。更妙的是,你还可以扩展自定义的数据类型(类),让它们与cout之类的输出对象配合使用。
1.3建立C++程序
编写一个程序只是创建应用程序的第一步。首先,你需要输入该程序的所有语句。
输入程序语句
要编写C++程序,你需要一个输入程序语句的工具。
? 你可以使用文本编辑器,比如MicrosoftWord或记事本程序。如果你采取的是这个办法,你必须把文档存为纯文本格式。
? 你可以在一个集成开发环境(integrated develomentenviroment,IDE)里输入文本。集成开发环境由文本编辑器和其他一些编程辅助工具共同构成。Microsoft VisualStudio就是一种集成开发环境。
建立程序(编译并链接)
所谓“建立程序”其实就是把源代码(C++语句)转换为应用程序的过程。这往往只需按下一个功能键即可。整个过程其实分为两步:编译和链接(把别人编写的标准函数引入你的程序)。如果这些步骤都成功了,你就可以运行程序了,参见图1-1。
图1-1程序建立流程图
如果建立过程成功了,你可以恭喜一下自己;编译器和链接器都没有发现错误。这是否意味着你可以收工了呢?不是。编译器只能发现语法错误和程序结构方面的错误,还有许多错误是它发现不了的。考虑下面这样的情况,假设你写出了一个如下所示的句子:
The moon is made green cheese. [sic]
这是一个语法不正确的英语句子。为了把它改成符合语法规则的句子,你需要插入一个单词of:
The moon is made of green cheese.
现在,这个句子没有语法错误了。但这是否意味着它就是一个正确的句子呢?当然不是。具体到这个例子,你还需要再插入一个单词not:
The moon is not made of green cheese.
程序设计语言也有类似的情况。C++编译器只能确定你是否写出了一个语法正确的程序,如果不是,它将报告它在程序的第几行发现了错误。但更大的问题,比如程序是否在所有情况下都能正确执行,就不那么显而易见了。要发现这种问题,就要进行下一步工作。
测试程序
在你成功建立了一个程序之后,你需要运行它以验证它是不是能够正确地完成你想让它完成的事情。如果那是一个很重要的程序,一个将被送给或卖给其他人的程序,你可能需要多次测试它。
你在这个阶段查找的错误称为程序逻辑错误。它们往往要比语法错误更难发现。如果程序输出了一个错误的数值或者无缘无故地停止了执行,是哪条语句导致了问题呢?人们把测试程序并查找问题根源的过程称为调试。
有错必纠
如果程序运行正确,你就可以收工了。但如果有程序逻辑错误,就需要查找错误的根源,修改程序,然后重建程序,参见图1-2。
图1-2程序开发流程图
在编写一个比较复杂的软件时,这样的循环可能需要反复进行许多次。这样的程序往往需要经过非常大量的测试以确保它在所有的情况下都能正确执行。只要你还没有结束这样的测试和改进,程序就不能算是真正完成。但就比较简单的程序而言,通常适当测试几次之后就可放心使用了。
1.4安装C++编译器
earson网站(www.informit.com/title/9780132673266)上有一个可以免费下载多种共享版编译器的链接。我强烈推荐Dev-C++开发工具,它提供了一个可以在其中编写、编译和测试程序的完备的开发环境。
编程示例1-1显示一条消息
现在开始编写程序,打开一个新的源代码文件,然后输入以下代码:
rint1.c
#include <iostream>
using namesace std;int main() {
cout << “Never fear, C++ ishere!“;
system(“AUSE“);
return 0;
}
注意 有些事情在VisualStudio和Dev-C++里的做法是不同的,如果你想让代码正确地编译,请继续阅读后面的几节内容。
在输入源代码的时候,空格的多少无关紧要,但字母的大小写必须准确无误。
如果你使用的是VisualStudio或Dev-C++环境,你将看到一些额外的代码行,就让它们留在那里好了。另外,你还需要打开一个新工程。
如果使用的是Dev-C++环境,打开File(文件)菜单,选择New(新建),打开一个新工程,选择“ConsoleAlication”(控制台应用程序)作为工程类型并为新工程起一个名字。然后在roject(工程)窗口(位于屏幕的左边)里选中源文件main.c。Dev-C++将替你创建出如下所示的代码:
#include <iostream>
#include <cstdlib>using namesace std;int main() {
system(“AUSE“);
return 0;
}
具体到这个例子,你只需要把以cout开头的语句插入到int main(){行与system(“AUSE“);行之间即可,不用理会其他的代码行。
输入程序之后,把它存为rint1文件,编译并运行它。下面是这个程序在输入正确的情况下的运行结果:
Never fear, C++ is here!
使用DEV-C++环境
如果你安装了前一小节描述的C++共享版本,请按以下步骤来运行这个程序。
(1) 按F9功能键来建立和运行这个程序。
(2)如果你没有看到任何出错消息,就说明这个程序的编译和链接步骤都成功了。祝贺你!如果你看到了出错消息,原因可能是你没把编译器安装好或者是你在输入这个例子时打错了字。请从头检查你敲入的每一个字符(包括标点符号在内)是不是准确无误。
使用Microsoft Visual Studio
如果你打算使用Microsoft Visual Studio来编写C++程序,你还需要多做几项准备工作。VisualStudio是一个出色的编程工具,但它是为了创建重要的Windows应用程序而设计的,不太适合用来学习编写简单的程序(如果你是一名C++初学者,当然应该从简单的程序开始)。
要想在Visual Studio里编写程序,必须先创建一个类型适当的工程。(在VisualStudio里,工程是对构成某个程序的全体文件的统称。)
(1) 从File(文件)菜单中选择File子菜单,再选择New(新建)命令。如果Newroject(新工程)正显示在屏幕中间附近,那么你也可以直接点击该按钮。
(2) 填写对话框,先点选ConsoleAlication(控制台应用程序)作为工程类型,再输入程序的名字,本例为rint1,然后单击OK(完成)按钮。
(3) 如果在屏幕上看不到rint1.c文件,请从屏幕左边的文件清单里找到它并双击之。
在输入任何C++代码之前,先把你在rint1.c文件里看到的所有代码全部删掉,除了下面这一行:
#include “stdafx.h“
这条语句是在VisualStudio里创建一个控制台应用程序(或者说,一个非Windows应用程序)所必须包括的。如果你打算使用VisualStudio来学习这本书的话,记得把这行代码插入到每一个程序的开头。
rint1.c文件里的代码应该是下面这样(新增加的代码行以粗体显示):
#include “stdafx.h“
#include <iostream>
using namesace std;int main() {
cout << “Never fear, C++ ishere!“;
return 0;
}
按F7功能键开始创建这个程序。这将启动编译器和链接器。
如果成功了,祝贺你。你已经迈出了第一步。如果程序没被成功地建立起来,请从头检查输入的每一行是否准确无误。
接下来,按Ctrl+F5组合键运行这个程序。虽然在VisualStudio里还有其他办法运行这个程序,但这是唯一能够避免MS-DOS窗口在屏幕上一闪而逝的办法。按下Ctrl+F5组合键(以非调试方式启动程序)将运行这个程序,然后将显示一条ressany key to continue信息,这让你能有机会看到这个程序的输出。
注意 代码行system(“AUSE“);可以让一个控制台应用程序不会太快地从屏幕上一闪而逝。可是,如果你的操作系统不是MS-DOS或Windows的话,这条语句有可能不起作用,你需要把它删掉。
代码分析
不管你是否相信,这个简单的程序只有一条真正的语句。就目前而言,你可以把其余的部分想象成一个模板——即一些你不得不保留在那里、但可以安全忽略的东西。(如果你对细节感兴趣,稍后的“小知识”部分将讨论#include指令。)
在下面给出的语法里,按有关标准必不可少的东西以粗体字给出。你现在还用不着关心它们为什么是必不可少的,原样照抄就行了。在花括号({})之间插入程序的真正代码——就本例而言,它只包含一条重要的语句。
#include <iostream>
using namesace std;int main() {
Enter_your_statements_here!
return 0;
}
这个程序只有一条真正的语句(第5行的那条语句,见前面给出的示例代码)。不要漏掉那个分号(;)!
cout << “Never fear, C++ is here!“;
cout是什么?它是一个对象——这是一个我将在本书的后半部分重点讨论的概念。就目前而言,你只要知道cout代表的是“控制台输出”就可以了。换句话说,它代表着计算机的显示器屏幕。当你把一些东西发送到显示器屏幕的时候,它将显示在屏幕上,就像你想象的那样。
在C++里,信息的输出显示可以通过使用cout和左向“流”操作符(<<)来完成,这个操作符表明了从一个值(在这个例子里是文本字符串“Neverfear, C++ is here!“)到控制台的数据流向。你可以把它想象成图1-3这样。
图1-3cout输出示意图
不要漏掉那个分号(;)。每一条C++语句都必须以分号结尾,只有少数情况下例外。
因为技术方面的原因,只要用到cout,就必须让它出现在左边。此时数据将向左流动。用左向“箭头”(<<),(它实际上是两个小于号)来连接它们。
表1-1给出了几个简单的cout用法示例:
表1-1cout用法示例
语句 动作
cout << “Do you C++?“; 显示短句Do you C++?
cout << “I think, “; 显示短句I think,
cout << “Therefore I rogram.“; 显示短句Therefore Irogram.练习题
练习题1.1.1编写一个程序来显示Get with therogram!。如果愿意,你可以沿用本示例的源文件并进行必要的修改。(提示:只需改动引号之间的文本,其余的程序代码都可以重复使用。)
练习题1.1.2编写一个程序来显示你本人的名字。
练习题1.1.3编写一个程序来显示Do you C++?。
#include和using是干什么用的
我刚才说示例程序的第5行是该程序的第一条“真正的”语句。现在我要说说第一行:
#include <iostream>
这是C++预处理器指令的一个例子。这类指令是下达给C++编译器的。该指令的格式如下所示:
#include <filename>
它将把C++标准库里的相关声明和定义部分引入到程序里。如果没有这个指令,你就不能使用cout了。
如果你曾使用过C和C++的老版本,你可能会困惑为什么这里没有给出一个具体的文件名(比如一个.h文件)。文件名iostream是一个虚拟头文件(virtualinclude file),对应文件里的信息是预编译格式的。
如果你是一位C++新手,只要记住,你必须使用#include指令引入C++标准库的特定组成部分,才能在程序里使用有关的功能。稍后,当我们开始使用sqrt(平方根)等数学函数时,你将需要引入cmath库:
#include <cmath>
有点儿麻烦?是的,是有点儿麻烦。之所以会有这些头文件,是因为C语言和它的标准运行库是区分开的。(专业的C/C++程序员有时会避免使用标准库而使用它们自己的运行库。)库函数和库对象(初学者不太容易区分这两者)与用户定义函数并无本质区别,这意味着它们也必须先声明,而头文件就是干这个用的(详见第4章)。
你还需要加上一条using语句,这样才能直接引用std::cout之类的对象。如果没有这条语句,你就只能像下面这样来显示一条消息:
std::cout << “Never fear, C++ is here!“;
cout(以及它的兄弟cin)是我们经常会用到的,在每个程序的开头加上一条using语句可以省不少事儿。
1.5前进到下一行
在C++程序里,发送到屏幕的文本不会自动前进到下一个物理显示行。你必须输出一个换行符才能做到那一点。(例外:如果你一直不输出换行符,文本将在占满了当前的物理显示行后自动“折返”到下一行,但这么做的显示效果往往很难看。)
输出一个换行符最简单的办法是,使用预定义常数endl。如下所示:
cout << “Never fear, C++ is here!“ << endl;
注意 endl是“end line”的缩写,所以它应该念作“end ELL”而不是“endONE”。还要注意的是,endl其实是std::endl,但using语句可以让你无须输入std::。
输出一个换行符的另一个办法是插入一个\n字符。这是一个转义序列,C++将把它解释为有某种特殊的含义,而不是按字面解释为\后面跟着一个n。下面这条语句和前面的例子有着同样的效果:
cout << “Never fear, C++ is here!\n“;
编程示例1-2显示多行消息
本小节里的程序将显示多行消息。如果你打算亲自动手输入这个程序的代码,请记住字母的大小写必须准确无误,但你可以改变引号内文本的大小写,这不影响程序的运行。
rint2.c
#include <iostream>
using namesace std;int main() {
cout << “I am Blaxxon,“ <<endl;
cout << “the godlike comuter.“<< endl;
cout << “Fear me!“ <<endl; system(“AUSE“);
return 0;
}
把这个程序保存为rint2.c文件,然后按编程示例1-1里给出的步骤编译并运行它。
代码分析
这个例子类似于我最早介绍的那个。主要的区别是这个例子使用了换行符。如果省略这些字符,程序的输出效果将是:
I am Blaxxon,the godlike comuter.Fear me!
而这并不是我们想要的。
图1-4从概念上描述了此程序语句的工作方式。
图1-4换行符输出示意图
你可以像这样显示任意多个数据项,但如果你没有使用换行符(endl)的话,它们将不会前进到下一个物理显示行。你可以用一条语句把多个数据项发送到控制台去:
cout << “This is a “ << “nice “ << “C++rogram.“;
这在程序运行时将显示如下所示的消息:
This is a nice C++ rogram.
你也可以像下面这样嵌入一个换行符:
cout << “This is a“ << endl << “C++rogram.“;
这将显示以下内容:
This is a
C++ rogram.
这个例子与前一个类似,将返回一个值。“返回一个值”是把一个信号发送回(具体到这个例子)操作系统或开发环境的过程。
返回一个值是通过使用return语句实现的。
return 0;
main函数的返回值是一个将被发送回操作系统的代码,一般用0表示执行成功。这本书里的绝大多数示例程序都将返回0。
练习题
练习题1.2.1从本小节的示例程序里删除换行符,但相应地增加一个空格,让各单词不挤在一起。(提示:C++不会在输出字符串之间自动插入一个空格。)输出结果应该是下面这样:
I am Blaxxon, the godlike comuter. Fear me!
练习题1.2.2修改示例程序,让它在两个输出行之间增加一个空白行——换句话说,让显示效果是双倍行距而不是单倍行距。(提示:在每个文本字符串的后面输出两个换行符。)
练习题1.2.3修改示例程序,让它在每个输出行之间增加两个空白行。
什么是字符串
从一开始,我就将要显示的文本括在了引号内,就像下面这条语句那样:
cout << “Never fear, C++ is here!“;
引号外的所有东西都是C++语法的一部分。括在引号内的东西是数据。
从本质上讲,存储在计算机里的一切数据都是数值。但根据具体用途,引号内的东西可以被解释为一串可打印的字符。这就是所谓的字符串。
你们可能听说过“ASCII编码”。本例中的Never fear, C++ ishere!就是这类数据。字符N、e、v、e、r等分别保存在它们各自的字节里,而每个字节里的数值编码都对应着一个可打印字符。
我将在第7章进一步讨论这类数据。现在要求你记住的是:括在引号里的文本都是纯粹的数据(与之相对的是命令),这类数据就是文本字符串,通常称为字符串。
1.6保存数据:C++变量
如果只能用来显示几条消息的话,C++也就没什么大用了。大多数情况下,我们用C++从一些地方获得新数据(比如来自最终用户的输入),再对它们做一些有意思的处理。
这种操作需要用到变量,也就是用来存放数据的地方。你可以把变量想象成用来盛放数据的魔盒。随着程序的进展,它可以根据需要去读取、写入或者改变这些值。接下来的例子使用了名为ctem和ftem的变量来分别存放摄氏温度值和华氏温度值,参见图1-5。
图1-5用两个变量分别存储摄氏温度值和华氏温度值
数据值是如何存放到变量里的呢?一种办法是通过控制台输入。在C++里,你可以使用cin对象来输入数据值,它(就目前而言)代表着控制台输入。配合cin对象,你应该使用一个表明数据向右流动的流操作符(>>),参见图1-6。
图1-6cin输入示意图
下面是这条语句在执行时将发生的事情。(实际过程会更加复杂一些,但现在还用不着关心那么多。)
(1) 程序暂停执行,等待用户输入一个数值。
(2) 用户敲入一个数值并按下回车键。
(3) 程序接收该数值并把它保存到变量ctem里去(就本例而言)。
(4) 程序继续执行。
总之,如果你关注细节的话,下面这条语句在执行时发生的事情还真不少:
cin >> ctem;
但在你可以在C++里使用一个变量之前,你必须先对它作出声明。这是一条必须遵守的规则,这是C++与Basic的重大区别之一,后者在这方面比较宽松,不要求你必须在使用一个变量前对它作出声明。(但因Basic在变量的声明和使用方面的不严格而导致的低级错误已经让好几代Basic程序员都悔恨得用头去撞墙了。)
这条规则的重要性值得反复强调,所以我将把它设为一条核心规则。
在C++里,你在使用一个变量前必须先对它作出声明。
要想说明一个变量,你必须先知道应该使用哪一种数据类型。这是C++和绝大多数其他程序设计语言中的关键概念。
1.7数据类型简介
好吧,你们可以把变量想象成一个供你存放信息或者数据的“魔盒”。但那是什么类型的数据呢?
计算机里的所有数据从本质上讲都是数值,但它们可以归结为三种基本的格式:整数、浮点数和文本字符串,参见图1-7。
图1-7三种数据类型
浮点数和整数的不同之处有好几个,但基本原则很简单。
如果你需要保存的数值带有小数部分,就使用一个浮点变量;否则,就使用整数。
C++里的基本浮点数据类型是double。这看起来像是个奇怪的名字;它的含义是“双精度浮点数”。还有一个单精度浮点类型(float),但它很少使用。当你需要保留小数部分的时候,如果你坚持使用double,你将得到更精确的结果以及更少的出错消息。
下面是声明double变量的语法。请注意,这条语句以一个分号(;)结尾,就像绝大多数语句那样。
double variable_name;
你可以用一个double声明创建多个变量:
double variable_name1, variable_name2, ...;
比如说,下面这个语句将创建一个名为aFloat的double变量:
double aFloat;
这条语句将创建出一个double类型的变量,参见图1-8。
图1-8double类型的变量
下面这条语句将创建4个double变量,它们的名字是b、c、d和amount:
double b, c, d, amount;
这条语句的效果和下面这些语句一样:
double b;
double c;
double d;
double amount;
这些声明的效果是创建出4个double类型的变量,参见图1-9。
图1-94个double类型的变量
双精度比单精度好在哪儿
双精度和单精度相似,但更好。双精度支持更大的取值范围,有更高的精确度:它使用8个字节而不是4个字节来表示一个浮点数。
C++在进行计算的时候会把所有的数据转换为双精度。考虑到现如今的个人电脑都装有8字节的协处理器,这种做法很合理。C++还会把浮点常数保存为双精度——除非你另行指定(比如说,使用带记号的12.5F而不是12.5)。
双精度有一个缺点;它需要更多的空间。但这个因素只在你需要把大量的浮点数值保存到一个磁盘文件里去的时候才值得考虑。也只有在那种情况下,才应该使用单精度类型float。
编程示例1-3温度转换
我每次到加拿大去的时候都不得不用自己的脑袋把摄氏温度换算为华氏温度。要是我有一台手持电脑,让它去替我完成这种换算就好了,计算机最擅长做这种事情。
下面是换算公式。星号(*)和数值一起使用时的含义是“乘以”。
华氏温度=(摄氏温度 * 1.8)+ 32
现在,一个有用的程序将把随意输入的摄氏温度值转换为华氏温度值。这需要用到几个新功能:
? 获取用户输入;
? 把输入值保存到一个变量里。
下面是完整的程序。打开一个新的源文件,输入代码,把它保存为convert.c文件。然后编译并运行。
convert.c
#include <iostream>
using namesace std; int main() {
double ctem, ftem; cout << “Inuta Celsius tem and ress ENTER: “;
cin >>ctem;
ftem = (ctem * 1.8) +32;
cout <<“Fahrenheit tem is: “ << ftem; system(“AUSE“);
return 0;
}
在程序里增加一些注释可以让它更容易理解——C++里的注释以双斜线(//)开头。编译器将忽略程序里的注释(它们对程序的行为没有任何影响),但注释对阅读程序的人很有用。下面是增加了注释的版本:
convert2.c
#include <iostream>
using namesace std; int main() { double ctem; //Celsius temerature
double ftem; //Fahrenheit temerature
// Get value of ctem(Celsius tem). cout << “Inuta Celsius tem and ress ENTER: “;
cin >> ctem;
// Calculate ftem(Fahrenheit tem) and outut. ftem = (ctem * 1.8)+ 32;
cout <<“Fahrenheit tem is: “ << ftem << endl; return 0;
}
这个增加了注释的版本虽然很适合阅读,但需要花费更多的时间去输入。在学习这本书里的示例程序时,你可以省略那些注释或者是稍后再添加它们。记住下面这条关于注释的核心规则。
以双斜线(//)开头的C++代码是一条注释,C++编译器将忽略它们,直到该行结束。
注释不是必不可少的,但使用它们是有好处的,尤其是在日后可能有人(包括你本人在内)需要查看这些C++代码的时候。
代码分析
main中的第一条语句声明了double类型的变量ctem和ftem,它们将分别用来保存摄氏温度和华氏温度。
double ctem, ftem;
这给了我们两个可以用来存放数值的地方,参见图1-10。因为它们是double类型的,所以可以容纳小数部分。请记住,double的含义是“双精度浮点数”。
图1-10两个double类型的变量
接下来的两条语句提示用户并把输入保存到变量ctem里去。假设用户输入的是10,那么存入ctem变量的数值就将是10.0,参见图1-11。
图1-11将用户的输入保存到变量里去
一般来说,你可以在程序里用类似的语句来显示一条提示消息并保存输入数据。提示消息非常有用,如果没有它们,用户将很难知道是不是已经到了应该去做某件事情的时间了。
注意 虽然例子中的输入是10,但它却被存为10.0。在纯粹的数学意义上,10和10.0是相等的——但在C++眼里,10.0表明这个数值是被存储为浮点格式而不是整数格式。这对此后将要发生的事情有着重要的影响。
接下来的语句负责完成具体的换算,用保存在ctem变量里的数值计算出ftem变量的值:
ftem = (ctem * 1.8) + 32;
这条语句完成的是一个赋值操作:求出等号(=)右边的值并把它复制到左边的变量里。这是C++里最常见的操作之一。
仍假设用户输入的数值是10,下面是数据在这个程序中的流动路线,参见图1-12。
图1-12数据在程序中的流动路线
最后,程序将显示换算结果——具体到这个例子,它是50,参见图1-13。
图1-13程序显示换算结果示意图
代码优化
如果仔细观察这个例子,你可能会问自己:真的有必要声明两个变量而不是一个吗?
说实话,还真没这个必要。欢迎来到优化的世界。下面这个版本对这个程序的第一个版本进行了改进,舍弃了ftem变量并把转换和输出步骤合在了一起:
convert3.c
#include <iostream>
using namesace std;
int main() { double ctem; // Celsiustemerature // romt and inut valueof ctem. cout << “Inut aCelsius tem and ress ENTER: “;
cin >> ctem;
// Convert ctem and oututresults. cout << “Fahr. temis: “ << (ctem * 1.8) + 32;
cout << endl; system(“AUSE“);
return 0;
}
你现在有没有觉察出一个程序的套路?对于简单的程序,其套路通常是下面这样的:
(1) 声明变量;
(2) 从用户那里获取输入(先显示一条提示消息);
(3) 进行计算并输出计算结果。
比如说,下面的程序做的事和刚才不同,但看起来很眼熟。这个程序将提示用户输入一个数值,然后显示它的平方积。这个程序里的语句和前例中的很相似,但使用了一个不同的变量(n)和一个不同的算式。
square.c
#include <iostream>
using namesace std; int main() { double n; // romt and inut valueof n. cout << “Inut anumber and ress ENTER: “;
cin >> n;
// Calculate and outut thesquare. cout << “The squareis: “ << n * n << endl; system(“AUSE“);
return 0;
}
练习题
练习题1.3.1改写示例程序,让它进行反向换算:输入一个数值到ftem变量(华氏温度)并换算到ctem变量(摄氏温度),然后显示换算结果。(提示:反向换算的公式是摄氏温度= (华氏温度-32) / 1.8)。
练习题1.3.2只使用一个变量ftem来编写华氏湿度到摄氏湿度换算程序。这是对练习题1.3.1的优化。
练习题1.3.3编写一个程序,把一个值输入到变量n里并输出其立方积(n*n*n)。记得在输出语句里用单词cube替换掉square。
练习题1.3.4改写示例程序square.c,用变量名num代替n。变量名n出现过的每一个地方都要改成新名字。
1.8变量名和关键字
你在本章已经见过的变量有ctem、tem和n。练习题1.3.4让你把n替换为num,这种替换要在整个程序范围内进行。所以num也是一个合法的名字。
变量名可以有无穷无尽的变化。比如说,我可以使用killerRobot或GovernorOf-California作为某些变量的名字。
哪些变量名是合法的,哪些变量名是不合法的呢?只要遵守以下规则,就可以使用任何你想使用的名字。
? 第一个字符必须是一个字母,不能是一个数字。第一个字符也可以是一个下划线(_),但C++库内部使用这种命名规则,所以最好不要用下划线作为变量名的首字符,以避免与C++库里的东西发生冲突。
? 名字的其余部分可以是字母、数字或者下划线(_)。
? 你必须避免使用一个已经在C++里有特殊含义的单词,比如各种关键字。
没必要坐下来背诵所有的C++关键字。你只需要知道如果使用了一个与C++关键字冲突的名字,编译器就会报告一条出错消息。如果遇到这种情况,换个名字试试。
练习题
练习题1.3.5在下面的清单里,哪些单词是合法的C++变量名、哪些不是?请根据上面的规则进行判断。
x
x1
EvilDarkness
ennslyvaniaAve1600
1600ennsylvaniaAve
Bobby_the_Robot
Bobby+the+Robot
whatThe???
amount
count2
count2five
5count
main
main2
1.9小结
下面是第1章的要点内容。
? 创建一个程序的过程从编写C++源代码开始。这由C++语句构成,它们和英语有几分相似。(反观机器码,除非你把每种1和0的组合的含义都弄清楚,否则根本看不懂。)必须先把程序翻译成机器码才能运行,计算机只能理解机器码。
? 把C++语句翻译成机器码的过程称为编译。
? 在编译后,还必须把程序与C++库中的标准函数进行链接。这个过程被称为链接。在这一步骤成功完成之后,你将获得一个可执行程序。
? 如果你手里有一个开发环境,你只需要按一个功能键就可以让编译和链接(合称为建立)步骤自动完成。
? 简单的C++程序有着如下所示的通用格式:
#include <iostream>
using namesace std;int main() {
Enter_your_statements_here!
return 0;
}
? 如果需要显示一条消息,可以使用cout对象。如下所示:
cout << “Never fear, C++ is here!“;
? 如果需要显示多行消息,可以使用cout对象,再发送一个换行符(endl)。如下所示:
cout << “Never fear, C++ is here!“; << endl;
? 几乎所有的C++语句都以一个分号(;)结束。
? 双斜线(//)是注释的开始标记,编译器将忽略从它开始直到该行结束的所有文本。但注释可以为程序维护人员提供帮助。
? 在使用一个变量之前,必须先声明它。如下所示:
double x; // Declare x as a floating-t variable.
? 需要保存小数部分的变量应该声明为double类型。这代表着“双精度浮点数”。单精度类型(float)应该只用于需要把大量的浮点数据保存到磁盘的场合。
? 如果需要把键盘输入的值存入一个变量,可以使用cin对象。如下所示:
cin >> x;
? 你还可以通过赋值操作(=)把数据存入一个变量。这个操作将求出等号(=)右边表达式的值,并把该值存入位于等号左边的变量中。如下所示:
x = y * 2; // Multily y times 2, lace result in x.