C++ Primer 笔记+习题解答(五)

今天是第五篇的总结,最近两天自我反省,效率着实有提升。

有错误 请指正 谢谢

0.引言:

    第五章主体是表达式和语句,重点则是讲述了几种常见的控制流,已经了解过的估计看起来很轻松,但是这本书中仍然介绍了许多奇技淫巧,直接大家借鉴。

1.简单语句:

  1.特征:

大多数语句以分号结束,其中表达式语句由表达式和一个分号构成,作用是执行表达式并丢弃求值结果。

  如:

int var=2;
var+3;
//一个简单的表达式语句。

  2.空语句:

由单独的分号构成。一般是语法上需要,但是逻辑上不需要。使用的时候最好加上注释。不要因为分号是空语句就随意使用,可能会造成误会。C++一般对缩进是无要求的,当你写下这个语句的时候:

for(auto i:array) ;
   cout<
一旦手贱在range for 语句后面加上了一个分号, 那么for语句的循环体就变成了空语句,而不是底下的输出语句。

  3.复合语句(块语句)

1.相关:

用花括号括起来的语句和声明序列。一般是语法是需要一条,但是逻辑上需要多条的地方。我们把语句块当成一条语句来理解,只不过是不以分号结尾。在我们可以看见的语法格式描述中,可能是如此的:

while(condition)
  statement
这个地方一般都是只写一个statement,因为规定就是只能用一条语句,但是多条语句只能括号出马了。 所以statement也不是复数,因为规定就是用一条语句。

2.语句作用域:

  在语句内部定义的变量包括 语句头定义的变量,一般只在作用域中可见,快外不可见,并且会隐藏域外同名变量。

3.条件语句:

  1.if语句:

一般有两种if语句,带else 和不带else 。if语句根据条件选择执行流程。

语法格式:

if(condition)
  statement
其中的condition 部分可以初始化的声明和表达式,至于语句部分就随意了。

关于if语句的嵌套:

我们平时见到如下的:

if 
else if 
else if
else
---
if{
   if
    else
} else 
如上面这些格式的都算嵌套了

嵌套时遇到的问题:

悬垂else问题,看名字比较难理解,其实很简单,就是一个原则引起的问题,因else 总是会和最近的if语句匹配,这个就会导致一些错误的匹配。解决办法也很简单,善用花括号。有的人推荐多个if语句一定要写上花括号,不然写多了自己就乱了,而且便于修改,如果不加花括号,那么改的时候还要加上。

  2.switch 语句:

我看微软的vs2013称之为开关语句。它是根据括号内的整形表达式计算结果选择执行的语句。看好了是整形表达式,如果你用浮点数,那么一定错了。

一般搭配case关键字和对应的值构成了case label .标签必须是整形常量表达式。不要认为char 不是整形。

任何两个case 标签不能相同,不然肯定有二义性问题产生,另外,default也是一个标签。

执行流程:可以多个标签公用一个执行语句,比如:

switch(ch){
 case 'a':
 case 'b‘:
 case 'c':
   ++cnt;
}
或者别的写法:
switch(ch){
 case 'a': case 'b‘: case 'c':
   ++cnt;
}
一般来说case 标签后跟break 一起用,用于流程跳转。

从上面我们可以看出来,标签后一般后跟语句,注意我们没说语句块,或者标签。如果只有默认标签,记得写上空语句。

switch 内部变量定义:一个很常见的问题,你在一个标签后定义了一个变量,一旦执行跳过这个标签,但是后面的标签却使用了前面中定义的变量,很容易出现问题,所以一般来说,case标签内定义的变量就给它一个单独的作用域,也就是说让它只在自己的case内可见可用。

控制流会绕过一个直接初始化的变量,不管是显式还是隐式的。

现代C++规定,不允许肉啊过变量的初始化语句直接跳转到该变量作用域内的另一个位置。

一开始我理解是有一个误区的,后来仔细斟酌才发现,与大家分享下:

switch(ch){
 case 'a':
   char temp=’ ’;
 case 'b‘:
   ++cnt;
}
一开始我以为temp变量的作用域仅仅局限于case 'a'标签内,但是事实上此变量作用域是整个switch 语句内,也就说一般来说只有花括号是能形参作用域,这个地方理解要注意。

4.迭代语句:

 0.迭代语句:

也称循环语句,循环语句常见的就三种,for循环,while 循环,do while 循环,如果算上C++11的范围for,一共四种。

 1.while 语句:

语法格式:

while(condition)
  statement
其中条件部分可以是表达式或者是初始化的声明,其实无论是什么东西,最后还是要转换成布尔值才能判断。

一般由条件部分或者循环体内改变迭代变量,不然成了死循环。

使用条件: 1.不知道要多少次迭代的时候使用。2.想在循环结束后访问迭代变量。

  2.传统的for语句:

