C++ Primer Plus(第6版)第二章 开始学习 C++

2.1 进入 C++

一个简单的入门程序如下:

// mytirst.cpp -- displays a message

#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;
}
2.1.1 // mytirst.cpp -- displays a message

C++注释以双斜杠(11)打头。注释是程序员为读者提供的说明,通常标识程序的一部分或解释代码的某个方面。编译器忽略注释,毕竟,它对 C++ 的了解至少和程序员一样,在任何情况下,它都不能理解注释。对编译器而言,程序就像没有注释一样。C++注释以 // 打头,到行尾结束。注释可以位于单独的一行上,也可以和代码位于同一行。在编写程序的过程中,应多使用注释來说明程序。程序越复杂,注释的价值越大。注释不仅有助于他人理解这些代码,也有助于程序员自己理解代码,特别是隔了一段时间没有接触该程序的情况下。

2.1.2 #include <iostream>

分为两个部分来解释:#include 是一个预处理指令。C++ 和 C 一样,也使用一个预处理器,该程序在进行主编译之前对源文件进行处理(第1章介绍过,有些C++实现使用翻译器程序将C++程序转换为 C 程序。虽然翻译器也是一种预处理器,但这里不讨论这种预处理器,而只讨论这样的预处理器,即它处理名称以#开头的编译指令)。不必执行任何特殊的操作来调用该预处理器,它会在编译程序时自动运行。该编译指令导致预处理器将 iostream 文件的内容添加到程序中。这是一种典型的预处理器操作:在源代码被编译之前,替换或添加文本。<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++ 头文件是有道理的,ANSIISO 委员会也这样认为。问题在于究竟使用哪种扩展名,因此最终他们一致同意不使用任何扩展名。

2.1.3 int main()

C++ 要求 main 函数的定义以函数头 int main() 开始。后面将详细讨论函数头语法,这里先简单预习一下。int,C++ 函数可以给调用函数返回一个值,这个值叫做返回值 (return value)。在这里,从关键字 int 可知,main 函数返回一个整数值。main,代表该函数的名字叫 main,这里之所以将程序中的函数命名为 main,原因是必须这样做。通常,C++ 程序必须包含名为 main 的函数(不是Main、MAIN 或 mian)。记住,大小写和拼写都要正确)。由于该程序只有一个函数,因此该函数必须担负起 main 的责任。在运行 C++ 程序时,通常从 main 函数开始执行。因此,如果没有 main 函数,程序将不完整,编译器将会报错指出未定义 main 函数。存在一些例外情况。例如,在 Windows 编程中,可以编写一个动态链接库 (DLL) 模块,这是其他 Windows 程序可以使用的代码。由于 DLL模块不是独立的程序,因此不需要 main 函数。(), C++ 函数在调用另一个函数时,可以将信息传递给该函数。空括号意味着 main 函数不接受任何信息,或者 main 不接受任何参数。简而言之,该函数名称是 main 函数可以给调用它的函数返回一个整数值,且不从调用它的函数那里获得任何信息。

2.1.4 using namespace std;

这叫做 using 编译指令。最简单的办法是,现在接受这个编译指令,以后再考虑它 (例如,到第9章再考虑它)。但这里还是简要地介绍它,以免您一头雾水。名称空间支持是一项 C++ 特性,旨在让您编写大型程序以及将多个厂商现有的代码组合起来的程序时更容易,它还有助于组织程序。一个潜在的问题是,可能使用两个己封装好的产品,而它们都包含一个名为 wanda 的函数。这样,使用 wanda() 函数时,编译器将不知道指的是哪个版本。名称空间让厂商能够将其产品封装在一个叫做名称空间的单元中,这样就可以用名称空间的名称来指出想使用哪个厂 商的产品,因此,Microflop Industries 可以将其定义放到一个名为 Microflop 的名称空间中。这样,其 wanda() 函数的全称为 Microflop: wanda() 同样,Piscine 公司的 wanda() 版本可以表示为 Piscine: wanda()。这样,程序就可以使用名称空间来区分不同的版本了:

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 << endl;

然而,多数用户并不喜欢将引入名称空间之前的代码(使用 iostream.h 和 cout)转换为名称空间代码(使用 iostream 和 std::cout),除非他们可以不费力地完成这种转换。于是,using 编译指令应运而生。下面的一行代码表明,可以使用std 名称空间中定义的名称,而不必使用 std:: 前缀:

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::前缀:

using namespace std;   // lazy approach, all names available

