5 控制语句和逻辑运算符

  • 1 计数器控制的循环的要素
  • 2 for循环语句
    • 应用:计算复利
      • 在金融计算中使用double或float类型的特别提醒
      • 利用流操纵符格式化数值的输出
  • 3 do...while循环语句
  • 4 switch多路选择语句
    • 读入输入的字符
    • 输入EOF指示符
    • 在输入中忽略换行符、制表符和空格
    • 有关数据类型的说明
    • C++11的类内初始化器
  • 5 break和continue语句
    • break语句
    • continue语句
  • 6 逻辑运算符
    • 逻辑与(&&)运算符
    • 逻辑或(||)运算符
    • 逻辑非(!)运算符
  • 7 运算符优先级总表
  • 8 ==运算符和=运算符的混淆问题
    • 左值和右值

1 计数器控制的循环的要素

计数器控制的循环需要:

  1. 命名一个控制变量(或者循环计数器)
  2. 设置控制变量(controler)的初值
  3. 定义一个循环继续条件,用于对控制变量终止的测试(例如,循环是否应该继续)
  4. 增值(或减值),即在每次循环过程中修改控制变量的值
#include<iostream>
using namespace std;int main()
{unsigned int counter = 1;while (counter <= 10){cout << counter << " ";++counter;}cout << endl;
}

也可以用下面的写法让代码更简练

#include<iostream>
using namespace std;int main()
{unsigned int counter = 0;while (++counter <= 10)cout << counter << " ";cout << endl;
}

TIPS:

应使用整数值控制计数器的循环。

自增运算符和自减运算符分别只能和整形操作数一起使用。

2 for循环语句

通常,for语句用来描述计数器控制的循环,而while语句用于表达标记控制的循环。

如果for语句头部的“初始化”表达式中声明了控制变量,那么该控制变量仅能在for语句的循环体中使用,在此for语句之外它是未知的。

对控制变量名的使用进行的限制称为变量的作用域(scope)。

for循环头部如果要定义多变量,只能定义同种数据类型的变量,否则只能在for循环外定义多于变量,若认为浪费变量名,可以加{}限制作用域。正确定义如下:

for (int i=0 , j = 1; i < 9 && j < 10; i++ , j++)
{//blabla...
}

for (int i=0 , j = 1; i < 9 || j < 10; i++ , j++)
{//blabla...
}

for循环头部的三个表达式可选,但两个分号必需。

将分号直接放置在for语句头部的右括号的右边,这是一个逻辑错误。

控制变量的值可以在for语句循环体内进行改变,但容易导致难以察觉的逻辑错误。

若循环控制变量增值或减值的步长超过1,应尽量避免在循环条件中使用相等运算符(!===)。

应用:计算复利

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;int main()
{double amount;double principal = 1000.0;double rate = .05;cout << "Year" << setw(21) << "Amount on deposit" << endl;cout << fixed << setprecision(2);for (unsigned int year = 1; year <= 10; ++year){amount = principal * pow(1.0 + rate, year);cout << setw(4) << year << setw(21) << amount << endl;}
}

函数pow(x,y) 计算x的y次幂的值,它需要接受两个类型为double 的实参,并返回一个double类型的值。如果这个程序没有头文件<cmath> ,那么将无法通过编译。例子中的变量year是个整数,这个头文件包含信息,告诉编译器在这个函数调用时,把year的值转换成一个临时的double值。这些信息含在pow函数的函数原型中。

如果忘记包含头文件<cmath> ,将会产生一个编译错误。

在金融计算中使用double或float类型的特别提醒

例如,计算机中保存到两笔金额分别为14.234(打印出来是14.23)和18.673(打印出来是18.67),当他们相加时,内部求和的结果是32.907(打印出来是32.91),但是我们自己将打印的数字相加得到的是32.90。应当注意这个隐患。

利用流操纵符格式化数值的输出

在例子中,流操纵符setw(4) 规定了下一个输出值应占用的域宽为4。也就是说,cout 打印一个值,它至少占用4个字符位置。如果输出的值小于4个字符位置的宽度,那么在默认情况下,该值的输出在域宽范围内向右对齐;如果输出的值大于4个字符位置的宽度,那么域宽将向右侧扩展到整个值的实际宽度。

为了指出值要向左对齐输出,只需要简单地输出无参数的流操纵符left(在头文件<iostream>中可以找到)即可。当然向右对齐也可以恢复,只是再输出无参数的流操纵符right 而已。

我们在例子中应用了流操纵符fixedsetprecision ,这些格式的设置如果不被更改则会一直起作用。正因如此,称这样的设置为黏性设置(sticky setting)。可是,指定域宽的setw 只对接下来要输出的值有用。

