《C++ Primer》学习笔记(一):快速入门 (转载)

专栏C++学习笔记

《C++ Primer》学习笔记/习题答案 总目录

——————————————————————————————————————————————————————

快速入门

1、编写简单的 C++ 程序

每个 C++ 程序都包含一个或多个函数,而且必须有一个命名为 main。函数由执行函数功能的语句序列组成。操作系统通过调用 main 函数来执行程序,main 函数则执行组成自己的语句并返回一个值给操作系统。

下面是一个简单的 main 函数,它不执行任何功能,只是返回一个值:

int main()
{
return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4

操作系统通过 main 函数返回的值来确定程序是否成功执行完毕。返回 0值表明程序程序成功执行完毕。main 函数在很多方面都比较特别,其中 最重要的是每个 C++ 程序必须含有 main 函数,且 main 函数是(唯一)被操作系统显式调用的函数。

定义 main 函数和定义其他函数一样。定义函数必须指定 4 个元素:返回类型、函数名、圆括号内的形参表(可能为空)和函数体main 函数的形参个数是有限的。上面的例子中定义的 main 函数形参表为空。后面将介绍 main 函数中可以定义的其他形参。main 函数的返回值必须是 int 型,该类型表示整数。int 类型是内置类型,即该类型是由 C++ 语言定义的。

函数体函数定义的最后部分,是以 花括号 开始并以 花括号 结束的语句块:

{
return 0;
}

  
  
  • 1
  • 2
  • 3

这个例子中唯一的语句就是 return,该语句终止函数。

注意 :return 语句后面的分号。在 C++ 中多数语句 以分号作为结束标记。分号很容易被忽略,而漏写分号将会导致莫名其妙的编译错误信息。

当 return 带上一个值(如 0)时,这个值就是函数的返回值。返回值类型必须和函数的返回类型相同,或者可以转换成函数的返回类型。对于 main 函数,返回类型必须是 int 型,0 是 int 型的。

在大多数系统中,main 函数的返回值是一个 状态指示器。返回值 0 往往表示 main 函数成功执行完毕,任何其他非零的返回值都有操作系统定义的含义。通常非零返回值表明有错误出现。每一种操作系统都有自己的方式告诉用户 main 函数返回什么内容。

2、程序源文件命名规范

不管使用命令行界面还是 IDE,大多数编译器希望待编译的程序保存在文件中。程序文件 称作 源文件。大多数系统中,源文件的名字由文件名(如 prog1)和文件后缀两部分组成。依据惯例,文件后缀表明该文件是程序。文件后缀通常也表明程序是用什么语言编写的,以及选择哪一种编译器运行。比如vs里面就是将该程序保存为:prog1.cpp
在这里插入图片描述
除此之外,还有像 .cc.cxx.cp.c

3、初窥输入/输出

C++ 并没有直接定义进行输入或输出(IO)的任何语句,这种功能是由标准库提供的。IO 库提供了大量的设施。然而,对许多应用,编程者只需要了解一些基本概念和操作。

书中的大多数例子都使用了 处理格式化输入和输出的 iostream 库。iostream 库的基础是两种命名为istream 和ostream 的类型,分别表示输入流和输出流。流是指要从某种 IO 设备上读入或写出的字符序列。术语“流”试图说明字符是随着时间顺序生成或消耗的。

1)标准输入与输出对象

标准库定义了 4 个 IO 对象。处理输入时使用命名为 cin(读作 see-in)的 istream 类型对象。这个对象也称为标准输入。处理输出时使用命名为 cout(读作 see-out)的 ostream 类型对象,这个对象也称为标准输出。标准库还定义了另外两个 ostream 对象,分别命名为 cerrclog(分别读作“see-err”和“see-log”)。cerr 对象又叫作标准错误,通常用来输出警告和错误信息给程序的使用者。而 clog 对象用于产生程序执行的一般信息

一般情况下,系统将这些对象与执行程序的窗口联系起来。这样,当我们从 cin 读入时,数据从执行程序的窗口读入,当写到 cincerrclog 时,输出写至同一窗口。运行程序时,大部分操作系统都提供了重定向输入或输出流的方法。利用重定向可以将这些流与所选择的文件联系起来。

2)头文件调用库

到目前为止,你应该已经明白如何编译与执行简单的程序,虽然那个程序什么也不做。再来看两数相加的问题,可以使用 IO 库来扩充 main 程序,要求用户给出两个数,然后输出它们的和:

#include <iostream>
int main()
{
	std::cout << "Enter two numbers:" << std::endl;
	int v1, v2;
	std::cin >> v1 >> v2;
	std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl;
	return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在vs中运行,程序首先在用户屏幕上显示提示语,Enter two numbers:,然后程序等待用户输入。如果用户输入,3 7,然后敲击回车,则程序产生下面的输出。
在这里插入图片描述
程序的第一行是一个预处理指示:#include <iostream>。告诉编译器要使用 iostream 库。尖括号里的名字是一个 头文件。程序使用库工具时必须包含相关的头文件。#include 指示必须单独写成一行——头文件名和 #include 必须在同一行。通常,#include 指示应出现在任何函数的外部,而且习惯上,程序的所有 #include 指示都在文件开头部分出现。

3)写入到流

main 函数体中第一条语句执行了一个表达式。C++ 中,一个表达式由一个或几个操作数和通常是一个操作符组成。该语句的表达式使用输出操作符(<< 操作符),在标准输出上输出提示语:out << "Enter two numbers:" << endl;。这个语句用了两次输出操作符。每个输出操作符实例都接受两个操作数:左操作数必须是 ostream 对象;右操作数是要输出的值。操作符将其右操作数写到作为其左操作数的 ostream 对象。

C++ 中,每个表达式都会产生一个结果,通常是将操作符作用到其操作数所产生的值。当操作符是输出操作符时,结果是左操作数的值。也就是说,输出操作返回的值是输出流本身。既然输出操作符返回的是其左操作数,那么我们就可以将输出请求链接在一起。输出提示语的那条语句等价于 (std::cout << "Enter two numbers:") << std::endl;

因为((std::cout << "Enter two numbers:"))返回其左操作数 std::cout,这条语句等价于

std::cout << "Enter two numbers:";
std::cout << std::endl;

  
  
  • 1
  • 2

endl 是一个特殊值,称为操纵符将它写入输出流时,具有输出换行的效果,并刷新与设备相关联的缓冲区。通过刷新缓冲区,用户可立即看到写入到流中的输出。程序员经常在调试过程中插入输出语句,这些语句都应该刷新输出流。忘记刷新输出流可能会造成输出停留在缓冲区中,如果程序崩溃,将会导致程序错误推断崩溃位置。

4)使用标准库中的名字

其实如果你了解一些的话,就会注意到这个程序中使用的是 std::coutstd::endl,而不是 coutendl。前缀 std:: 表明 coutendl 是定义在 命名空间 std 中的。使用命名空间程序员可以避免与库中定义的名字相同而引起无意冲突。因为标准库定义的名字是定义在命名空间中,所以我们可以按自己的意图使用相同的名字。

标准库使用命名空间的副作用是,当我们使用标准库中的名字时,必须显式地表达出使用的是命名空间 std 下的名字。std::cout 的写法使用了 作用域操作符(scope operator,:: 操作符),表示使用的是定义在命名空间 std 中的 cout

5)读入流

在输出提示语后,将读入用户输入的数据。先定义两个名为 v1v2 的变量来保存输入:int v1, v2;。将这些变量定义为 int 类型,int 类型是一种代表整数值的内置类型。这些变量未初始化,表示没有赋给它们初始值。这些变量在首次使用时会读入一个值,因此可以没有初始值。

下一条语句读取输入:std::cin >> v1 >> v2;。输入操作符(>> 操作符)行为与输出操作符相似。它接受一个 istream 对象作为其左操作数,接受一个对象作为其右操作数,它从 istream 操作数读取数据并保存到右操作数中。像输出操作符一样,输入操作符返回其左操作数作为结果。由于输入操作符返回其左操作数,我们可以将输入请求序列合并成单个语句。换句话说,这个输入操作等价于:

std::cin >> v1;
std::cin >> v2;

  
  
  • 1
  • 2

输入操作的效果是从标准输入读取两个值,将第一个存放在 v1 中,第二个存放在 v2 中。

6)输出

