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

C++重学之路 5 控制语句和逻辑运算符,第1张

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
using namespace std;

int main()
{
	unsigned int counter = 1;
	while (counter <= 10)
	{
		cout << counter << " ";
		++counter;
	}
	cout << endl;
}

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

#include
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
#include
#include
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类型的值。


如果这个程序没有头文件 ,那么将无法通过编译。


例子中的变量year是个整数,这个头文件包含信息,告诉编译器在这个函数调用时,把year的值转换成一个临时的double值。


这些信息含在pow函数的函数原型中。


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


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

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


应当注意这个隐患。


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

在例子中,流 *** 纵符setw(4) 规定了下一个输出值应占用的域宽为4。


也就是说,cout 打印一个值,它至少占用4个字符位置。


如果输出的值小于4个字符位置的宽度,那么在默认情况下,该值的输出在域宽范围内向右对齐;如果输出的值大于4个字符位置的宽度,那么域宽将向右侧扩展到整个值的实际宽度。


为了指出值要向左对齐输出,只需要简单地输出无参数的流 *** 纵符left(在头文件中可以找到)即可。


当然向右对齐也可以恢复,只是再输出无参数的流 *** 纵符right 而已。


我们在例子中应用了流 *** 纵符fixedsetprecision ,这些格式的设置如果不被更改则会一直起作用。


正因如此,称这样的设置为黏性设置(sticky setting)。


可是,指定域宽的setw 只对接下来要输出的值有用。


3 do…while循环语句

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


#include
#include
#include
using namespace std;

int main()
{
	unsigned int counter = 1;
	do
	{
		cout << counter << " ";
		++counter;
	} while (counter <= 10);
	cout << endl;
}

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


4 switch多路选择语句

使用switch语句优化GradeBook类:

#include 

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 
#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是一个符号整数常量,它通过头文件 包含到程序中。


EOF具有的数据类型是int


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

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

在数学中的 33 < 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的值保持不变。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/578231.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-11
下一篇 2022-04-11

发表评论

登录后才能评论

评论列表(0条)

保存