3 do…while循环语句

do…while语句是循环体执行之后再进行循环继续条件的测试,因此循环体总是至少执行一次。

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;int main()
{unsigned int counter = 1;do{cout << counter << " ";++counter;} while (counter <= 10);cout << endl;
}

注意while语句的括号右侧有分号。

4 switch多路选择语句

使用switch语句优化GradeBook类:

#include <string>class GradeBook
{public:explicit GradeBook(std::string );void setCourseName(std::string );std::string getCourseName() const;void displayMessage() const;void inputGrades();void displayGradeReport() const;
private:std::string courseName;unsigned int aCount;unsigned int bCount;unsigned int cCount;unsigned int dCount;unsigned int fCount;
};
#include <iostream>
#include "GradeBook.h"
using namespace std;GradeBook::GradeBook(std::string) : aCount(0), bCount(0), cCount(0), dCount(0), fCount(0);
{setCourseName(name);
}
// SETTERS
void GradeBook::setCourseName(std::string)
{if (name.length() <= 25)courseName = name;else {courseName = name.substr(0, 25);cerr << "Name \"" << name << "\" exceeds maximum length (25).\n"<< "Limiting courseName to first 25 characters.\n"<< endl;}
}
// GETTERS
string GradeBook::getCourseName() const
{return courseName;
}
void GradeBook::displayMessage() const {std::cout << "Welcome to the grade book for\n"<< getCourseName() << "!\n"<< std::endl;
}
void GradeBook::inputGrades() {int grade;cout << "Enter the letter grades.\n"<< endl<< "Enter the EOF character to end input." << endl;while ((grade = cin.get()) != EOF) {switch (grade) {case 'A':case 'a':++aCount;break;case 'B':case 'b':++bCount;break;case 'C':case 'c':++cCount;break;case 'D':case 'd':++dCount;break;case 'F':case 'f':++fCount;break;case '\n':case '\t':case ' ':break;default:cout << "Incorrect letter grade entered. Enter a new grade."<< endl;break;}}
}
void GradeBook::displayGradeReport() const {cout << "\n\nNumber of students who received each letter grade:"<< "\nA: " << aCount << "\nB: " << bCount << "\nC: " << cCount<< "\nD: " << dCount << "\nF: " << fCount << endl;
}
#include "GradeBook.hpp"int main()
{GradeBook myGradeBook("CS101 C++ Programming");myGradeBook.displayMessage();myGradeBook.inputGrades();myGradeBook.displayGradeReport();
}

读入输入的字符

函数cin.get() 从键盘读入一个字符并保存到整型变量grade中,一般字符存储在char类型的变量中,它们也可以存储在任何整数数据类型中,因为类型shortintlonglong long 都可以保证不比char类型小。

所以根据具体用途,即可以把字符当作整数来处理,也可按照字符来对待。如:

cout << "The character (" << 'a' << ") has the value " << static_cast<int>('a') << endl;

打印字符a和它的整数值,结果如下:

The character (a) has the value 97

一般而言,整个赋值表达式的值正是赋给赋值运算符左边变量。因此赋值表达式grade=cin.get()的值等于由cin.get()返回并赋给变量grade的值。

a = b = c = 0;

这行代码首先计算赋值表达式c = 0 的值(=运算符是从右到左结合的)。然后,赋值表达式c = 0 的值(是0)赋给变量b,接着,赋值表达式b = (c = 0) 的值(也是0)赋值给变量a。

输入EOF指示符

EOF代表“end-of-file”,是用于标记“文件结束”的一个符号。在程序中我们常使用EOF(一般取值为-1)做标记值,但不可以直接输入-1或者EOF这三个字符作为这个标记值。准确地说,只能输入一个由具体系统决定的代表“文件结束”的组合键,指示不再有数据需要输入了。

EOF是一个符号整数常量,它通过头文件<iostream> 包含到程序中。EOF具有的数据类型是int

在OS X/UNIX/Linux系统和很多其他系统中,“文件结束”的输入通过在一行上输入如下的组合键实现:<Ctrl> d

在Microsoft Windows之类的其他系统下,“文件结束”的输入通过在一行上输入如下的组合键实现:<Ctrl> z

某些情况下,必须在按了前述组合键后,再按一次回车键。字符^Z 有时出现在屏幕上,表示文件结束。

switch语句中,若在单词case与被测试的整数值之间遗漏了空格,例如将case 3:写成了case3: ,那么会引起一个逻辑错误。

在输入中忽略换行符、制表符和空格

case '\n':
case '\t':
case ' ':break;