然而,要使用 iostream 中的其他名称,必须将它们分别加到 using 列表中。本书首先采用这种偷懒的方法,其原因有两个。首先,对于简单程序而言,采用何种名称空间管理方法无关紧要;其次,本书的重点是介绍C++的基本方面。本书后面将采用其他名称空间管理技术。

2.1.5 cout << "Come up and C++ me some time.";

它将字符串 “Come up and Ct+ me some time.” 插入到输出流中。双引号括起的部分是要打印的消息。在 C++ 中,用双引号括起的一系列字符叫做字符串,因为它是由若干字符组合而成的。<< 符号功能该语句将把这个字符串发送给 cout;该符号指出了信息流动的路径。cout 是什么呢?它是一个预定义的对象,知道如何显示字符串、数字和单个字符等。现在我们还不理解什么是对象,后面章节会详细讲到。学到后面我们会知道 << 其实是一个运算符重载,最终会调用对象的一个重载函数,现在理解起来比较困难,后面也会详细讲到运算符重载。

2.1.6 cout << endl;

endl 是一个特殊的C++符号,表示一 个重要的概念:重起一行。在输出流中插入 endl 将导致屏幕光标移到下一行开头。诸如 endl 等对于 cout 来说有特殊含义的特殊符号被称为控制符 (manipulator)。和 cout一样,endl 也是在头文件 iostream 中定义的,且位于名称空间 std 中。打印字符串时,cout 不会自动移到下一行,因此在开头程序中,第一条 cout 语句将光标留在输出字符串的后面。每条 cout 语句的输出从前一个输出的末尾开始,因此如果省略最开头程序中的 endl,得到的输出将如下:

Come up and C++ me some time. You won' t regret it !

从上述输出可知,Y 紧跟在句点后面。下面来看另一个例子,假设有如下代码:

cout << "The Good, the"
cout << "Bad,"
cout << "and the Ukulele"

其输出将如下:

The Good, theBad,and the Ukulele

2.2 C++ 语句

C++程序是一组函数,而每个函数又是一组语句。C++ 有好几种语句,下面介绍其中的一些。程序清单 2.2 提供了两种新的语句。声明语句创建变量,赋值语句给该变量提供一个值。

// 程序清单 2.2 carrot.cpp
// carrots. cpp -- food processing program
// uses and displays a variable

#include <iostream>
int main(){
    using namespace std;

    int carrots;

    carrots = 25;
    cout << "I have ";
    cout << carrots;
    cout << " carrots.";
    cout << endl;
    carrots = carrots - 1;
    cout << "Crunch, crunch. Now I have " << carrots << " carrtos." << endl;
    return 0;
}

下面是该程序的输出:

I have 25 carrots
Crunch, crunch. Now I have 24 carrots

我们来探讨一下这个程序。

2.2.1 int carrots;

计算机是一种精确的、有条理的机器。要将信息项存储在计算机中,必须指出信息的存储位置和所需的内存空间。在 C++ 中,完成这种任务的一种相对简便的方法,是使用声明语句来指出存储类型并提供位置标签。这条语句提供了两项信息:需要的内存以及该内存单元的名称。具体地说,这条语句指出程序需要足够的存储空间来存储一个整数,在 C++ 中用 int 表示整数。编译器负责分配和标记内存的细节。C++ 可以处理多种类型的数据,而 int 是最基本的数据类型。它表示整数没有小数部分的数字。C++ 的 int 类型可以为正,也可以为负,但是大小范围取决于实现。第 3 章将详细介绍 int 和其他基本类型。完成的第二项任务是给存储单元指定名称。在这里,该声明语句指出,此后程序将使用名称 carrots 来标识存储在该内存单元中的值。carrots 被称为变量,因为它的值可以修改。在 C++ 中,所有变量都必须声明。如果省略了carrots.cpp 中的声明,则当程序试图使用 carrots 时,编译器将指出错误。

2.2.2 carrots = 25;

这是赋值语句将值赋给存储单元。这条语句将整数 25 赋给变量 carrots 表示的内存单元,符号 = 叫做赋值运算符。

2.2.3 carrots = carrots - 1;

这条赋值语句表明,可以对变量的值进行修改。赋值运算符右边的表达式 carrots -1 是一个算术表达式。计算机将变量 carrots 的值 25 减去1,得到 24。然后,赋值运算符将这个新值存储到变量 carrots 对应的内存单元中。

2.3 其他 C++ 语句

再来看一个 C+语句的例子。程序清单 2.3 中的程序对前一个程序进行了扩展,要求在程序运行时输入一个值。为实现这项任务,它使用了 cin 这是与 cout 进行对应的用于输入的对象。

