首页 > 代码库 > C++primer第一章 快速入门
C++primer第一章 快速入门
本章介绍 C++ 的大部分基本要素:内置类型、库类型、类类型、变量、表达式、语句和函数。
在这一过程中还会简要说明如何编译和运行程序。
要学会一门新的程序语言,必须实际动手编写程序。在这一章,我们将缩写程序解决一个简单的数据处理问题:某书店以文件形式保存其每一笔交易。每一笔交易记录某本书的销售情况,含有 ISBN(国际标准书号,世界上每种图书的唯一标识符)、销售册数和销售单价。每一笔交易形如:
0-201-70353-X 4 24.99
在编写这个程序之前,必须知道 C++ 的一些基本特征。至少我们要知道怎么样编写、编译和执行简单的程序。这个程序要做什么呢?虽然还没有设计解决方案,但是我们知道程序必须:
- 定义变量。
- 实现输入和输出。
- 定义数据结构来保存要处理的数据。
- 测试是否两条记录具有相同的 ISBN。
- 编写循环。处理交易文件中的每一条记录。
1.1. 编写简单的 C++ 程序
每个 C++ 程序都包含一个或多个函数,而且必须有一个命名为 main。函数由执行函数功能的语句序列组成。操作系统通过调用 main 函数来执行程序,main 函数则执行组成自己的语句并返回一个值给操作系统。
int main(){ return 0;}
定义 main 函数和定义其他函数一样。定义函数必须指定 4 个元素:返回类型、函数名、圆括号内的形参表(可能为空)和函数体。
main 函数的返回值必须是 int 型,该类型表示整数。int 类型是内置类型,即该类型是由 C++ 语言定义的。
函数体函数定义的最后部分,是以花括号开始并以花括号结束的语句块:
{
return 0;
}
在大多数系统中,main 函数的返回值是一个状态指示器。返回值 0 往往表示 main 函数成功执行完毕。任何其他非零的返回值都有操作系统定义的含义。通常非零返回值表明有错误出现。每一种操作系统都有自己的方式告诉用户main 函数返回什么内容。
1.1.1. 编译与执行程序
许多基于 PC 的编译器都在集成开发环境(IDE)中运行,IDE 将编译器与相关的构建和分析工具绑定在一起。
程序源文件命名规范
不管我们使用命令行界面还是 IDE,大多数编译器希望待编译的程序保存在
文件中。程序文件称作源文件。
我们用来编译本书实例的系统将带有后缀 .cc 的文件视为 C++ 程序,因此我们将该程序保存为:
prog1.cc
1.2. 初窥输入/输出
本书的大多数例子都使用了处理格式化输入和输出的 iostream 库。iostream 库的基础是两种命名为 istream 和 ostream 的类型,分别表示输入流和输出流。流是指要从某种 IO 设备上读入或写出的字符序列。术语“流”试图说明字符是随着时间顺序生成或消耗的。
1.2.1. 标准输入与输出对象
标准库定义了 4 个 IO 对象。处理输入时使用命名为 cin(读作 see-in)的 istream 类型对象。这个对象也称为标准输入。处理输出时使用命名为 cout(读作 see-out)的 ostream 类型对象,这个对象也称为标准输出。标准库还定义了另外两个 ostream 对象,分别命名为 cerr 和 clog(分别读作“see-err”和“see-log”)。cerr 对象又叫作标准错误,通常用来输出警告和错误信息给程序的使用者。而 clog 对象用于产生程序执行的一般信息。
1.2.2. 一个使用IO 库的程序
到目前为止,我们已经明白如何编译与执行简单的程序,虽然那个程序什么也不做。在开篇的书店问题中,有一些记录含有相同的 ISBN,需要将这些记录进行汇总,也就是说需要弄清楚如何累加已售出书籍的数量。
1 #include <iostream> 2 int main() 3 { 4 std::cout << "Enter two numbers:" << std::endl; 5 int v1, v2; 6 std::cin >> v1 >> v2; 7 std::cout << "The sum of " << v1 << " and " << v2 8 << " is " << v1 + v2 << std::endl; 9 return 0;10 }
程序的第一行是一个预处理指示:
#include <iostream>
告诉编译器要使用 iostream 库。尖括号里的名字是一个。头文件。程序使用库工具时必须包含相关的头文件。
写入到流
main 函数体中第一条语句执行了一个表达式。C++ 中,一个表达式由一个或几个操作数和通常是一个操作符组成。该语句的表达式使用输出操作符(<< 操作符),在标准输出上输出提示语:
std::cout << "Enter two numbers:" << std::endl;
这个语句用了两次输出操作符。每个输出操作符实例都接受两个操作数:左操作数必须是 ostream 对象;右操作数是要输出的值。
endl 是一个特殊值,称为操纵符,将它写入输出流时,具有输出换行的效果,并刷新与设备相关联的缓冲区。通过刷新缓冲区,用户可立即看到写入到流中的输出。
使用标准库中的名字
这个程序中使用的是 std::cout 和 std::endl,而不是 cout 和 endl。前缀 std:: 表明 cout 和 endl 是定义在命名空间 std 中的。使用命名空间程序员可以避免与库中定义的名字相同而引起无意冲突。
std::cout 的写法使用了作用域操作符(scope operator,:: 操作符),表示使用的是定义在命名空间 std 中的cout。
读入流
在输出提示语后,将读入用户输入的数据。先定义两个名为 v1 和 v2 的变量来保存输入:
int v1, v2;
将这些变量定义为 int 类型,int 类型是一种代表整数值的内置类型。
下一条语句读取输入:
std::cin >> v1 >> v2;
输入操作符(>> 操作符)行为与输出操作符相似。它接受一个 istream 对象作为其左操作数,接受一个对象作为其右操作数,它从 istream 操作数读取数据并保存到右操作数中。像输出操作符一样,输入操作符返回其左操作数作为结果。
完成程序
剩下的就是要输出结果:
std::cout << "The sum of " << v1 << " and " << v2<< " is " << v1 + v2 << std::endl;
这条语句虽然比输出提示语的语句长,但概念上没什么区别。它将每个操作数输出到标准输出。有趣的是操作数并不都是同一类型的值,有些操作数是字符串字面值。
1.3. 关于注释
在程序变得更复杂之前,我们应该明白C++如何处理注释。注释可以帮助其他人阅读程序,通常用于概括算法、确认变量的用途或者阐明难以理解的代码段。注释并不会增加可执行程序的大小,编译器会忽略所有注释。
C++ 中有单行注释和成对注释两种类型的注释。单行注释以双斜线(//)开头,行中处于双斜线右边的内容是注释,被编译器忽略。
另一种定界符,注释对(/* */),是从 C 语言继承过来的。这种注释以“/*”开头,以“*/”结尾。编译器把落入注释对“/**/”之间的内容作为注释:
1 #include <iostream> 2 /* Simple main function: Read two numbers and write their sum */ 3 int main() 4 { 5 // prompt user to enter two numbers 6 std::cout << "Enter two numbers:" << std::endl; 7 int v1, v2; // uninitialized 8 std::cin >> v1 >> v2; // read input 9 return 0;10 }
注释对不可嵌套
注释总是以 /* 开始并以 */ 结束。这意味着,一个注释对不能出现在另一个注释对中。
1 #include <iostream> 2 /* 3 * comment pairs /* */ cannot nest. 4 * "cannot nest" is considered source code, 5 * as is the rest of the program 6 */ 7 int main() 8 { 9 return 0;10 }
1.4. 控制结构 语句总是顺序执行的:函数的第一条语句首先执行,接着是第二条,依次类推。当然,少数程序——包括我们将要编写的解决书店问题的程序——可以仅用顺序执行语句编写。事实上,程序设计语言提供了多种控制结构支持更为复杂的执行路径。本节将简要地介绍 C++ 提供的控制结构,第六章再详细介绍各种语句。
1.4.1. while 语句
1 #include <iostream> 2 int main() 3 { 4 int sum = 0, val = 1; 5 // keep executing the while until val is greater than 10 6 while (val <= 10) { 7 sum += val; // assigns sum + val to sum 8 ++val; // add 1 to val 9 }10 std::cout << "Sum of 1 to 10 inclusive is "11 << sum << std::endl;
return 0;
}
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 语句的条件用了小于或等于操作符(<= 操作符),将 val 的当前值和 10 比较,只要 val 小于或等于 10,就执行 while 循环体。
块是被花括号括起来的语句序列。C++ 中,块可用于任何可以用一条语句的地方。块中第一条语句使用了复合赋值操作符(+= 操作符),这个操作符把它的右操作数加至左操作数,这等效于编写含一个加法和一个赋值的语句:
sum = sum + val; // assign sum + val to sum
使用了前自增操作符(++ 操作符),自增操作符就是在它的操作数上加 1,++val 和 val = val + 1 是一样的。
1.4.2. for 语句
#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; return 0;}
包含 for 语句头和 for 语句体两部分。for 语句头控制 for 语句体的执行次数。
for 语句头由三部分组成:一个初始化语句,一个条件,一个表达式。
扼要重述一下,for 循环总的执行流程为:
- 创建 val 并初始化为 1。
- 测试 val 是否小于或等于 10。
- 如果 val 小于或等于 10,则执行 for 循环体,把 val 加到 sum 中。如果 val 大于 10,就退出循环,接着执行 for 语句体后的第一条语句。
- val 递增。
- 重复第 2 步的测试,只要条件为真,就继续执行其余步骤。
1.4.3. if 语句
求 1 到 10 之间数的和,其逻辑延伸是求用户提供的两个数之间的数的和。可以直接在 for 循环中使用这两个数,使用第一个输入值作为下界而第二个输入值作为上界。然而, 如果用户首先给定的数较大,这种策略将会失败:程序会立即退出 for 循环。因此,我们应该调整范围以便较大的数作上界而较小的数作下界。这样做,我们需要一种方式来判定哪个数更大一些。
#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 fromlower 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; return 0;}
1.4.4. 读入未知数目的输入
#include <iostream>int main(){ int sum = 0, value; // read till end-of-file, calculating a running total of allvalues read while (std::cin >> value) sum += value; // equivalent to sum = sum + value std::cout << "Sum is: " << sum << std::endl; return 0;}
当我们使用 istream 对象作为条件,结果是测试流的状态。如果流是有效的(也就是说,如果读入下一个输入是可能的)那么测试成功。遇到文件结束符或遇到无效输入时,如读取了一个不是整数的值,则 istream 对象是无效的。处于无效状态的 istream 对象将导致条件失败。
1.5. 类的简介
解决书店问题之前,还需要弄明白如何编写数据结构来表示交易数据。C++中我们通过定义类来定义自己的数据结构。类机制是 C++ 中最重要的特征之一。事实上,C++ 设计的主要焦点就是使所定义的类类型的行为可以像内置类型一样自然。我们前面已看到的像 istream 和 ostream 这样的库类型,都是定义为类的,也就是说,它们严格说来不是语言的一部分。
使用类时我们需要回答三个问题:
1. 类的名字是什么?
2. 它在哪里定义?
3. 它支持什么操作?
1.5.1. Sales_item 类
依据惯例,类类型存储在一个文件中,其文件名如同程序的源文件名一样,由文件名和文件后缀两部分组成。通常文件名和定义在头文件中的类名是一样的。通常后缀是 .h,但也有一些程序员用 .H、.hpp 或 .hxx。
Sales_item 对象上的操作
像使用内置类型一样,可以定义类类型的变量。当写下
Sales_item item;
除了可以定义 Sales_item 类型的变量,我们还可以执行 Sales_item 对象的以下操作:
• 使用加法操作符,+,将两个 Sales_item 相加。
• 使用输入操作符,<<,来读取一个 Sales_item 对象。
• 使用输出操作符,>>,来输出一个 Sales_item 对象。
• 使用赋值操作符,=,将一个 Sales_item 对象赋值给另一个 Sales_item对象。
• 调用 same_isbn 函数确定两个 Sales_item 是否指同一本书。
1.6. C++ 程序
C++primer第一章 快速入门