语法格式:

for(init-statement;condition;expression)
  statement
语句头中的初始化部分,可以定义多个对象,但是只能有一条声明语句,也就是说基础类型要一致。如:

for(int i=0,var=1; ;)
for语句的省略:

1.省略初始化部分:无须初始化的时候就可以省略,当然一般是在循环体外定义过了相关迭代变量。但是后面分号不可以省略。

2.省略condition 部分:等价于把条件设置为1,也就是永真,这个时候最后在expression 部分或者循环体内有相应的退出循环措施。

3.省略expression部分:只需要在循环体内或者条件部分修改迭代变量就可以了。比如:

for(int i;cin>>i;)
/**/
我们直在条件里面检测循环变量并且可以修改循环变量,当然这个做法着实是我第一次见到,有点震惊,但是对比下while 又觉得可以接受。

4.range for 语句:

范围for语句其实挺好用的,一般处理的是序列中的全部元素。

语法格式:

for( declaration:expressin)
 statement
expression 一般是一个序列。也就是说可以写个花括号在那里。

declaration 部分一般是声明一个变量用于迭代序列里的元素。一般用auto,省去推断类型。

5.do while 语句:

同while 无大区别,一般就是do while 语句一定会执行一次循环体。

语法格式:

do 
statement
while(conditon);
不建议在condition里面定义变量,应该顺序执行,最后才执行到conditon里。所以可能会发生未定义行为。

5.跳转语句:

   0.四种:

break语句。continue 语句。returned 语句。goto 语句。

  1.break 语句:

适用范围:循环和switch 语句中。结束范围是好最近的循环或者标签内。

功能:结束当前循环或者标签内的执行,控制权移交到循环体或者开关语句外的第一条语句。

  2.continue 语句:

适用范围:循环语句内。结束范围是循环体内。

功能:加速下一次迭代。

区别:在for语句中执行continue 语句,相当于直接跳转到expression 部分执行。但是在while 语句中,却是直接跳转到condition部分,如果condition部分没用修改条件的能力,那么会发生什么呢?当然当你的condition中有修改迭代变量的能力的时候,那就相当于执行for语句的expression部分。

  3.returne 语句:

暂时不表。

   4.goto语句:

暂时不表。

6.异常处理和标准异常:

不详细总结,按照书上的要求,用到的时候在详细介绍。这个地方只要知道有这个特性就可以了。

 异常处理机制:

   1.异常检测,throw出去。

   2.异常处理:try catch住。

  异常类:

用于throw表达式和catch 中传递相关的错误信息。总而言之就是个类。

7.习题解答:

5.1

由单独的分号构成的语句。
用处:一般是逻辑上不需要,但是语法上需要。
5.2

用花括号括起来的语句和声明序列。
可以写一条语句的地方都可以用快。一般来说是语法上需要一条,但是逻辑上需要多天的地方。
5.3

#include 
#include 
using namespace std;
int main(){
	int sum = 0;
	int var = 0;
	while ((++var,var <= 10))//这个地方的顺序还不能颠倒,因为while顺序有求值顺序的。
		sum += var;
	cout << "The sum is " << sum << endl;
	system("pause");
	return 0;
}
其实写成
sum+=var++是最好读的方式。
用法逗号表达式重新可读性下降了。
5.4

a)因为声明的变量没用初始化,所以比较行为不合乎我们的要想
修改:while(string::iterator iter =s.begin()!=s.end())
b)应该是误用==和=号。
修改:while(bool status==find(word))
5.5

#include 
#include 
using namespace std;
int main(){
	string level;
	unsigned grade = 0;
	cout << "Enter grade ";
	cin >> grade;
	if (grade < 60)
		level = "F";
	else if (grade >= 60 && grade <= 69)
		level = "D";
	else if (grade >= 70 && grade <= 79)
		level = "C";
	else if (grade >= 80 && grade <= 89)
		level = "B";
	else if (grade >= 90 && grade <= 99)
		level = "A";
	else if (grade == 100)
		level = "A++";
	else
		cout << "The grade is more than 100,check the grade " << endl;
	cout << "The level is " << level << endl;
	system("pause");
	return 0;
}
这个写法比较常见了,推荐下书上的写法。
#include 
#include 
#include 
using namespace std;
int main(){
    vector svec = { "F", "D", "C", "B", "A", "A++" };
    unsigned grade = 0;
    string level;
    cout << "Enter grade : ";
    cin >> grade;
    if (grade < 60)
        level = svec[0];
    else{
        if (grade == 100)
            level = svec[5];
        else{
            if (grade % 10>7)
                level = svec[(grade - 50) / 10] + "+";
            else if (grade % 10 < 3)
                level = svec[(grade - 50) / 10] + "-";
            else
                level = svec[(grade - 50) / 10];
        }
    }
    cout << "The level is " << level << endl;
    system("pause");
    return 0;
}
//书上这个还实现了A+, A-;而且简洁。
5.6