剩下的就是要输出结果:std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl;。这条语句虽然比输出提示语的语句长,但概念上没什么区别。它将每个操作数输出到标准输出。有趣的是操作数并不都是同一类型的值,有些操作数是字符串字面值。例如 "The sum of ",其他是各种 int 值,如 v1v2 以及对算术表达式 v1 + v2 求值的结果。iostream 库定义了接受全部内置类型的输入输出操作符版本。在写 C++ 程序时,大部分出现空格符的地方可用换行符代替。这条规则的一个例外是字符串字面值中的空格符不能用换行符代替。另一个例外是空格符不允许出现在预处理指示中。

7)已初始化变量和未初始化变量

在 C++ 中,初始化是一个非常重要的概念,已初始化变量是指变量在定义时就给定一个值。未初始化变量则未给定初始值:

int val1 = 0; // initialized
int val2; // uninitialized

  
  
  • 1
  • 2

给变量一个初始值几乎总是正确的,但不要求必须这样做。当我们确定变量在第一次使用时会赋一个新值,那就不需要创建初始值。

定义变量时,应该给变量赋初始值,除非确定将变量用于其他意图之前会覆盖这个初值。如果不能保证读取变量之前重置变量,就应该初始化变量。

4、注释

在程序变得更复杂之前,应该明白C++如何处理注释。注释可以帮助其他人阅读程序,通常用于概括算法、确认变量的用途或者阐明难以理解的代码段。注释并不会增加可执行程序的大小,编译器会忽略所有注释。

