欢迎大家来到IT世界,在知识的湖畔探索吧!
在20世纪90年代便是最重要的编程语言之一,并在21世纪仍保持强劲势头。C++继承了C语言高效、简洁、快速和可移植性的传统。C++面向对象的特性带来了全新的编程方法,这种方法是为应付复杂程度不断提高的现代编程任务而设计的。C++的模板特性提供了另一种全新的编程方法——泛型编程。这三件法宝既是福也是祸,一方面让C++语言功能强大,另一方面则意味着有更多的东西需要学习。
C++融合了3种不同的编程方式:C语言代表的过程性语言、C++在C语言基础上添加的类代表的面向对象语言、C++模板支持的泛型编程。使用C++的原因之一是为了利用其面向对象的特性。要利用这种特性,必须对标准C语言知识有较深入的了解,因为它提供了基本类型、运算符、控制结构和语法规则。所以,如果已经对C有所了解,便可以学习C++了,但这并不仅仅是学习更多的关键字和结构,从C过渡到C++的学习量就像从头学习C语言一样大。另外,如果先掌握了C语言,则在过渡到C++时,必须摒弃一些编程习惯。如果不了解C语言,则学习C++时需要掌握C语言的知识、OOP知识以及泛型编程知识,但无需摒弃任何编程习惯。如果您认为学习C++可能需要扩展思维,这就对了。
如果你想学习C++,选择 C++ Primer Plus 第6版 中文版准没错。
C++ Primer Plus 第6版 中文版在今年重新再版。
划重点:
C++教程十年新版再现,经久不衰的C++畅销经典教程,中文版累计销量超册,2020版赠送价值99元e读版电子书及在线实验环境,附赠大尺寸(60CM*80CM)全书学习思维导图。
- 全新升级,针对C++11标准全面更新;
- 专为零基础读者撰写,近百万程序员的C++编程启蒙教程;
- 示意图解释概念,方面理解;
- 随时指出潜存的问题,避免走弯路;
- 随处可见的警告、注意、提示随时给读者以警醒;
- 庖丁解牛式分析程序,确保知其然更知其所以然;
- 精心设计复习题、编程练习,检验学习中的问题,提示就业面试笔试的要点;
- 登陆异步社区,免费获得本书配套源代码等资源。
这本书在豆瓣:
豆瓣评分8.6,下图是来自豆瓣的一段中肯建议:
本书遵循的C++标准
当代的编译器都对C++98提供了很好的支持。编写本书期间,有些编译器还支持一些C++11 特性;随着新标准获批,对这些特性的支持将很快得到提高。本书反映了当前的情形,详尽地介绍了C++98,并涵盖了C++11新增的一些特性。在探讨相关的C++98主题时顺便介绍了一些C++新特性,而第18章专门介绍新特性,它总结了本书前面提到的一些特性,并介绍了其他特性。
在编写本书期间,对C++11的支持还不全面,因此难以全面介绍C++11新增的所有特性。考虑到篇幅限制,即使这个新标准获得了全面支持,也无法在一本书中全面介绍它。本书重点介绍大多数编译器都支持的特性,并简要地总结其他特性。
本文重点C++ Primer Plus 第6版 中文版习题解答来啦!
《C++ Primer Plus(第6版)中文版习题解答》是超级畅销书《C++ Primer Plus(第6版)中文版》的配套习题答案,针对书中的复习题和编程练习,给出了解题思路和答案。
《C++ Primer Plus(第6版)中文版习题解答》共分为18章,每一章的主题与《C++ Primer Plus(第6版)中文版》完全一致。每章开篇采用思维导图的方式列出本章的知识点,然后对每章的重点内容进行了梳理总结,最后则对每章中的复习题和编程练习进行了分析并给出了解答思路,确保读者在彻底夯实理论知识的同时,进一步提升实际编程能力。
作为《C++ Primer Plus(第6版)中文版》的配套参考书,《C++ Primer Plus(第6版)中文版习题解答》特别适合需要系统学习C++语言的初学者阅读,也适合打算巩固C++语言知识或者希望进一步提高编程技术的程序员阅读。
关于作者:
Stephen Prata曾在加利福尼亚的马林学院(肯特菲尔德)教授天文学、物理学和程序设计课程,现已退休。他在加州理工学院获得学士学位,在加州大学伯克利分校获得博士学位。他最早接触程序设计,是为了利用计算机给星团建模。Stephen撰写和与他人合著了十几本书籍,其中包括C Primer Plus和Unix Primer Plus。
截选本书第2章部分内容
开始学习C++
本章内容包括:
- 创建C++程序;
- C++程序的一般格式;
- #include编译指令;
- main()函数;
- 使用cout对象进行输出;
- 在C++程序中加入注释;
- 何时以及如何使用endl;
- 声明和使用变量;
- 使用cin对象进行输入;
- 定义和使用简单函数。
要建造简单的房屋,首先要打地基、搭框架。如果一开始没有牢固的结构,后面就很难建造窗子、门框、圆屋顶和镶木地板的舞厅等。同样,学习计算机语言时,应从程序的基本结构开始学起。只有这样,才能一步一步了解其具体细节,如循环和对象等。本章对C++程序的基本结构做一概述,并预览后面将介绍的主题,如函数和类(这里的理念是,先介绍一些基本概念,这样可以激发读者接下去学习的兴趣)。
2.1 进入C++
首先介绍一个显示消息的简单C++程序。程序清单2.1使用C++工具cout生成字符输出。源代码中包含一些供读者阅读的注释,这些注释都以//打头,编译器将忽略它们。C++对大小写敏感,也就是说区分大写字符和小写字符。这意味着大小写必须与示例中相同。例如,该程序使用的是cout,如果将其替换为Cout或COUT,程序将无法通过编译,并且编译器将指出使用了未知的标识符(编译器也是对拼写敏感的,因此请不要使用kout或coot)。文件扩展名cpp是一种表示C++程序的常用方式,您可能需要使用第1章介绍的其他扩展名。
程序清单2.1 myfirst.cpp
// myfirst.cpp -- displays a message #include <iostream> // a PREPROCESSOR directive int main() // function header { // start of function body using namespace std; // make definitions visible cout << "Come up and C++ me some time."; // message cout << endl; // start a new line cout << "You won’t regret it!" << endl; // more output return 0; // terminate main() }
欢迎大家来到IT世界,在知识的湖畔探索吧!
程序调整
要在自己的系统上运行本书的示例,可能需要对其进行修改。有些窗口环境在独立的窗口中运行程序,并在程序运行完毕后自动关闭该窗口。正如第1章讨论的,要让窗口一直打开,直到您按任何键,可在return语句前添加如下语句:
欢迎大家来到IT世界,在知识的湖畔探索吧!cin.get();
对于有些程序,要让窗口一直打开,直到您按任何键,必须添加两条这样的语句。第4章将更详细地介绍cin.get()。
如果您使用的系统很旧,它可能不支持C++98新增的特性。
有些程序要求编译器对C++11标准提供一定的支持。对于这样的程序,将明确的指出这一点,并在可能的情况下提供非C++11代码。
将该程序复制到您选择的编辑器中(或使用本书配套网站的源代码,详情请参阅封底)后,便可以C++编译器创建可执行代码了(参见第1章的介绍)。下面是运行编译后的程序时得到的输出:
Come up and C++ me some time. You won’t regret it!
C语言输入和输出
如果已经使用过C语言进行编程,则看到cout函数(而不是printf()函数)时可能会小吃一惊。事实上,C++能够使用printf()、scanf()和其他所有标准C输入和输出函数,只需要包含常规C语言的stdio.h文件。不过本书介绍的是C++,所以将使用C++的输入工具,它们在C版本的基础上作了很多改进。
您使用函数来创建C++程序。通常,先将程序组织为主要任务,然后设计独立的函数来处理这些任务。程序清单2.1中的示例非常简单,只包含一个名为main()的函数。myfirst.cpp示例包含下述元素。
- 注释,由前缀//标识。
- 预处理器编译指令#include。
- 函数头:int main()。
- 编译指令using namespace。
- 函数体,用{和}括起。
- 使用C++的cout工具显示消息的语句。
- 结束main()函数的return语句。
下面详细介绍这些元素。先来看看main()函数,因为了解了main()的作用后,main()前面的一些特性(如预处理器编译指令)将更易于理解。
2.1.1 main()函数
去掉修饰后,程序清单2.1中的示例程序的基本结构如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!int main() { statements return 0; }
这几行表明有一个名为main()的函数,并描述了该函数的行为。这几行代码构成了函数定义(function definition)。该定义由两部分组成:第一行int main()叫函数头(function heading),花括号({和})中包括的部分叫函数体。图2.1对main()函数做了说明。函数头对函数与程序其他部分之间的接口进行了总结;函数体是指出函数应做什么的计算机指令。在C++中,每条完整的指令都称为语句。所有的语句都以分号结束,因此在输入示例代码时,请不要省略分号。
图2.1 main( )函数
main()中最后一条语句叫作返回语句(return statement),它结束该函数。本章将讲述有关返回语句的更多知识。
语句和分号
语句是要执行的操作。为理解源代码,编译器需要知道一条语句何时结束,另一条语句何时开始。有些语言使用语句分隔符。例如,FORTRAN通过行尾将语句分隔开来,Pascal使用分号分隔语句。在Pascal中,有些情况下可以省略分号,例如END前的语句后面,这种情况下,实际上并没有将两条语句分开。不过C++与C一样,也使用终止符(terminator),而不是分隔符。终止符是一个分号,它是语句的结束标记,是语句的组成部分,而不是语句之间的标记。结论是:在C++中,不能省略分号。
1.作为接口的函数头
就目前而言,需要记住的主要一点是,C++句法要求main()函数的定义以函数头int main()开始。本章后面的“函数”一节将详细讨论函数头句法,然而,为满足读者的好奇心,下面先预览一下。
通常,C++函数可被其他函数激活或调用,函数头描述了函数与调用它的函数之间的接口。位于函数名前面的部分叫作函数返回类型,它描述的是从函数返回给调用它的函数的信息。函数名后括号中的部分叫作形参列表(argument list)或参数列表(parameter list);它描述的是从调用函数传递给被调用的函数的信息。这种通用格式用于main()时让人感到有些迷惑,因为通常并不从程序的其他部分调用main()。
然而,通常,main()被启动代码调用,而启动代码是由编译器添加到程序中的,是程序和操作系统(UNIX、Windows 7或其他操作系统)之间的桥梁。事实上,该函数头描述的是main()和操作系统之间的接口。
来看一下main()的接口描述,该接口从int开始。C++函数可以给调用函数返回一个值,这个值叫作返回值(return value)。在这里,从关键字int可知,main()返回一个整数值。接下来,是空括号。通常,C++函数在调用另一个函数时,可以将信息传递给该函数。括号中的函数头部分描述的就是这种信息。在这里,空括号意味着main()函数不接受任何信息,或者main()不接受任何参数。(main()不接受任何参数并不意味着main()是不讲道理的、发号施令的函数。相反,术语参数(argument)只是计算机人员用来表示从一个函数传递给另一个函数的信息)。
简而言之,下面的函数头表明main()函数可以给调用它的函数返回一个整数值,且不从调用它的函数那里获得任何信息:
int main()
很多现有的程序都使用经典C函数头:
欢迎大家来到IT世界,在知识的湖畔探索吧!main() // original C style
在C语言中,省略返回类型相当于说函数的类型为int。然而,C++逐步淘汰了这种用法。
也可以使用下面的变体:
int main(void) // very explicit style
在括号中使用关键字void明确地指出,函数不接受任何参数。在C++(不是C)中,让括号空着与在括号中使用void等效(在C中,让括号空着意味着对是否接受参数保持沉默)。
有些程序员使用下面的函数头,并省略返回语句:
欢迎大家来到IT世界,在知识的湖畔探索吧!void main()
这在逻辑上是一致的,因为void返回类型意味着函数不返回任何值。该变体适用于很多系统,但由于它不是当前标准强制的一个选项,因此在有些系统上不能工作。因此,读者应避免使用这种格式,而应使用C++标准格式,这不需要做太多的工作就能完成。
最后,ANSI/ISO C++标准对那些抱怨必须在main()函数最后包含一条返回语句过于繁琐的人做出了让步。如果编译器到达main()函数末尾时没有遇到返回语句,则认为main()函数以如下语句结尾:
return 0;
这条隐含的返回语句只适用于main()函数,而不适用于其他函数。
2.为什么main()不能使用其他名称
之所以将myfirst.cpp程序中的函数命名为main(),原因是必须这样做。通常,C++程序必须包含一个名为main()的函数(不是Main()、MAIN()或mane()。记住,大小写和拼写都要正确)。由于myfirst.cpp程序只有一个函数,因此该函数必须担负起main()的责任。在运行C++程序时,通常从main()函数开始执行。因此,如果没有main(),程序将不完整,编译器将指出未定义main()函数。
存在一些例外情况。例如,在Windows编程中,可以编写一个动态链接库(DLL)模块,这是其他Windows程序可以使用的代码。由于DLL模块不是独立的程序,因此不需要main()。用于专用环境的程序——如机器人中的控制器芯片——可能不需要main()。有些编程环境提供一个框架程序,该程序调用一些非标准函数,如_tmain()。在这种情况下,有一个隐藏的main(),它调用_tmain()。但常规的独立程序都需要main(),本书讨论的都是这种程序。
2.1.2 C++注释
C++注释以双斜杠(//)打头。注释是程序员为读者提供的说明,通常标识程序的一部分或解释代码的某个方面。编译器忽略注释,毕竟,它对C++的了解至少和程序员一样,在任何情况下,它都不能理解注释。对编译器而言,程序清单2.1就像没有注释一样:
欢迎大家来到IT世界,在知识的湖畔探索吧!#include <iostream> int main() { using namespace std; cout << "Come up and C++ me some time."; cout << endl; cout << "You won’t regret it!" << endl; return 0; }
C++注释以//打头,到行尾结束。注释可以位于单独的一行上,也可以和代码位于同一行。请注意程序清单2.1的第一行:
// myfirst.cpp -- displays a message
本书所有的程序都以注释开始,这些注释指出了源代码的文件名并简要地总结了该程序。在第1章中介绍过,源代码的文件扩展名取决于所用的C++系统。在其他系统中,文件名可能为myfirst.C或myfirst.cxx。
提示:
应使用注释来说明程序。程序越复杂,注释的价值越大。注释不仅有助于他人理解这些代码,也有助于程序员自己理解代码,特别是隔了一段时间没有接触该程序的情况下。
C-风格注释
C++也能够识别C注释,C注释包括在符号/和/之间:
欢迎大家来到IT世界,在知识的湖畔探索吧!#include <iostream> /* a C-style comment */
由于C-风格注释以*/结束,而不是到行尾结束,因此可以跨越多行。可以在程序中使用C或C++风格的注释,也可以同时使用这两种注释。但应尽量使用C++注释,因为这不涉及到结尾符号与起始符号的正确配对,所以它产生问题的可能性很小。事实上,C++标准也在C语言中添加了//注释。
下面简要介绍一下需要知道的一些知识。如果程序要使用C++输入或输出工具,请提供这样两行代码:
#include <iostream> using namespace std;
可使用其他代码替换第2行,这里使用这行代码旨在简化该程序(如果编译器不接受这几行代码,则说明它没有遵守标准C++98,使用它来编译本书的示例时,将出现众多其他的问题)。为使程序正常工作,只需要知道这些。下面更深入地介绍一下这些内容。
C++和C一样,也使用一个预处理器,该程序在进行主编译之前对源文件进行处理(第1章介绍过,有些C++实现使用翻译器程序将C++程序转换为C程序。虽然翻译器也是一种预处理器,但这里不讨论这种预处理器,而只讨论这样的预处理器,即它处理名称以#开头的编译指令)。不必执行任何特殊的操作来调用该预处理器,它会在编译程序时自动运行。
程序清单2.1使用了#include编译指令:
欢迎大家来到IT世界,在知识的湖畔探索吧!#include <iostream> // a PREPROCESSOR directive
该编译指令导致预处理器将iostream文件的内容添加到程序中。这是一种典型的预处理器操作:在源代码被编译之前,替换或添加文本。
这提出了一个问题:为什么要将iostream文件的内容添加到程序中呢?答案涉及程序与外部世界之间的通信。iostream中的io指的是输入(进入程序的信息)和输出(从程序中发送出去的信息)。C++的输入/输出方案涉及iostream文件中的多个定义。为了使用cout来显示消息,第一个程序需要这些定义。#include编译指令导致iostream文件的内容随源代码文件的内容一起被发送给编译器。实际上,iostream文件的内容将取代程序中的代码行#include <iostream>。原始文件没有被修改,而是将源代码文件和iostream组合成一个复合文件,编译的下一阶段将使用该文件。
注意:
使用cin和cout进行输入和输出的程序必须包含文件iostream。
2.1.4 头文件名
像iostream这样的文件叫作包含文件(include file)——由于它们被包含在其他文件中;也叫头文件(header file)——由于它们被包含在文件起始处。C++编译器自带了很多头文件,每个头文件都支持一组特定的工具。C语言的传统是,头文件使用扩展名h,将其作为一种通过名称标识文件类型的简单方式。例如,头文件math.h支持各种C语言数学函数,但C++的用法变了。现在,对老式C的头文件保留了扩展名h(C++程序仍可以使用这种文件),而C++头文件则没有扩展名。有些C头文件被转换为C++头文件,这些文件被重新命名,去掉了扩展名h(使之成为C++风格的名称),并在文件名称前面加上前缀c(表明来自C语言)。例如,C++版本的math.h为cmath。有时C头文件的C版本和C++版本相同,而有时候新版本做了一些修改。对于纯粹的C++头文件(如iostream)来说,去掉h不只是形式上的变化,没有h的头文件也可以包含名称空间——本章的下一个主题。表2.1对头文件的命名约定进行了总结。
由于C使用不同的文件扩展名来表示不同文件类型,因此用一些特殊的扩展名(如.hpp或.hxx)表示C++头文件是有道理的,ANSI/ISO委员会也这样认为。问题在于究竟使用哪种扩展名,因此最终他们一致同意不使用任何扩展名。
2.1.5 名称空间
如果使用iostream,而不是iostream.h,则应使用下面的名称空间编译指令来使iostream中的定义对程序可用:
using namespace std;
这叫作using编译指令。最简单的办法是,现在接受这个编译指令,以后再考虑它(例如,到第9章再考虑它)。但这里还是简要地介绍它,以免您一头雾水。
名称空间支持是一项C++特性,旨在让您编写大型程序以及将多个厂商现有的代码组合起来的程序时更容易,它还有助于组织程序。一个潜在的问题是,可能使用两个已封装好的产品,而它们都包含一个名为wanda()的函数。这样,使用wanda()函数时,编译器将不知道指的是哪个版本。名称空间让厂商能够将其产品封装在一个叫作名称空间的单元中,这样就可以用名称空间的名称来指出想使用哪个厂商的产品。因此,Microflop Industries可以将其定义放到一个名为Microflop的名称空间中。这样,其wanda()函数的全称为Microflop::wanda();同样,Piscine公司的wanda()版本可以表示为Piscine::wanda()。这样,程序就可以使用名称空间来区分不同的版本了:
欢迎大家来到IT世界,在知识的湖畔探索吧!Microflop::wanda("go dancing?"); // use Microflop namespace version Piscine::wanda("a fish named Desire"); // use Piscine namespace version
按照这种方式,类、函数和变量便是C++编译器的标准组件,它们现在都被放置在名称空间std中。仅当头文件没有扩展名h时,情况才是如此。这意味着在iostream中定义的用于输出的cout变量实际上是std::cout,而endl实际上是std::endl。因此,可以省略编译指令using,以下述方式进行编码:
std::cout << "Come up and C++ me some time."; std::cout << std::endl;
然而,多数用户并不喜欢将引入名称空间之前的代码(使用iostream.h和cout)转换为名称空间代码(使用iostream和std::cout),除非他们可以不费力地完成这种转换。于是,using编译指令应运而生。下面的一行代码表明,可以使用std名称空间中定义的名称,而不必使用std::前缀:
欢迎大家来到IT世界,在知识的湖畔探索吧!using namespace std;
这个using编译指令使得std名称空间中的所有名称都可用。这是一种偷懒的做法,在大型项目中是一个潜在的问题。更好的方法是,只使所需的名称可用,这可以通过使用using声明来实现:
using std::cout; // make cout available using std::endl; // make endl available using std::cin; // make cin available
用这些编译指令替换下述代码后,便可以使用cin和cout,而不必加上std::前缀:
欢迎大家来到IT世界,在知识的湖畔探索吧!using namespace std; // lazy approach, all names available
然而,要使用iostream中的其他名称,必须将它们分别加到using列表中。本书首先采用这种偷懒的方法,其原因有两个。首先,对于简单程序而言,采用何种名称空间管理方法无关紧要;其次,本书的重点是介绍C++的基本方面。本书后面将采用其他名称空间管理技术。
2.1.6 使用cout进行C++输出
现在来看一看如何显示消息。myfirst.cpp程序使用下面的C++语句:
cout << "Come up and C++ me some time.";
双引号括起的部分是要打印的消息。在C++中,用双引号括起的一系列字符叫作字符串,因为它是由若干字符组合而成的。<<符号表示该语句将把这个字符串发送给cout;该符号指出了信息流动的路径。cout是什么呢?它是一个预定义的对象,知道如何显示字符串、数字和单个字符等(第1章介绍过,对象是类的特定实例,而类定义了数据的存储和使用方式)。
马上就使用对象可能有些困难,因为几章后才会介绍对象。实际上,这演示了对象的长处之一——不用了解对象的内部情况,就可以使用它。只需要知道它的接口,即如何使用它。cout对象有一个简单的接口,如果string是一个字符串,则下面的代码将显示该字符串:
欢迎大家来到IT世界,在知识的湖畔探索吧!cout << string;
对于显示字符串而言,只需知道这些即可。然而,现在来看看C++从概念上如何解释这个过程。从概念上看,输出是一个流,即从程序流出的一系列字符。cout对象表示这种流,其属性是在iostream文件中定义的。cout的对象属性包括一个插入运算符(<<),它可以将其右侧的信息插入到流中。请看下面的语句(注意结尾的分号):
cout << "Come up and C++ me some time.";
它将字符串“Come up and C++ me some time.”插入到输出流中。因此,与其说程序显示了一条消息,不如说它将一个字符串插入到了输出流中。不知道为什么,后者听起来更好一点(参见图2.2)。
图2.2 使用cout显示字符串
初识运算符重载
如果熟悉C后才开始学习C++,则可能注意到了,插入运算符(<<)看上去就像按位左移运算符(<<),这是一个运算符重载的例子,通过重载,同一个运算符将有不同的含义。编译器通过上下文来确定运算符的含义。C本身也有一些运算符重载的情况。例如,&符号既表示地址运算符,又表示按位AND运算符;* 既表示乘法,又表示对指针解除引用。这里重要的不是这些运算符的具体功能,而是同一个符号可以有多种含义,而编译器可以根据上下文来确定其含义(这和确定“sound card”中的“sound”与“sound financial basic”中的“sound”的含义是一样的)。C++扩展了运算符重载的概念,允许为用户定义的类型(类)重新定义运算符的含义。
1.控制符endl
现在来看看程序清单2.1中第二个输出流中看起来有些古怪的符号:
欢迎大家来到IT世界,在知识的湖畔探索吧!cout << endl;
endl是一个特殊的C++符号,表示一个重要的概念:重起一行。在输出流中插入endl将导致屏幕光标移到下一行开头。诸如endl等对于cout来说有特殊含义的特殊符号被称为控制符(manipulator)。和cout一样,endl也是在头文件iostream中定义的,且位于名称空间std中。
打印字符串时,cout不会自动移到下一行,因此在程序清单2.1中,第一条cout语句将光标留在输出字符串的后面。每条cout语句的输出从前一个输出的末尾开始,因此如果省略程序清单2.1中的endl,得到的输出将如下:
Come up and C++ me some time.You won’t regret it!
从上述输出可知,Y紧跟在句点后面。下面来看另一个例子,假设有如下代码:
欢迎大家来到IT世界,在知识的湖畔探索吧!cout << "The Good, the"; cout << "Bad, "; cout << "and the Ukulele"; cout << endl;
其输出将如下:
The Good, theBad, and the Ukulele
同样,每个字符串紧接在前一个字符串的后面。如果要在两个字符串之间留一个空格,必须将空格包含在字符串中。注意,要尝试上述输出示例,必须将代码放到完整的程序中,该程序包含一个main()函数头以及起始和结束花括号。
2.换行符
C++还提供了另一种在输出中指示换行的旧式方法:C语言符号\n:
欢迎大家来到IT世界,在知识的湖畔探索吧!cout << "What’s next?\n"; // \n means start a new line
\n被视为一个字符,名为换行符。
显示字符串时,在字符串中包含换行符,而不是在末尾加上endl,可减少输入量:
cout << "Pluto is a dwarf planet.\n"; // show text, go to next line cout << "Pluto is a dwarf planet." << endl; // show text, go to next line
另一方面,如果要生成一个空行,则两种方法的输入量相同,但对大多数人而言,输入endl更为方便:
欢迎大家来到IT世界,在知识的湖畔探索吧!cout << "\n"; // start a new line cout << endl; // start a new line
本书中显示用引号括起的字符串时,通常使用换行符\n,在其他情况下则使用控制符endl。一个差别是,endl确保程序继续运行前刷新输出(将其立即显示在屏幕上);而使用“\n”不能提供这样的保证,这意味着在有些系统中,有时可能在您输入信息后才会出现提示。
换行符是一种被称为“转义序列”的按键组合,转义序列将在第3章做更详细的讨论。
2.1.7 C++源代码的格式化
有些语言(如FORTRAN)是面向行的,即每条语句占一行。对于这些语言来说,回车的作用是将语句分开。然而,在C++中,分号标示了语句的结尾。因此,在C++中,回车的作用就和空格或制表符相同。也就是说,在C++中,通常可以在能够使用回车的地方使用空格,反之亦然。这说明既可以把一条语句放在几行上,也可以把几条语句放在同一行上。例如,可以将myfirst.cpp重新格式化为如下所示:
#include <iostream> int main () { using namespace std; cout << "Come up and C++ me some time." ; cout << endl; cout << "You won’t regret it!" << endl;return 0; }
这样虽然不太好看,但仍然是合法的代码。必须遵守一些规则,具体地说,在C和C++中,不能把空格、制表符或回车放在元素(比如名称)中间,也不能把回车放在字符串中间。下面是一个不能这样做的例子:
欢迎大家来到IT世界,在知识的湖畔探索吧!int ma in() // INVALID -- space in name re turn 0; // INVALID -- carriage return in word cout << "Behold the Beans of Beauty!"; // INVALID -- carriage return in string
然而,C++11新增的原始(raw)字符串可包含回车,这将在第4章简要地讨论。
1.源代码中的标记和空白
一行代码中不可分割的元素叫作标记(token,参见图2.3)。通常,必须用空格、制表符或回车将两个标记分开,空格、制表符和回车统称为空白(white space)。有些字符(如括号和逗号)是不需要用空白分开的标记。下面的一些示例说明了什么情况下可以使用空白,什么情况下可以省略:
return0; // INVALID, must be return 0; return(0); // VALID, white space omitted return (0); // VALID, white space used intmain(); // INVALID, white space omitted int main() // VALID, white space omitted in () int main () // ALSO VALID, white space used in ()
图2.3 标记和空白
2.C++源代码风格
虽然C++在格式方面赋予了您很大的自由,但如果遵循合理的风格,程序将更便于阅读。有效但难看的代码不会令人满意。多数程序员都使用程序清单2.1所示的风格,它遵循了下述规则。
- 每条语句占一行。
- 每个函数都有一个开始花括号和一个结束花括号,这两个花括号各占一行。
- 函数中的语句都相对于花括号进行缩进。
- 与函数名称相关的圆括号周围没有空白。
前三条规则旨在确保代码清晰易读;第四条规则帮助区分函数和一些也使用圆括号的C++内置结构(如循环)。在涉及其他指导原则时,本书将提醒读者。
2.2 C++语句
C++程序是一组函数,而每个函数又是一组语句。C++有好几种语句,下面介绍其中的一些。程序清单2.2提供了两种新的语句。声明语句创建变量,赋值语句给该变量提供一个值。另外,该程序还演示了cout的新功能。
程序清单2.2 carrots.cpp
欢迎大家来到IT世界,在知识的湖畔探索吧!// carrots.cpp -- food processing program // uses and displays a variable #include <iostream> int main() { using namespace std; int carrots; // declare an integer variable carrots = 25; // assign a value to the variable cout << "I have "; cout << carrots; // display the value of the variable cout << " carrots."; cout << endl; carrots = carrots - 1; // modify the variable cout << "Crunch, crunch. Now I have " << carrots << " carrots." << endl; return 0; }
空行将声明语句与程序的其他部分分开。这是C常用的方法,但在C++中不那么常见。下面是该程序的输出:
I have 25 carrots. Crunch, crunch. Now I have 24 carrots.
下面探讨这个程序。
2.2.1 声明语句和变量
计算机是一种精确的、有条理的机器。要将信息项存储在计算机中,必须指出信息的存储位置和所需的内存空间。在C++中,完成这种任务的一种相对简便的方法,是使用声明语句来指出存储类型并提供位置标签。例如,程序清单2.2中包含这样一条声明语句(注意其中的分号):
欢迎大家来到IT世界,在知识的湖畔探索吧!int carrots;
这条语句提供了两项信息:需要的内存以及该内存单元的名称。具体地说,这条语句指出程序需要足够的存储空间来存储一个整数,在C++中用int表示整数。编译器负责分配和标记内存的细节。C++可以处理多种类型的数据,而int是最基本的数据类型。它表示整数——没有小数部分的数字。C++的int类型可以为正,也可以为负,但是大小范围取决于实现。第3章将详细介绍int和其他基本类型。
完成的第二项任务是给存储单元指定名称。在这里,该声明语句指出,此后程序将使用名称carrots来标识存储在该内存单元中的值。carrots被称为变量,因为它的值可以修改。在C++中,所有变量都必须声明。如果省略了carrots.cpp中的声明,则当程序试图使用carrots时,编译器将指出错误。事实上,程序员尝试省略声明,可能只是为了看看编译器的反应。这样,以后看到这样的反应时,便知道应检查是否省略了声明。
为什么变量必须声明?
有些语言(最典型的是BASIC)在使用新名称时创建新的变量,而不用显式地进行声明。这看上去对用户比较友好,事实上从短期上说确实如此。问题是,如果错误地拼写了变量名,将在不知情的情况下创建一个新的变量。在BASIC中,ss程序员可能编写如下语句:
CastleDark = 34 ... CastleDank = CastleDark + MoreGhosts ... PRINT CastleDark
由于CastleDank是拼写错误(将r拼成了n),因此所作的修改实际上并没有修改CastleDark。这种错误很难发现,因为它没有违反BASIC中的任何规则。然而,在C++中,将声明CastleDark,但不会声明被错误拼写的CastleDank,因此对应的C++代码将违反“使用变量前必须声明它”的规则,因此编译器将捕获这种错误,发现潜在的问题。
图2.4 变量声明
程序中的声明语句叫作定义声明(defining declaration)语句,简称为定义(definition)。这意味着它将导致编译器为变量分配内存空间。在较为复杂的情况下,还可能有引用声明(reference declaration)。这些声明命令计算机使用在其他地方定义的变量。通常,声明不一定是定义,但在这个例子中,声明是定义。
如果您熟悉C语言或Pascal,就一定熟悉变量声明。不过C++中的变量声明也可能让人小吃一惊。在C和Pascal中,所有的变量声明通常都位于函数或过程的开始位置,但C++没有这种限制。实际上,C++通常的做法是,在首次使用变量前声明它。这样,就不必在程序中到处查找,以了解变量的类型。本章后面将有一个这样的例子。这种风格也有缺点,它没有把所有的变量名放在一起,因此无法对函数使用了哪些变量一目了然(C99标准使C声明规则与C++非常相似)。
提示:
对于声明变量,C++的做法是尽可能在首次使用变量前声明它。
2.2.2 赋值语句
赋值语句将值赋给存储单元。例如,下面的语句将整数25赋给变量carrots表示的内存单元:
欢迎大家来到IT世界,在知识的湖畔探索吧!carrots = 25;
符号=叫作赋值运算符。C++(和C)有一项不寻常的特性——可以连续使用赋值运算符。例如,下面的代码是合法的:
int steinway; int baldwin; int yamaha; yamaha = baldwin = steinway = 88;
赋值将从右向左进行。首先,88被赋给steinway;然后,steinway的值(现在是88)被赋给baldwin;然后baldwin的值88被赋给yamaha(C++遵循C的爱好,允许外观奇怪的代码)。
程序清单2.2中的第二条赋值语句表明,可以对变量的值进行修改:
欢迎大家来到IT世界,在知识的湖畔探索吧!carrots = carrots - 1; // modify the variable
赋值运算符右边的表达式carrots – 1是一个算术表达式。计算机将变量carrots的值25减去1,得到24。然后,赋值运算符将这个新值存储到变量carrots对应的内存单元中。
2.2.3 cout的新花样
到目前为止,本章的示例都使用cout来打印字符串,程序清单2.2使用cout来打印变量,该变量的值是一个整数:
cout << carrots;
程序没有打印“carrots”,而是打印存储在carrots中的整数值,即25。实际上,这将两个操作合而为一了。首先,cout将carrots替换为其当前值25;然后,把值转换为合适的输出字符。
如上所示,cout可用于数字和字符串。这似乎没有什么不同寻常的地方,但别忘了,整数25与字符串“25”有天壤之别。该字符串存储的是书写该数字时使用的字符,即字符2和5。程序在内部存储的是字符2和字符5的编码。要打印字符串,cout只需打印字符串中各个字符即可。但整数25被存储为数值,计算机不是单独存储每个数字,而是将25存储为二进制数(附录A讨论了这种表示法)。这里的要点是,在打印之前,cout必须将整数形式的数字转换为字符串形式。另外,cout很聪明,知道carrots是一个需要转换的整数。
与老式C语言的区别在于cout的聪明程度。在C语言中,要打印字符串“25”和整数25,可以使用C语言的多功能输出函数printf():
欢迎大家来到IT世界,在知识的湖畔探索吧!printf("Printing a string: %s\n", "25"); printf("Printing an integer: %d\n", 25);
撇开printf()的复杂性不说,必须用特殊代码(%s和%d)来指出是要打印字符串还是整数。如果让printf()打印字符串,但又错误地提供了一个整数,由于printf()不够精密,因此根本发现不了错误。它将继续处理,显示一堆乱码。
cout的智能行为源自C++的面向对象特性。实际上,C++插入运算符(<<)将根据其后的数据类型相应地调整其行为,这是一个运算符重载的例子。在后面的章节中学习函数重载和运算符重载时,将知道如何实现这种智能设计。
<script type=”text/javascript” src=”//mp.toutiao.com/mp/agw/mass_profit/pc_product_promotions_js?item_id=0″></script><script type=”text/javascript” src=”//mp.toutiao.com/mp/agw/mass_profit/pc_product_promotions_js?item_id=0″></script>
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/107676.html