#include 
#include 
#include 
using namespace std;
int main(){
	vector svec = { "F", "D", "C", "B", "A", "A++" };
	unsigned grade = 0;
	string level;
	cout << "Enter grade : ";
	cin >> grade;
	level = ((grade == 100) ? "A++"
		: ((grade < 100 && grade >= 90) ? "A"
		: ((grade < 90 && grade >= 80) ? "B"
		: (((grade < 80 && grade >= 70) ? "C"
		: ((grade < 70 && grade >= 60) ? "D" : "F"))))));  //你看这个括号写的。。。
	cout << "The level is " << level << endl;
	system("pause");
	return 0;
}
5.7

a) 
if(ival1!=ival2)
  ival1=ival2;
else ival1=ival2=0;
b)
if(ival
5.8

悬垂else就是 else总是会和最近的if匹配,从而可能导致问题产生。
处理措施一般就是用花括号。
5.9

#include 
using namespace std;
int main(){
	char ch;
	int cnt = 0;
	cout << "Enter chars or Enter Ctrl +z to stop ";
	while (cin>>ch){
		if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
			cnt++;
		else
			continue;
	}
	cout << "The occurance of vowel is " << cnt << endl;
	system("pause");
	return 0;
}
5.10

#include 
#include 
#include 
using namespace std;
int main(){
	char ch;
	int acnt = 0;
	int ecnt = 0;
	int icnt = 0;
	int ocnt = 0;
	int ucnt = 0;
	while (cin>>ch){
		ch = tolower(ch);
		switch (ch){
			case 'a':
				++acnt;
				break;
			case 'e':
				++ecnt;
				break;
			case 'i':
				++icnt;
				break;
			case 'o':
				++ocnt;
				break;
			case 'u':
				++ucnt;
				break;
			default:
				break;
		}
	}
	cout << "The result is :\n"
		<< "a or A occur " << acnt << " times\n"
		<< "e or E occur " << ecnt << " times\n"
		<< "i or I occur " << icnt << " times\n"
		<< "o or O occur " << ocnt << " times\n"
		<< "u or U occur " << ocnt << " times\n";
	system("pause");
	return 0;
}


5.11

#include 
#include 
#include 
using namespace std;
int main(){
	unsigned acnt = 0;  //这个地方可以考虑用向量.
	unsigned ecnt = 0;
	unsigned icnt = 0;
	unsigned ocnt = 0;
	unsigned ucnt = 0;
	unsigned space_cnt = 0;  //统计空格。
	unsigned t_cnt = 0;  //统计制表符
	unsigned n_cnt = 0; //统计
	string line = "asASDFA  AEdqwf\t\n       asqeas "; //因为你用cin或者getline输入字符的时候会忽略空格或者换行。
        for (auto &x : line){
		x = tolower(x);
		if(x=='a') ++acnt;
		else if(x=='e') ++ecnt;
		else if(x=='i') ++icnt;
		else if(x=='o') ++ocnt;
		else if(x=='u') ++ucnt;
		else if(!isspace(x)) ++space_cnt;
		else if(x=='\n') ++n_cnt;
		else if (x == '\t') ++t_cnt;
		else continue;
	}
	cout << "The result is :\n"
		<< "a or A occur " << acnt << " times\n"
		<< "e or E occur " << ecnt << " times\n"
		<< "i or I occur " << icnt << " times\n"
		<< "o or O occur " << ocnt << " times\n"
		<< "u or U occur " << ocnt << " times\n"
		<< "space occurs " << space_cnt << "times\n"
		<< "\\t occurs " << t_cnt << " times\n"
		<< "\\n occurs " << n_cnt << " times\n";
	system("pause");
	return 0;
}
5.12

#include 
#include 
#include 
#include 
using namespace std;
int main(){
	unsigned ff_cnt = 0;
	unsigned fl_cnt = 0;
	unsigned fi_cnt = 0;
	string line = "fffqwfiasfl";
	for (decltype(line.size()) i = 0; i != line.size()-1; i++){
		if (line[i] == 'f'){
			if (line[i + 1] == 'f')
				++ff_cnt;
			else if (line[i + 1] == 'l')
				++fl_cnt;
			else if (line[i + 1] == 'i')
				++fi_cnt;
			else
				continue;
		}
		else
			continue;
	}
	cout << "ff occurs " << ff_cnt << " times\n"
		<< "fl occurs " << fl_cnt << "times\n"
		<< "fi occurs " << fi_cnt << "times\n";
	system("pause");
	return 0;
}
这个地方 就不用switch 实现了但是目标还是先判断字符f,然后在此标签内部继续用开关语句或者用if语句分别统计ff等。

5.13

a)
缺少break语句。修改略。
b)
在标签内定义变量,没有加上花括号。
c)
书写格式有错误。
d)
标签后的值必须是整形常量表达式。