C++ 中有单行注释和成对注释两种类型的注释。单行注释以双斜线(//)开头,行中处于双斜线右边的内容是注释,被编译器忽略。另一种定界符,注释对(/* /),是从 C 语言继承过来的。这种注释以“/”开头,以“*/”结尾。编译器把落入注释对“/**/”之间的内容作为注释:

#include <iostream>
/* Simple main function: Read two numbers and write their sum */
int main()
{
	// prompt user to enter two numbers
	std::cout << "Enter two numbers:" << std::endl;
	int v1, v2; // uninitialized
	std::cin >> v1 >> v2; // read input
	return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

任何允许有制表符、空格或换行符的地方都允许放注释对。注释对可跨越程序的多行,但不是一定要如此。当注释跨越多行时,最好能直观地指明每一行都是注释。我们的风格是在注释的每一行以星号开始,指明整个范围是多行注释的一部分。

程序通常混用两种注释形式。注释对一般用于多行解释,而双斜线注释则常用于半行或单行的标记。太多的注释混入程序代码可能会使代码难以理解,通常最好是将一个注释块放在所解释代码的上方。

代码改变时,注释应与代码保持一致。程序员即使知道系统其他形式的文档已经过期,还是会信任注释,认为它会是正确的。错误的注释比没有注释更糟,因为它会误导后来者。

注意:注释对不可嵌套!!!

5、控制结构

语句总是顺序执行的:函数的第一条语句首先执行,接着是第二条,依次类推。当然,少数程序可以仅用顺序执行语句编写。事实上,程序设计语言提供了多种控制结构支持更为复杂的执行路径。

1)while 语句

while 语句提供了迭代执行功能。可以用 while 语句编写一个如下所示的从 1 到 10(包括 10)的求和程序:

#include <iostream>
int main()
{
	int sum = 0, val = 1;
	// keep executing the while until val is greater than 10
	while (val <= 10) {
		sum += val; // assigns sum + val to sum
		++val; // add 1 to val
	}
	std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl;
	return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

编译并执行后,将输出:
在这里插入图片描述
与前面一样,程序首先包含 iostream 头文件并定义 main 函数。在 main 函数中定义两个 int 型变量:sum 保存总和,val 表示从 1 到 10 之间的每一个值。我们给 sum 赋初值 0,而 val 则从 1 开始。重要的部分是 while 语句。while 结构有这样的形式:while (condition) while_body_statement;。while 通过测试 condition (条件)和执行相关 while_body_statement 来重复执行,直到 condition 为假。

条件是一个可求值的表达式,所以可以测试其结果。如果结果值非零,那么条件为真;如果值为零,则条件为假。如果 condition 为真(表达式求值不为零),则执行while_body_statement。执行完后,再次测试 condition 。如果 condition 仍为真,则再次执行 while_body_statement。while 语句一直交替测试 condition和执行 while_body_statement,直到 condition 为假为止。

在这个程序中,while 语句是

// keep executing the while until val is greater than 10
while (val <= 10) {
	sum += val; // assigns sum + val to sum
	++val; // add 1 to val
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5

while 语句的条件用了小于或等于操作符(<= 操作符),将 val 的当前值和 10 比较,只要 val 小于或等于 10,就执行 while 循环体。这种情况下,while 循环体是一个包含两个语句的块:

{
	sum += val; // assigns sum + val to sum
	++val; // add 1 to val
}

  
  
  • 1
  • 2
  • 3
  • 4

块是被花括号括起来的语句序列。C++ 中,块可用于任何可以用一条语句的地方。块中第一条语句使用了复合赋值操作符(+= 操作符),这个操作符把它的右操作数加至左操作数,这等效于编写含一个加法和一个赋值的语句:

sum = sum + val; // assign sum + val to sum

  
  
  • 1

因此第一条语句是把 val 的值加到 sum 的当前值,并把结果存入 sum

第二条语句:

++val; // add 1 to val

  
  
  • 1

使用了前自增操作符(++ 操作符),自增操作符就是在它的操作数上加 1,++val 和 val = val + 1 是一样的。
在这里插入图片描述
执行 while 的循环体后,再次执行 while 的条件。如果 val 的值(自增后)仍小于或等于 10,那么再次执行 while 的循环体。循环继续,测试条件并执行循环体,直到 val 的值不再小于或等于 10 为止。一旦 val 的值大于 10,程序就跳出 while 循环并执行 while 后面的语句,此例中该语句打印输出,其后的 return 语句结束 main 程序。

2)for 语句

在 while 循环中,我们使用变量 val 来控制循环执行次数。每次执行 while 语句,都要测试 val 的值,然后在循环体中增加 val 的值。由于需要频频使用像 val 这样的变量控制循环,因而 C++ 语言定义了第二种控制结构,称为 for 语句,简化管理循环变量的代码。使用 for 循环重新编写求 1 到 10 的和的程序,如下:

#include <iostream>
int main()
{
	int sum = 0;
	// sum values from 1 up to 10 inclusive
	for (int val = 1; val <= 10; ++val)
		sum += val; // equivalent to sum = sum + val
	std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl;
	system("pause");
	return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述
在 for 循环之前,我们定义 sum 并赋 0 值。用于迭代的变量 val 被定义为 for 语句自身的一部分。for 语句

for (int val = 1; val <= 10; ++val)
	sum += val; // equivalent to sum = sum + val

  
  
  • 1
  • 2

包含 for 语句头和 for 语句体两部分。for 语句头控制 for 语句体的执行次数。for 语句头由三部分组成:一个初始化语句,一个条件,一个表达式。在这个例子中,初始化语句int val = 1;,定义一个名为 val 的 int 对象并给定初始值 1。初始化语句仅在进入 for语句时执行一次。条件val <= 10

将 val 的当前值和 10 比较,每次经过循环都要测试。只要 val 小于或等于 10,就执行 for 语句体。仅当 for 语句体执行后才执行表达式。在这个 for循环中,表达式使用前自增操作符,val 的值加 1,执行完表达式后,for 语句重新测试条件,如果 val 的新值仍小于或等于 10,则执行 for 语句体,val 再次自增,继续执行直到条件不成立。

在这个循环中,for 语句体执行求和sum += val; // equivalent to sum = sum + val,for 语句体使用复合赋值操作符,把 val 的当前值加到 sum,并将结果保存到 sum 中。

扼要重述一下,for 循环总的执行流程为:

  1. 创建 val 并初始化为 1。
  2. 测试 val 是否小于或等于 10。
  3. 如果 val 小于或等于 10,则执行 for 循环体,把 val 加到 sum 中。如果 val 大于 10,就退出循环,接着执行 for 语句体后的第一条语句。
  4. val 递增。
  5. 重复第 2 步的测试,只要条件为真,就继续执行其余步骤。

退出 for 循环后,变量 val 不再可访问,循环终止后使用 val 是不可能的。

3)if 语句

求 1 到 10 之间数的和,其逻辑延伸是求用户提供的两个数之间的数的和。可以直接在 for 循环中使用这两个数,使用第一个输入值作为下界而第二个输入值作为上界。然而, 如果用户首先给定的数较大,这种策略将会失败:程序会立即退出 for 循环。因此,我们应该调整范围以便较大的数作上界而较小的数作下界。这样做,我们需要一种方式来判定哪个数更大一些。

像大多数语言一样,C++ 提供支持条件执行的 if 语句。使用 if 语句来编写修订的求和程序如下:

#include <iostream>
int main()
{
	std::cout << "Enter two numbers:" << std::endl;
	int v1, v2;
	std::cin >> v1 >> v2; // read input
	// use smaller number as lower bound for summation
	// and larger number as upper bound
	int lower, upper;
	if (v1 <= v2) {
		lower = v1;
		upper = v2;
	} else {
		lower = v2;
		upper = v1;
	}
	int sum = 0;
	// sum values from lower up to and including upper
	for (int val = lower; val <= upper; ++val)
		sum += val; // sum = sum + val
	std::cout << "Sum of " << lower
				<< " to " << upper
				<< " inclusive is "
				<< sum << std::endl;
	system("pause");
	return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

在这里插入图片描述
这个程序中大部分代码我们在之前的举例中已经熟知了。程序首先向用户输出提示并定义 4 个 int 变量,然后从标准输入读入值到 v1v2 中。仅有 if条件语句是新增加的代码:

// use smaller number as lower bound for summation
// and larger number as upper bound
int lower, upper;
if (v1 <= v2) {
	lower = v1;
	upper = v2;
} else {
	lower = v2;
	upper = v1;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这段代码的效果是恰当地设置 upperlower 。if 的条件测试 v1 是否小于或等于 v2。如果是,则执行条件后面紧接着的语句块。这个语句块包含两条语句,每条语句都完成一次赋值,第一条语句将 v1 赋值给 lower ,而第二条语句将 v2 赋值给 upper。如果这个条件为假(也就是说,如果 v1 大于 v2)那么执行 else 后面的语句。这个语句同样是一个由两个赋值语句组成的块,把 v2 赋值给 lower 而把 v1 赋值给 upper

4)读入未知数目的输入

对求和程序稍作改变,还可以允许用户指定一组数求和。这种情况下,我们不知道要对多少个数求和,而是要一直读数直到程序输入结束。输入结束时,程序将总和写到标准输出:

#include <iostream>
int main()
{
	int sum = 0, value;
	// read till end-of-file, calculating a running total of all values read
	while (std::cin >> value)
		sum += value; // equivalent to sum = sum + value
	std::cout << "Sum is: " << sum << std::endl;
	system("pause");
	return 0;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述
可能会有小伙伴出现不停止的情况,在 while 循环中,cin只有在遇到文件结束符(end-of-file),或遇到一个无效输入时(例如输入的值不是一个整数),cin的状态会变为无效退出循环。

操作系统使用不同的值作为文件结束符。

  • Windows 系统下我们通过键入control—z——同时键入“ctrl”键和“z”键,来输入文件结束符。
  • Unix 系统中,包括 Mac OS—X 机器,通常用 control—d。

与平常一样,程序首先包含必要的头文件。main 中第一行定义了两个 int变量,命名为 sumvalue。在 while 条件中,用 value 保存读入的每一个数:

while (std::cin >> value)

  
  
  • 1

这里所产生的是判断条件,先执行输入操作

std::cin >> value

  
  
  • 1

它具有从标准输入读取下一个数并且将读入的值保存在 value 中的效果。输入操作符返回其左操作数。while 条件测试输入操作符的返回结果,意味着测试 std::cin

当我们使用 istream 对象作为条件,结果是测试流的状态。如果流是有效的(也就是说,如果读入下一个输入是可能的)那么测试成功。遇到文件结束符或遇到无效输入时,如读取了一个不是整数的值,则 istream 对象是无效的。处于无效状态的 istream 对象将导致条件失败。在遇到文件结束符(或一些其他输入错误)之前,测试会成功并且执行 while 循环体。循环体是一条使用复合赋值操作符的语句,这个操作符将它的右操作数加到左操作数上。

一旦测试失败,while 终止并退出循环体,执行 while 之后的语句。该语句在输出 sum 后输出 endlendl 输出换行并刷新与 cout 相关联的缓冲区。最后,执行 return,通常返回零表示程序成功运行完毕。

6、总结

本章介绍了足够多的 C++ 知识,能够编译和执行简单 C++ 程序。看到了如何定义 main 函数,这是任何 C++ 程序首先执行的函数。也看到了如何定义变量,如何进行输入和输出,以及如何编写 if、for 和 while 语句。

参考文章

  • 《C++ Primer》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值