《C++primer》第五版学习笔记——第一章知识点及习题

    科技2022-09-02  101

    附:此笔记是为了记录自己学习《C++ primer》中文版第五版的学习过程,同时督促自己,“希望有一天,自己从来不缺从头再来的勇气”,在此之前看的C++的书都很杂乱,所以想系统性地再认真学一遍,打好基础。

    书中使用最多的编译器是GNU编译器4.7.0,本人使用的Dev-C++ 5.11,并对书中的练习进行了相应解答,仅供参考,有错误的地方,欢迎联系我指正,十分感谢。

    第一章 开始

    0 示例

    编写一个程序来解决简单的书店问题。

    要求:书店保存所有销售记录的档案,每条记录保存某本书的一次销售的信息(一册或多册)。每条记录包含三个数据项。

    0-201-70353-X 4 24.99

    第一项是书的ISBN号。第二项是售出的册数,第三项是书的单价。

    有时书店老板需要查询此档案,计算每本书的销售量、销售额及评价售价。

    思考该程序包含哪些子问题?

    定义变量

    进行输入和输出

    使用数据结构保存数据

    检测两条记录是否有相同的ISBN

    包含一个循环来处理销售档案中的每条记录

    1.1 输入输出

    #include <iostream>

    iostream库中包含两个基础类型istream和ostream,分别表示输入和输出。一个流就是一个字符序列,是从IO设备读出或写入IO设备的。

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

    cin 标准输入,istream类型的对象。使用输入运算符>>,该运算符返回其左侧的运算对象,左侧的运算对象必须是一个istream对象。

    cout 标准输出,ostream类型的对象。使用输出运算符<<,该运算符返回其左侧的运算对象,左侧的运算对象必须是一个ostream对象。

    std::cout<<"Enter two numbers:"<<std::endl;,有两个<<运算符,每个运算符的左侧运算对象都是相同的,即都是std::cout,因此可以写成一行,也可以用两条语句来生成相同的输出:

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

    第一个输出运算符给用户打印一条信息,是一个字符串字面值常量,是用一对双引号包围的字符序列。在双引号之间的文本被打印到标准输出。

    第二个运算符打印endl,是一个操纵符的特殊值,作用是结束当前行,并将于设备关联的缓冲区中的内容刷到设备中。

    注意 使用标准库中的名字std:: cout和 std::endl,而不是直接的cout和endl。

    前缀std::指出名字cout和endl是定义在名为std的命名空间(namespace)中的。命名空间可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在命名空间std中。

    通过命名空间使用标准库有一个副作用:当使用标准库中的一个名字时,必须显式说明我们想使用来自命名空间std中的名字。例如,需要写出std:: cout,通过使用作用域运算符(::)来指出我们想使用定义在命名空间std中的名字cout。

    如果在程序首部声明命名空间using namespace std;,则在输入、输出就不需要作用运算符进行前缀,直接写cin,cout即可。

    练习1.3

    编写程序,在标准输出上打印 Hello, World。

    #include <iostream> int main( ) { std::cout << "Hello, World" << std::endl; return 0; }

    练习1.4

    我们的程序使用加法运算符+来将两个数相加。编写程序使用乘法运算符*,来打印两个数的积。

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

    练习1.5

    我们将所有输出操作放在一条很长的语句中。重写程序,将每个运算对象的打印操作放在一条独立的语句中。

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

    练习1.6

    解释下面程序片段是否合法。如果程序是合法的,它的输出是什么?如果程序不合法,原因何在?应该如何修正?

    std::cout << "The sum of " << v1; << " and " << v2; << " is " << v1 + v2 << std::endl;

    不合法,第一、二行不需要分号,删除多余的“;”,修改如下:

    std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl;

    1.2 注释简介

    单行注释 //

    界定符对注释 : 以 /*开始, */结束,不能嵌套。当注释界定符跨越多行时,最好能显式指出其内部的程序行都属于多行注释的一部分,可以一个星号开头。

    练习1.7

    编译一个包含不正确的嵌套注释的程序,观察编译器返回的错误信息。

    界定符对注释是配对出现的,后面再出现的就相当于程序了。

    练习1.8

    指出下列哪些输出语句是合法的(如果有的话):预测编译这些语句会产生什么样的结果,实际编译这些语句来验证你的答案(编写一个小程序,每次将上述一条语句作为其主体),改正每个编译错误。

    std::cout << "/*"; std::cout << "*/"; std::cout << /* "*/" */; std::cout << /* "*/" /* "/*" */;

    第三行编译出错,改正方法是增加一个引号。输出: /**/ */ /*

    1.3 控制流

    1.3.1 while 语句

    用while语句编写程序,实现1到10这10个数之和。

    #include <iostream> int main( ){ int sum = 0,val = 1; //只要val的值小于等于10,while循环就会持续执行 while (val <= 10){ sum+= val; //将sum + val赋予sum ++val; //将val 加1 } std::cout <<"sum of i to 10 inclusive is" << sum <<std::endl; return 0; }

    输出结果sum of i to 10 inclusive is 55

    while (val <= 10){ sum+= val; //将sum + val赋予sum ++val; //将val 加1 }

    循环体由两条语句组成的语句块:

    while(condition) { statement; }

    while语句的执行过程是交替地检测condition条件,和执行关联的语句statement,直至condition为假时停止。

    练习1.9

    编写程序,使用while循环将50到100的整数相加。

    #include <iostream> using namespace std; void main( ) { int i=50; int sum = 0; while (i >= 50 && i <= 100) { sum = sum+i; i++; } cout<<sum<<endl; }

    练习1.10

    除了++运算符将运算对象的值增加1之外,还有一个递减运算符(–)实现将值减少1。编写程序,使用递减运算符在循环中按递减顺序打印出10到0之间的整数。

    #include <iostream> using namespace std; void main() { int i=10; while (i >= 0 && i <= 10) { cout<<i<<endl; i--; } }

    练习1.11

    编写程序,提示用户输入两个整数,打印出这两个整数所指定的范围内的所有整数。

    #include <iostream> using namespace std; int main( ) { int a,b; std::cout<<"输入两个整数"<<std::endl; std::cin>>a>>b; if(a>b) { int temp; temp=a; a=b; b=temp; } while(a<=b) { cout<<a<<endl; a++; } return 0; }

    1.3.2 for语句

    用for语句编写程序,实现1到10这10个数之和。

    #include <iostream> int main( ){ int sum = 0; //从1加到10 for (int val=1;val<=10;val++){ sum+= val; //等价于sum= sum+val } std::cout <<"sum of i to 10 inclusive is" << sum <<std::endl; return 0; }

    简要重述一下for 循环的总体执行流程:

    创建变量val,将其初始化为1。检测val是否小于等于10。若检测成功,执行for循环体。若失败,退出循环,继续执行for循环体之后的第一条语句。将val的值增加1。重复第2步中的条件检测,只要条件为真就继续执行剩余步骤。

    练习1.12

    下面的for循环完成了什么功能?sum的终值是多少?

    int sum = 0; for (int i = -100; i <= 100; ++i) sum += i;

    从 -100 加到 100 ,sum 的终值为 0。

    练习1.13

    #include <iostream> using namespace std; int main( ) { int a,b; std::cout<<"输入两个整数"<<std::endl; std::cin>>a>>b; if(a>b) { int temp; temp=a; a=b; b=temp; } for(int i=a;i<=b;i++) { cout<<i<<endl; } return 0; }

    练习1.14

    对比for循环和while循环,两种形式的优缺点各是什么?

    在for循环中,循环控制变量的初始化和修改都放在语句头部分,形式较简洁,且特别适用于循环次数已知的情况。在while循环中,循环控制变量的初始化一般放在while语句之前,循环控制变量的修改一般放在循环体中,形式上不如for语句简洁,但它比较适用于循环次数不易预知的情况(用某一条件控制循环)。两种形式各有优点,但它们在功能上是等价的,可以相互转换。

    1.3.3 if语句

    if语句统计在输入中每个值连续出现了多少次。

    #include <iostream> int main( ) { // currVal是我们正在统计的数;我们将读入的新值存入val int currval = 0,val =0; //读取第一个数,并确保确实有数据可以处理 if (std::cin>>currval) { int cnt=1; //保存我们正在处理的当前值的个数 while (std::cin >> val) { // 读取刺余的数 if (val == currval) ++cnt; // 如果值相同,将cnt加1 else { //否则,打印前一个值的个数 std::cout << currval <<"occurs " << cnt <<"times" << std::endl; currval=val; //记住新值 cnt = 1; //重置计数器 } } // while循环在这里结束 //记住打印文件中最后一个值的个数 std::cout << currval << "occurs" << cnt<< "times" << std::endl; } //最外层的if语句在这里结束 return 0; }

    输出与书本结果不一致。????

    1.4 类简介

    在后面的章节有详细讲解,这个部分是直接用了类的特性,不关心它是如何实现的,只需知道类对象可以执行什么操作即可。采用.h作为头文件的后缀

    1.5 书店程序

    #include <iostream> #include "sales_item.h" int main() { sales_ item total; //保存下一条交易记录的变量 //读入第一条交易记录,并确保有数据可以处理 if (std::cin >> total) { sales_ item trans; //保存和的变量 //读入并处理剩余交易记录 while (std::cin >> trans) { //如果我们仍在处理相同的书 if (total.isbn()== trans. isbn()) total += trans; // 更新总销售额 else { //打印前一本书的结果 std::cout << total << std::endl; total = trans; //total现在表示下一本书的销售额 } } std::cout << total << std::endl; // 打印最后一本书的结果 } else { //没有输入!警告读者 std: :cerr << "No data?!" << std: :endl ; . return -1; //表示夫败 } return 0; }

    练习1.20

    在网站http://www.informit.com/title/032174113 上,第1章的代码目录包含了头文件 Sales_item.h。将它拷贝到你自己的工作目录中。用它编写一个程序,读取一组书籍销售记录,将每条记录打印到标准输出上。

    #include <iostream> #include "Sales_item.h" using namespace std; int main() { Sales_item item; cin >> item; cout << item << endl; return 0; }

    练习1.21

    读取两个ISBN相同的Sales_item 对象,输出它们的和。

    #include <iostream> #include "Sales_item. h" int main( ) { Sales_ item iteml, item2; std::cin >> iteml >> item2; //读取一对交易记录 //首先检查item1和item2是否表示相同的书 if (iteml.isbn() == item2.isbn()) { std: :cout << iteml + item2 << std: :endl; // 打印它们的和 return 0; //表示成功 } else{ std::cerr << "Data must refer to same ISBN" //cerr通常用来输出警告和错误消息,也称为标准错误 << std::endl; return -1; //表示失败 }

    练习1.22

    编写程序,读取多个具有相同 ISBN 的销售记录,输出所有记录的和。

    #include <iostream> #include "Sales_item.h" int main() { Sales_item total; if (std::cin >> total) { Sales_item trans; while (std::cin >> trans) { if (total.isbn() == trans.isbn()) total += trans; else { std::cout << total << std::endl; total = trans; } } std::cout << total << std::endl; } else { std::cerr << "No data?!" << std::endl; return -1; } return 0; }

    练习1.23

    编写程序,读取多条销售记录,并统计每个 ISBN(每本书)有几条销售记录。

    #include <iostream> #include "Sales_item.h" int main() { Sales_item currItem, valItem; if (std::cin >> currItem) { int cnt = 1; while (std::cin >> valItem) { if (valItem.isbn() == currItem.isbn()) { ++cnt; } else { std::cout << currItem << " occurs " << cnt << " times " << std::endl; currItem = valItem; cnt = 1; } } std::cout << currItem << " occurs " << cnt << " times " << std::endl; } return 0; }
    Processed: 0.016, SQL: 9