C++ Primer 5th 第5章 语句
和大多数语言一样,C++提供了条件执行语句、重复执行相同代码的循环语句和由于中断当前控制流的跳转语句,表达式语句和声明语句等。
语句有简单语句和复合语句之分。简单语句但多数以分号结束,最简单的语句就是空语句,空语句中就只含有一个单独的分号。
复合语句是用花括号括起来的语句或声明,复合语句也叫块。复合语句不同于简单语句的是,复合语句具有作用域,即块作用域,块中引入的名字只能被当前块或者当前块的字块访问。复合语句是不用分号结尾的。
可以在if、switch、while、for语句的控制结构内定义变量,这个变量只能在当前语句内访问,语句结束,变量就消亡了。
if语句的语法形式是
if (condition)
statement
对于if的condition,必须使用括号括起来,condition可以是一个表达式,也可以是一个初始化了的变量声明,并且不允许为空。
switch语句的语法形式是
switch(expression)
{
case value:
}
对于switch语句,首先对expression表达式求值,expression也可以是一个初始化了的变量声明。表达式的值转换成整形。然后与每个case标签比较。
case标签的值必须是个常量表达式,且是整型类型的。
如果没有任何一个case标签能匹配switch表达式的值,在switch语句有default表达式的情况下,将默认执行该default表达式,default表达式的位置无关紧要。
while语句的语法形式是
while (condition)
statement
condition是不允许为空的,可以是个表达式,也可以是一个初始化了的变量声明。
while循环不同于for循环的一点是,while条件部分或者while循环体内定义的变量每次迭代后都会被销毁。
范围for语句的语法形式是
for (declaration : expression)
statement
expression必须是一个序列,比如花括号括起来的初始值列表{1,2,3,4,5},或者数组、vector、string等类型的对象,这些对象的特点是可以使用begin和end成员或者函数来获取其相应的迭代器。
do while语句中while的条件部分使用的变量必须是循环前定义的。
break语句用于终止循环,break语句只能出现在迭代语句或者switch语句的内部,嵌套在循环语句的子语句也是可以的。
continue语句用于停止当前迭代的执行,重新开始下一次的迭代,但是不能终止循环,continue语句只能出现在for、while、do while循环的内部,或者循环内部的子块。
goto语句较难把控,不建议使用
try语句块和异常处理:
当程序的某部分检测到一个它无法处理的问题时,需要使用异常处理,异常分为两块,一块是异常的检测,一块是异常的处理。
检测部分是发出某种信号,表明遇到故障。发出是由throw完成的,称作throw引发了异常。某种信号则是异常的类型。
异常的处理是try和catch负责的。
throw表达式引发一个异常,表达式包含关键字和一个表达式,表达式的类型就是异常的类型,用于发出某种信号。
try语句块是一个关键字加上紧随的复合语句块,必须是复合语句块,不能是一个简单语句。
try语句之后是一个或多个catch子句。catch子句包含一个关键字catch,一个括号括起来的对象声明,一个语句块。当选中某个catch子句处理完毕后,程序就跳到所有catch子句之后的地方继续执行。如果没有catch子句,程序一般会非正常退出。
另外,try语句块具有块作用域,出了该块,不能在外部访问块内引入的变量。
练习5.1:什么是空语句?什么时候会用到空语句?
空语句就是只含有一个单独分号的语句。当语法上需要一条语句,逻辑上不需要时,就需要使用空语句
练习5.2:什么是块?什么时候会用到块?
块就是用花括号括起来的语句或者声明序列,当语法上需要一条语句,但是逻辑上需要多条语句,此时就要使用块。
练习5.3:使用逗号运算符(参见4.10节,第104页)重写1.4.1节(第10页)的 while 循环,使它不再需要块,观察改写之后的代码的可读性提高了还是降低了。
#include <iostream> using namespace std; int main()
{
int i = , sum = ;
while (i <= )
sum += i, ++i; return ;
}
改写后的可读性降低。
练习5.4:说明下列例子的含义,如果存在问题,试着修改它。
(a) while (string::iterator iter != s.end())
{
/* . . . */
} (b) while (bool status = find(word))
{
/* . . . */
}
if (!status)
{
/* . . . */
}
(a) 用循环遍历string s,语法错误,while头部只能是一个表达式或者初始化了的变量声明。应该将iter放在while外面定义。
(b) while头部定义的变量只在当前循环内可见,if无法访问,应该将status的定义放在最外面。
练习5.5:写一段自己的程序,使用if else 语句实现把数字成绩转换为字母成绩的要求。
#include <iostream>
#include <vector> using namespace std; int main()
{
const vector<string> scores = {"F", "D", "C", "B", "A", "A++"};
string lettergrade;
int grade;
while (cin >> grade)
{
if (grade < )
lettergrade = scores[];
else
lettergrade = scores[(grade - ) / ];
cout << lettergrade << '\n';
}
return ;
}
练习5.6:改写上一题的程序,使用条件运算符(参见4.7节,第134页)代替if else语句。
#include <iostream>
#include <vector> using namespace std; int main()
{
const vector<string> scores = {"F", "D", "C", "B", "A", "A++"};
string lettergrade;
int grade;
while (cin >> grade)
{
(grade < ) ? ( lettergrade = scores[]) : (lettergrade = scores[(grade - ) / ]);
cout << lettergrade << '\n';
}
return ;
}
练习5.7:改写下列代码段中的错误。
(a) if (ival1 != ival2)
ival1 = ival2
else
ival1 = ival2 = ; (b) if (ival < minval)
minval = ival;
occurs = ; (c) if (int ival = get_value())
cout << "ival = " << ival << endl;
if (!ival)
cout << "ival = 0\n"; (d) if (ival = )
ival = get_value();
(a) ival1 = ival2 后面缺少分号。
(b) 应该用花括号括起来。
(c) if (!ival) 应该改为else。
(d) if (ival = 0) 应该改为 if (ival == 0)。
练习5.8:什么是“悬垂else”?C++语言是如何处理else子句的?
悬垂else就是一个if语句嵌套在另一个if语句内部,使得if分支多于else分支。C++规定else与离它最近的尚未匹配的if匹配。
练习5.9:编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母。
#include <iostream> using namespace std; int main()
{
char c;
size_t num = ;
while (cin >> c)
{
if (c == 'a')
++num;
if (c == 'e')
++num;
if (c == 'i')
++num;
if (c == 'o')
++num;
if (c == 'u')
++num;
}
cout << num << endl;
return ;
}
练习5.10:我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,既统计元音字母的小写形式,也统计元音字母的大写形式,也就是说,新程序遇到'a'和'A'都应该递增 aCnt 的值,以此类推。
#include <iostream> using namespace std; int main()
{
char c;
size_t num = ;
while (cin >> c)
{
if (c == 'a' || c == 'A')
++num;
if (c == 'e' || c == 'E')
++num;
if (c == 'i' || c == 'I')
++num;
if (c == 'o' || c == 'O')
++num;
if (c == 'u' || c == 'U')
++num;
}
cout << num << endl;
return ;
}
练习5.11:修改统计元音字母的程序,使其也能统计空格、制表符、和换行符的数量。
#include <iostream> using namespace std; int main()
{
size_t num;
char ch;
while (cin >> ch)
{
switch (ch)
{
case 'a': case 'A': case 'e': case 'E': case 'i': case 'I': case 'o':
case 'O': case 'u': case 'U': case ' ': case '\t': case '\n':
++num;
}
}
return ;
}
练习5.12:修改统计元音字母的程序,使其能统计含以下两个字符的字符序列的数量: ff、fl和fi。
#include <iostream> using namespace std; int main()
{
size_t num;
string s;
while (cin >> s)
{
if (s == "ff" || s == "fl" || s == "fi")
{
++num;
}
}
return ;
}
练习5.13:下面显示的每个程序都含有一个常见的编码错误,指出错误在哪里,然后修改它们。
(a) unsigned aCnt = , eCnt = , iouCnt = ;
char ch = next_text();
switch (ch)
{
case 'a': aCnt++;
case 'e': eCnt++;
default: iouCnt++;
} (b) unsigned index = some_value();
switch (index)
{
case :
int ix = get_value();
ivec[ ix ] = index;
break;
default:
ix = ivec.size() - ;
ivec[ ix ] = index;
} (c) unsigned evenCnt = , oddCnt = ;
int digit = get_num() % ;
switch (digit)
{
case , , , , :
oddcnt++;
break;
case , , , , :
evencnt++;
break;
} (d) unsigned ival = , jval = , kval = ;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch (swt)
{
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
(a) 每个case缺少break语句。
case 'a': aCnt++;
break;
case 'e': eCnt++;
break;
default: iouCnt++;
break;
(b) default标签中的ix 未定义。修改为
int ix;
unsigned index = some_value();
switch (index)
{
case 1:
ix = get_value();
ivec[ ix ] = index;
break;
default:
ix = ivec.size() - 1;
ivec[ ix ] = index;
}
(c) case标签错误,变量名错误。修改为
unsigned evenCnt = 0, oddCnt = 0;
int digit = get_num() % 10;
switch (digit)
{
case 1:case 3:case 5:case 7:case 9:
oddcnt++;
break;
case 2:case 4:case 6:case 8:case 10:
evencnt++;
break;
}
(d) case 标签必须是整型常量表达式。修改为
constexpr unsigned ival = 512, jval = 1024, kval = 4096;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch (swt)
{
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
练习5.14:编写一段程序,从标准输入中读取若干string对象并查找连续重复出现的单词。所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身。要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。例如:如果输入是:
how now now now brown cow cow
那么输出应该表明单词now连续出现了3次。
#include <iostream> using namespace std; int main()
{
string s1, s2;
if (cin >> s1)
{
int cnt = ;
while (cin >> s2)
{
if (s1 == s2)
++cnt;
else
{
cout << s1 << "occurs " << cnt << " times" << endl;
s1 = s2;
cnt = ;
}
}
cout << s1 << "occurs " << cnt << " times" << endl;
} return ;
}
练习5.15:说明下列循环的含义并改正其中的错误。
(a) for (int ix = ; ix != sz; ++ix) { /* ... */ }
if (ix != sz)
// . . .
(b) int ix;
for (ix != sz; ++ix) { /* ... */ }
(c) for (int ix = ; ix != sz; ++ix, ++sz) { /*...*/ }
(a) if不可以访问for的局部变量ix,应该将ix放在for的前面定义
(b) for的语法格式错误,应改为for( ; ix != sz; ++ix)
(c) 死循环,ix != sz 恒成立,不应该使用 ++ix,++sz
练习5.16:while 循环特别适用于那种条件不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for 循环更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于哪种?为什么?
#include <iostream> using namespace std; int main()
{
int i = , sum = ;
while (i <= )
{
sum += i;
++i;
} for (int i = ; i != ; ++i)
{
sum += i;
}
return ;
}
如果只能使用一种,我倾向于for循环,因为for循环头部提供更多的选项,可以更多的控制循环,相对while循环来说更强大易用。
练习5.17:假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的vector对象,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,如果两个vector对象的元素分别是0、1、1、2 和 0、1、1、2、3、5、8,则程序的返回结果为真。
#include <iostream>
#include <vector> using namespace std; int main()
{
vector<int> v1{, , , }, v2{, , , , , , };
if (v1.size() < v2.size())
{
for (size_t i = ; i != v1.size(); ++i)
{
if (v1[i] != v2[i])
cout << "not equal\n";
}
}
else
{
for (size_t i = ; i != v2.size(); ++i)
{
if (v1[i] != v2[i])
cout << "not equal\n";
}
}
return ;
}
练习5.18:说明下列循环的含义并改正其中的错误。
(a) do
int v1, v2;
cout << "Please enter two numbers to sum:" ;
if (cin >> v1 >> v2)
cout << "Sum is: " << v1 + v2 << endl;
while (cin); (b) do {
// . . .
} while (ival = get_response());
(c) do {
ival = get_response();
} while (ival);
(a) 语法错误,do后面,while前面的语句应该用花括号括起来
(b) 语法错误,do while条件使用的表达式规定必须是在循环前定义!
(c) 语法错误,do while条件使用的表达式规定必须是在循环前定义!
练习5.19:编写一段程序,使用do while 循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。
#include <iostream> using namespace std; int main()
{
string s1, s2;
char c;
do
{
cout << "input two strings:";
cin >> s1 >> s2;
if (s1.size() > s2.size())
cout << s1 << endl;
else
cout << s2 << '\n' << "More ? Enter 'y' or 'n' " << endl;
cin >> c;
}
while (c != 'n');
return ;
}
练习5.20:编写一段程序,从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续重复出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。
#include <iostream> using namespace std; int main()
{
string s1, s2;
if (cin >> s1)
{
while (cin >> s2)
{
if (s1 == s2)
{
cout << s2;
break;
}
else
{
s1 = s2;
}
}
} return ;
}
练习5.21:修改5.5.1节练习题的程序,使其找到的重复单词必须以大写字母开头。
#include <iostream> using namespace std; int main()
{
string s1, s2;
if (cin >> s1)
{
while (cin >> s2)
{
if (s1 == s2 && isupper(s2[]))
{
cout << s2 << endl;
break;
}
else
{
s1 = s2;
}
}
} return ;
}
练习5.22本节的最后一个例子跳回到 begin,其实使用循环能更好的完成该任务,重写这段代码,注意不再使用goto语句。
#include <iostream> using namespace std; int main()
{
int sz = get_size();
while (sz <= )
sz = get_size();
return ;
}
练习5.23:编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。
#include <iostream> using namespace std; int main()
{
int i1, i2;
cin >> i1 >> i2;
if (i2 == )
throw "ERROR! Division by zero!"; cout << i1 / i2 << endl;
return ;
}
练习5.24:修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch子句,运行程序并真的为除数输入0,看看会发生什么?
程序终止。
练习5.25:修改上一题的程序,使用try语句块去捕获异常。catch子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行try语句块的内容。
#include <iostream> using namespace std; int main()
{
int i1, i2;
while (cin >> i1 >> i2)
{ try
{
if (i2 == )
throw string("ERROR! Division by zero!");
}
catch (string s)
{
cout << s << endl;
cout << "Try again? 'Y' or 'N'";
char c;
cin >> c;
if (!cin || c == 'n')
break;
else
continue;
}
cout << i1 / i2 << endl;
}
return ;
}
C++ Primer 5th 第5章 语句的更多相关文章
- C++ Primer 5th 第1章 开始
*****代码在Ubuntu g++ 5.31 / clang++ 3.8(C++11)下编写调试***** 每个C++程序必须有一个main( )函数,main( )函数的返回值也必须是int类型, ...
- C++ Primer 5th 第15章 面向对象程序设计
面向对象程序设计的核心思想是:数据抽象.继承和动态绑定. 数据抽象:将类的接口与实现分离: 继承:定义相似类型并对相似关系建模: 动态绑定:一定程度上上忽略相似类型间的区别,用同一方式使用它们. 1. ...
- C++ Primer 5th 第12章 动态内存
练习12.1:在此代码的结尾,b1 和 b2 各包含多少个元素? StrBlob b1; { StrBlob b2 = {"a", "an", "th ...
- C++ Primer 5th 第9章 顺序容器
练习9.1:对于下面的程序任务,vector.deque和list哪种容器最为适合?解释你的选择的理由.如果没有哪一种容器优于其他容器,也请解释理由.(a) 读取固定数量的单词,将它们按字典序插入到容 ...
- C++ Primer 5th 第6章 函数
正如第一章所说:C++的函数是一个能够完成一个功能的模块或者说是一段命名了的代码块. 如下图所示,函数可以重载,是一段实现某些功能命名了的代码. 一个完整的函数的构成有四部分: 1.返回类型 2.函数 ...
- C++ Primer 5th 第3章 字符串、向量和数组
*****代码在Debian g++ 5.40 / clang++ 3.8(C++11)下编写调试***** 本章主要是关于字符串.数组的内容,以及一些简单的容器知识. 1.using的声明 usin ...
- C++ Primer 5th 第2章 变量和基本类型
*****代码在Debian g++ 5.3.1 / clang++ 3.8(C++11)下编写调试***** 由于部分编译器对标准遵循的不同以及自身额外的扩展,本章书中的少数知识点与实际实现存在偏差 ...
- C++ Primer 5th 第14章 重载运算与类型转换
当运算符作用域类类型的对象时,可以通过运算符重载来重新定义该运算符的含义.重载运算符的意义在于我们和用户能够更简洁的书写和更方便的使用代码. 基本概念 重载的运算符是具有特殊名字的函数:函数名由关键词 ...
- C++ Primer 5th 第11章 关联容器
练习11.1:描述map 和 vector 的不同. map是关联容器,vector是顺序容器,关联容器与值无关,vector则与值密切相关 练习11.2:分别给出最适合使用 list.vector. ...
随机推荐
- php stripslashes() addslashes() 解析
stripslashes() 函数删除由 addslashes() 函数添加的反斜杠. 实例: <?php $str = "Is your name O\'reilly?"; ...
- Oracle merge into 使用记录
符合条件进行更新操作,不符合则进行插入操作. merge into myd_nsrdt n using ('as nsrsbh,'' as nsrmc, ' as nowphone,sysdate a ...
- 如何让多个Activity共用一个Menu
我们可以定义一个自己的CommActivity继承自Activity,然后让每个自定义Activity继承CommActivity,就可以做到. 例如: public class CommActivi ...
- PHP 之isset() 与 unset()
isset()用来判断某个变量是否已经被声明,他返回一个boolean类型的值,如果声明则返回true否则返回false.如果变量被声明后,给他赋值为NULL,他也返回false. 如: <?p ...
- Entity Framewor 学习笔记 (include + where)
如果我们想在子查询做过滤的话应该怎样写呢? IEnumerable<Product> products = db.products.Include(p => p.colors.Whe ...
- ural 1333 Genie Bomber 2
#include <cstdio> #include <cstring> #include <algorithm> #define maxn 200 using n ...
- ural 1671 Anansi's Cobweb
这道题是并差集的简单应用 #include <cstdio> #include <cstring> #include <algorithm> #define max ...
- Kill Process by Name
Kill Process by Name(works in: Microsoft Windows 95/98/ME/NT/2000/XP)It is sometimes necessary to te ...
- Delphi EurekaLog 调试内存泄露方法
要使用EurekaLog进行内存泄露检测,需要手动开启"EurekaLog Options..."下的"Advanced Options"旁的"Mem ...
- codeforces 100548F (西安现场赛F题):容斥原理
题目大意: 对n个排成一排的物品涂色,有m种颜色可选. 要求相邻的物品颜色不相同,且总共恰好有K种颜色,问所有可行的方案数 分析: 从m种颜色中选出k种,有c(m,k)种方法,那么我们只用考虑 k种颜 ...