为了使程序读入字符,必须通过按回车键,这样会在希望处理的字符之后在输入中多加一个换行符。上述语句避免了每次输入换行符、制表符和空格时,都有default 子句打印一条错误信息。

每个case情况只可用于测试整型常量表达式——字符常量和整数常量的任意组合,其计算结果是一个常整数值。同样,每个case标签只能指定一个整型常量表达式。

TIPS:

switch语句的case标签中指定非常量的整型表达式是一个语法错误。

switch语句中,如果提供同样的case标签,则产生一个编译错误。

有关数据类型的说明

C++具有灵活的数据类型长度,每种类型的整数取值的范围由具体平台所决定。

除了intchar之外,C++还提供了类型shortlonglong long 。对于short整数而言,它的最小取值范围是-32768 ~ 32767。对于绝大多数的整数运算来说,long整数就足够了。long整数的最小取值范围是-2147483648 ~ 2147483647。在大多数计算机中,int类型要么与short类型等价,要么与long类型等价。各个int类型的取值范围至少与short类型相同,最多与long类型一样。数据类型char既可以用来表示计算机字符集中的任何字符,也可以用于表示小整数。

C++11的类内初始化器

C++11允许程序员在类声明中声明数据成员时,为它们提供默认值。如:

unsigned int aCount = 0;
unsigned int bCount = 0;
unsigned int cCount = 0;
unsigned int dCount = 0;
unsigned int fCount = 0;

这与之前例子中在类的构造函数中对数据成员初始化不同。

5 break和continue语句

break语句

break语句在whilefordo...while或者switch语句中执行,立刻使程序退出这些语句。

break语句的常见用法是要么提前离开循环,要么用于跳过switch语句的剩余部分。

continue语句

continue语句在whilefordo...while或者switch语句中执行时,是程序跳过循环体内剩下语句,继续进行循环体下一次迭代。

whiledo...while语句中,循环继续条件的测试在continue语句执行之后马上进行。在for语句中,则执行增值表达式,然后对循环继续条件进行测试。

for循环语句中,当continue语句执行后,程序控制转到for头部的控制变量增值部分继续执行。

如果while语句的增值表达式跟随在continue语句之后时,该增值表达式在程序测试循环继续条件之前不会执行,很可能导致死循环。

6 逻辑运算符

逻辑与(&&)运算符

若我们希望在保证两个条件都为true的前提下才能选择某个执行路径,则可以使用&&运算符。

一个逻辑与表达式的右侧只有在其左侧为true的情况下才会被计算。

TIPS:

在数学中的 3<x<7 是正确的表达,但在C++中要写成 3 < x && x < 7

逻辑或(||)运算符

&&运算符的优先级比||稍高些。两个运算符都是从左到右结合的。

&&一样,含||的表达式,其计算在一旦能够确定整个表达式的真假时,就会立即结束。

逻辑非(!)运算符

一元的逻辑非运算符只用一个条件作为操作数,且放在要“逆转”的条件前面。如:

if(!(grade == sentineValue))

大多数情况下,对于用逻辑非运算符表达的条件,程序员同样可以通过合适的关系运算符或者相等运算符来表达。例如,上面语句可以写成:

if(grade != sentineValue)

7 运算符优先级总表

在上一章的总表中加入逻辑和逗号运算符。

运算符 结合律 类型
:: () 从左向右 最高
++ -- static_cast<类型>() 从左向右 后缀
++ -- + - 从右向左 一元(前缀)
* / % 从左向右
+ - 从左向右
<< >> 从左向右 插入/提取
< <= > >= 从左向右 关系
== != 从左向右 相等
&& 从左向右 逻辑与
|| 从左向右 逻辑或
?: 从右向左 条件
= += -= *= /= %= 从右向左 赋值
, 从左向右 逗号

8 ==运算符和=运算符的混淆问题

在赋值时用==运算符,在比较时用=运算符,都属于逻辑错误,这种互换具有破坏性,因为通常不产生语法错误。

TIPS:

在书写x==7 之类的条件时,通常将变量名放左边,常量放右边。但写成7==x 这种形式会好些,即将常量放左边,变量名放右边,因为当不小心用=代替了== ,编译器将起到保护作用。编译器会认为7=x 是个编译错误,因为常量值是不可更改的。

左值和右值

变量名称为左值(lvalue),因为可以在赋值运算符左边使用;常量称为右值(rvalue),因为只能在赋值运算符右边使用。

左值可以作右值,但右值绝不能作左值。

如果想用一下一条简单语句为一个变量赋值:

x = 1;

却写成:

x == 1;