// 程序清单 2.3 getinfo.cpp
// getinfo.cpp -- input and output

#include <iostream>
int main() {
    using namespace std;
    int carrots;
    cout << "How many carrots do you have?" << endl;
    cin >> carrots;
    cout << "Here are two more.";
    carrots = carrots + 2;
    cout << "Now you have " << carrots << " carrots." << endl;
    return 0;
}

下面是该程序的运行情况:

How many carrots do you have:
12
Here are two more. Now you have 14 carrots
2.3.1 cin >> carrots;

上面的输出表明,从键盘输入的值(12)最终被赋给变量 carrots。从这条语句可知,信息从 cin 流向 carrots。显然,对这一过程有更为正式的描述。就像 C++ 将输出看作是流出程序的字符流一样,它也将输入看作是流入程序的字符流。iostream 文件将 cin 定义为一个表示这种流的对象。输出时,<< 运算符将字符串插入到输出流中;输入时,cin 使用 >> 运算符从输入流中抽取字符。通常,需要在运算符右侧提供一个变量,以接收抽取的信息(符号 << 和 >> 被选择用来指示信息流的方向),与 cout 一样,cin 也是一个智能对象。它可以将通过键盘输入的一系列字符(即输入)转换为接收信息的变量能够接受的形式。在这个例子中,程序将 carrots 声明为一个整型变量,因此输入被转换为计算机用来存储整数的数字形式。

2.4 函数

由于两数用于创建 C++ 程序的模块,对 C++ 的 OOP 定义至关重要,因此必须熟悉它。函数的某些方面属于高级主题,将在第 7 章和第 8 章重点讨论函数。现在我们可以先了解函数的一些基本特征,将使得在以后的函数学习中更加得心应手。本章剩余的内容将介绍函数的一些基本知识。C++ 函数分两种:有返回值的和没有返回值的。在标准 C++ 函数库中可以找到这两类函数的例子,您也可以自己创建这两种类型的函数。下面首先来看一个有返回值的库函数,然后介绍如何编写简单的函数。

2.4.1 使用有返回值的库函数

有返回值的函数将生成一个值,而这个值可赋给变量或在其他表达式中使用。例如,标准 C/C++ 库包含一个名为 sqrt() 的函数,它返回平方根。假设要计算 6.25 的平方根,并将这个值赋给变量 x,则可以在程序中使用下面的语句:

X = sqrt (6.25); // returns the value 2.5 and assigns it to x

表达式 sqrt(6.25) 将调用 sqrt() 函数。表达式 sqrt(6.25) 被称为两数调用,被调用的函数叫做被调用函数(called function),包含函数调用的函数叫做调用函数(calling function,参见图 2.6)。圆括号中的值(这里为6.25)是发送给函数的信息,这被称为传递给函数。以这种方式发送给函数的值叫做参数。(参见图 2.7。)函数 sqrt() 得到的结果为 2.5,并将这个值发送给调用函数,发送回去的值叫做函数的返回值(return value)。可以这么认为,函数执行完毕后,语句中的函数调用部分将被替换为返回的值。因此,这个例子将返回值赋给变量 x。简而言之,参数是发送给函数的信息,返回值是函数中发送回去的值。


图 2.6 调用函数

图 2.7 函数调用的语法
// 程序清单 2.4 sqrt.cpp
// sqrt. cpp -- using the sqrt () function

#include <iostream>
#include <cmath>
int main() {
    using namespace std;
    double area;
    cout << "Enter the floor area, in square feet, of your home: ";
    cin >> area;
    double side;
    side = sqrt(area);
    cout << "That's the equivalent of a square " << side << " feet to the side." << endl;
    cout << "How fascinating!" << endl;
    return 0;
}

下面是该程序的运行情况:

Enter the floor area, in square feet, of your home: 123
That's the equivalent of a square 11.0905 feet to the side.
How fascinating!
2.4.2 函数变体

有些函数需要多项信息。这些函数需要传递多个参数,参数间用逗号分开。例如,数学函数 pow() 接受两个参数,返回值为以第一个参数为底,第二个参数为指数的幂。该两数的原型如下:

double pow (double, double);    // prototype of a function with two arguments

要计算 5 的 8 次方,可以这样使用该函数:

answer = pow (5.0, 8.0) ;      //  function call with a list of arguments

另外一些两数不接受任何参数。例如,有一个C库(与cstdlib 或 stdlib.h 头文件相关的库)包含一个 rand() 函数,该函数不接受任何参数,并返回一个随机整数。该函数的原型如下:

int rand (void) ;   // prototype of a function that takes no arguments

关键宇 void 明确指出,该函数不接受任何参数。如果省略 void,让括号为空,则 C++ 将其解释为一个不接受任何参数的隐式声明。可以这样使用该函数:

myGuess = rand();     // function call with no arguments

注意,与其他一些计算机语言不同,在 C++ 中,两数调用中必须包括括号,即使没有参数,还有一些函数没有返回值。例如,假设编写了一个函数,它按美元、美分格式显示数宇。当向它传递参数 23.5 时,它将在屏幕上显示 $23.50。由于这个函数把值发送给屏幕,而不是调用程序,因此不需要返
回值。可以在原型中使用关键字 void 来指定返回类型,以指出两数没有返回值:

void bucks (double) ;   // prototype for function with no return value

由于它不返回值,因此不能将该两数调用放在赋值语句或其他表达式中。相反,应使用一条纯粹的函数调用语句:

bucks (1234.56) :      //  function call. no return value

在有些语言中,有返回值的两数被称为两数(function):没有返回值的函数被称为过程 (procedure) 或子程序 (subroutine)。但 C++ 与 C 一样,这两种变体都被称为函数。

2.4.3 用户定义的函数

标准 C 库提供了 140 多个预定义的函数。如果其中的西数能满足要求,则应使用它们。但用户经常需要编写自己的函数,尤其是在设计类的时候。无论如何,设计自己的函数很有意思,下面来介绍这一过程。前面已经使用过好几个用户定义的两数,它们都叫 main() 每个 C++程序都必须有一个 main()函数,用户必须对它进行定义。假设需要添加另一个用户定义的函数。和库西数一样,也可以通过函数名来调用用户定义的两数。对于库函数,在使用之前必须提供其原型,通常把原型放到 main() 定义之前。但现在您必须提供新函数的源代码。最简单的方法是,将代码放在main( )的后面。程序清单 2.5 演示了这些元素。

// 程序清单 2.5 ourfunc.cpp
// ourfunc.cpp--defining your own tunctior

#include <iostream>

void simon(int n){
    using namespace std;
    cout << "Simon says touch your toes " << n << " times." << endl;
}

int main() {
    using namespace std;
    simon(3);
    cout << "Pick an intecer: ";
    int count;
    cin >> count;
    simon(count);
    cout << "Done!" << endl;
    return 0;
}

main() 两数两次调用 simon() 函数,一次的参数为 3,另一次的参数为变量 count。在这两次调用之间,用户输入一个整数,用来设置 count 的值。这个例子没有在 cout 提示消息中使用换行符。这样将导致用户输入与提示出现在同一行中。下面是运行情况:

Simon says touch your toes 3 times
Pick an integer: 512
Simon says touch your toes 512 times
Done
2.4.4 用户定义的有返回值的函数

我们再深入一步,编写一个使用返回语句的函数。main() 函数已经揭示了有返回值的函数的格式:在函数头中指出返回类型,在函数体结尾处使用return 。可以用这种形式为在英国观光的人解决重量的问题。在英国,很名浴室都以英石(stone)为单位,不像美国以磅或公斤为单位。一英石等于14磅,程序清单 2.6 使用一个函数来完成这样的转换。

// 程序清单 2.6 convert.cpp
// convert. cpp -- converts stone to pounds

#include <iostream>

int stonetolb(int);

int main() {
    using namespace std;
    int stone;
    cout << "Enter the weight in stone: ";
    cin >> stone;
    int pounds = stonetolb(stone);
    cout << stone << " stone = ";
    cout << pounds << " pounds." << endl;
    return 0;
}

int stonetolb(int stone) {
    return 14 * stone;
}

下面是该程序的运行情况:

Enter the weight in stone: 15
15 stone = 210 pounds.

在 main() 中,程序使用 cin 来给整型变量 stone 提供一个值。这个值被作为参数传递给 stonetolb( ) 函数在该函数中,这个值被赋给变量 stone。然后,
stonetolb() 用关键字return 将 14*stone 返回给 main()。这表明 return 后面并非一定得跟一个简单的数字。这里通过使用较为复杂的表达式,避免了创建一个新变量,将结果赋给该变量,然后将它返回。程序将计算表达式的值(这里为210),并将其返回。如果返回表达式的值很麻烦,可以采取更复杂的方式:

int stonetolb(int stone) {
    int bounds = 14 * stone:
    return pounds;
}

视频链接: pan.baidu.com/s/1wWTcf7NqiWW_N-EQyev3Ig
视频密码: r88b

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容