5.14

#include 
#include 
#include 
using namespace std;
int main(){
	string word;
	vector svec;
	cout << "Enter word " << endl;
	while (cin >> word){
		svec.push_back(word);
	}
	int max_cnt = 0;
	int cnt = 0;
	for (decltype(svec.size()) i = 0; imax_cnt)
			max_cnt = cnt;
		
	}
	if (max_cnt == 0)
		cout << "No exist " << endl;
	else
		cout << max_cnt +1<< endl;
	system("pause");
	return 0;
}
5.15

a)if语句永远都不会执行。
b)缺少初始化部分,空语句都没写。
c)一个循环,只不过表达式部分是一个逗号表达式,同时地址迭代变量和sz.
5.16

#include 
#include 
#include 
using namespace std;
int main(){
	int sum = 0;
	int var = 1;
	while (var<11){
		sum += var++;
	}
	cout << "The sum is " << sum << endl;
	system("pause");
	return 0;
}
#include 
#include 
#include 
using namespace std;
int main(){
    int sum = 0;
    int var = 1;
    for (var = 1; var < 11; ++var)
        sum += var;
    cout << "The sum is " << sum << endl;
    system("pause");
    return 0;
}
一般不知道明确的循环次数的时候我倾向于使用while循环,明确知道要循环多少次的时候我倾向使用for循环。
5.17

#include 
#include 
#include 
using namespace std;
int main(){
	vector short_ivec = { 0, 1, 1, 2 };
	vector long_ivev = { 0, 1, 1, 2, 3, 5, 8 };
	bool status;
	for (decltype(short_ivec.size())i = 0; i < short_ivec.size(); ++i){
		if (short_ivec[i] != long_ivev[i]){
			status = false;
			break;
		}
		else
			status = true;
	}
	if (status)
		cout << "It is prefix " << endl;
	else
		cout << "Not prefix " << endl;
	system("pause");
	return 0;
}
5.18

a)缺少花括号。
循环输出输入的两个数的和直到cin流无效。
b)
在条件中定义变量。可能无法使用。
c)
可能会出现死循环。含义大致是给ival赋值,然后检测其值是否是0,0就跳出循环,不是0,重复。
5.19

#include 
#include 
#include 
using namespace std;
int main(){
	string str1, str2;
	cout << "Enter two strings " << endl;
	cin >> str1 >> str2;
	do {
		cout << ((str1.size()》
str2.size()) ? str2 : str1)<>str1>>str2);
	system("pause");
	return 0;
}
5.20

#include 
#include 
#include 
using namespace std;
int main(){
	string word, preword;
	cout << "Enter string or Enter x to exit ";
	while (cin >> word){
		if (word == preword){
			cout << word << endl;
			break;
		}
		preword = word;
		if (word == "x"){
			cout << "读取完毕" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
5.21

#include 
#include 
#include 
using namespace std;
int main(){
	string word, preword;
	cout << "Enter string or Enter x to exit ";
	while (cin >> word){
		if (word == preword){
			if (isupper(word[0])){
				cout << word << endl;
				break;
			}
			else
				continue;
		}
		preword = word;
		if (word == "x"){
			cout << "读取完毕" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
5.22

do{
  int sz=get_size();
}while(sz<=0);
5.23

#include 
#include 
#include 
using namespace std;
int main(){
	int var1, var2;
	cin >> var1>>var2;
	if (var2 != 0)
		cout << var1 / var2;
	else
		cout << "被除数为0" << endl;
	system("pause");
	return 0;
}
5.24

#include 
#include 
#include 
using namespace std;
int main(){
	int var1, var2;
	cin >> var1>>var2;
        cout << var1 / var2;
	system("pause");
	return 0;
}
//程序异常终止。
5.25

#include 
#include 
#include 
using namespace std;
int main(){
	int var1, var2;
	try{
		cout << "Enter two numbers ";
		cin >> var1 >> var2;
		if (var2 == 0)
			throw 0;
		cout <<"The result is "<< var1 / var2 << endl;
	}
	catch (int){
		cout << "被除数为0,是否重新输入 yes or no";
		char ch;
		cin>>ch;
		if (ch != 'y'&& ch != 'Y')
			exit(0);
		cout << "重新输入被除数 ";
		cin >> var2;
		cout << "The result is " << var1 / var2 << endl;
	}
	system("pause");
	return 0;
}


后记:

   越发觉得自己水平不够,有些习题做的都有点吃力。加油自勉。

End

你可能感兴趣的:(读书笔记,C++,Primer,读书笔记)