这里不是一个语法错误。编译器只是简单判断这个条件表达式。表达式的值为true或false,不管怎样,这里没赋值运算符,所以这个值自然丢失了,同时x的值保持不变。

C++重学之路 5 控制语句和逻辑运算符相关推荐

  1. C++重学之路 4 控制语句、赋值、自增和自减运算符

    4 控制语句.赋值.自增和自减运算符 1 算法 2 伪代码 3 控制结构 C++中的选择语句 C++中的循环语句 4 if选择语句 5 if...else双路选择语句 条件运算符(?:) 嵌套的if. ...

  2. C++重学之路 1 计算机和C++简介

    1 计算机和C++简介 1.1 硬件和软件 1.1.1 摩尔定律 1.1.2 计算机的组成 1.2 数据的层次结构 1.3 机器语言.汇编语言和高级语言 机器语言(Machine Language) ...

  3. 重学之路--Redis(1)

    基于狂神视频的笔记 Nosql概述 为什么Nosql 原来的架构–单机Mysql Memcached(缓存)+mysql+垂直拆分(读写分离) 减轻数据的压力 使用缓存来保证效率 分库分表 +水平拆分 ...

  4. 重学之路-Redis(2)

    基于狂神视频做的笔记 事务 Redis 事务本质:一组命令的集合!事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行! 一次性,顺序性,排他性!执行一系列命令! Redis事务没有隔离级别 ...

  5. 重学前端学习笔记(八)--JavaScript中的原型和类

    笔记说明 重学前端是程劭非(winter)[前手机淘宝前端负责人]在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的专 ...

  6. 从底层重学 Java 之 BigInteger 大整数 Gitchat连接

    Gitchat连接 https://gitbook.cn/gitchat/activity/5f395a80aced402379f6a0ca 简介 从底层,从原理,我们来重学一次 Java.BigIn ...

  7. css html 双面打印_CSS语法与规则 — 重学CSS

    我是三钻,一个在<技术银河>中等你们一起来终生漂泊学习. 点赞是力量,关注是认可,评论是关爱!下期再见 ! 前言 进入重学 CSS 的第一步,首先需要找到一些线索.我们在前面的课程中讲学习 ...

  8. 重学Java设计模式-创建者模式-建造者模式

    重学Java设计模式-创建者模式-建造者模式 内容摘自:重学 Java 设计模式:实战建造者模式「各项装修物料组合套餐选配场景」 | bugstack 虫洞栈 建造者模式介绍 图片来自:https:/ ...

  9. 《重学设计模式》PDF 出炉了 - 小傅哥,肝了50天写出18万字271页的实战编程资料...

    持续坚持原创输出,点击蓝字关注我吧 作者:小傅哥 博客:https://bugstack.cn ❝ 沉淀.分享.成长,让自己和他人都能有所收获!???? ❞ 目录 一.前言 二.简介 1. 谁发明了设 ...

最新文章

  1. --single-transaction 参数对应MyISAM引擎和InnoDB引擎
  2. R语言多因素方差分析及评估假设检验
  3. 手把手pytorch-transformers实战
  4. SSH-KeyGen 的用法 【转载】
  5. 发现四川科技馆在线网站修改用户设置页面的一个问题
  6. html优美界面左侧下拉,一组时尚的侧边栏菜单和下拉列表UI设计
  7. 修改之前的myshell使之支持输入输出重定向
  8. [前端随笔][css] 弹性布局
  9. nvsip能用别的软件吗_为什么很多企业转向了 Golang? Java, Python, C#没落了吗?
  10. 一文搞懂注册中心 zookeeper 和 eureka 中的CP和 AP
  11. linux上python3的安装
  12. Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结
  13. 深入解析数码相机CCD坏点及噪点检测!【图解教程】
  14. AD转换原理,器件与参数
  15. Scratch编程学习的好处
  16. python绘制国际象棋规则口诀_学好国际象棋必须知道的小口诀技巧
  17. 物联网常用无线模块 接收灵敏度及发射功率简化测量方法
  18. curl 命令的使用
  19. 传递给Appium服务器以开启相应安卓Automation会话的Capabilities的几点说明
  20. 你真的了解抑郁症吗?

热门文章

  1. .NetFrameWork介绍
  2. MobaXterm 忘记主密码 密码重置
  3. uart RX/TX测试方法
  4. 千锋教育实训day04————java
  5. 百度距离谷歌何止一个太平洋的距离
  6. 利用TensorRT实现神经网络提速(读取ONNX模型并运行)
  7. 四种方法处理“无法停止通用卷设备”
  8. 火车票报销凭证可以网上打印出来吗?火车票报销凭证怎么取
  9. python+0~100的奇数和
  10. 游戏光枪的三十年历史