1、递增(++)和递减(–)运算符
递增和递减运算符都是在自身的基础上进行加 1 或者 减 1。根据其在数值前面还是后面,运算结果略有不同。
#include <iostream>
int main()
{
using namespace std;
int a = 20;
int b = 20;
cout << "a = " << a << ", b = " << b << endl;
cout << "a++ = " << a++ << ", ++b = " << ++b << endl;
cout << "a = " << a << ", b = " << b << endl;
return 0;
}
程序输出:
a = 20, b = 20
a++ = 20, ++b = 21
a = 21, b = 21
程序分析:a++ 是使用 a 的当前值计算表达式,计算完成后再对 a 加 1,因此在第二次输出 a++ 时结果依然为 20,但是在第三次输出 a 时,结果为 21;++b 是先将 b 的值加 1,然后使用新的值计算表达式,因此在第二步输出 ++b,值为 21。
2、副作用和顺序点
下面详细地介绍 c++ 就递增运算符何时生效的哪些方面做了规定,哪些方面没有规定。
副作用指的是在计算表达式时对某些东西(如储存在变量中的值)进行了修改;顺序点是程序执行过程中的一个点,在这里,进入下一步之前将确保对所有的副作用都进行了评估,在 c++ 中,语句中的分号就是一个顺序点,这意味着程序处理下一条语句之前,赋值运算符、递增运算符和递减运算符执行的所有修改都必须完成。任何完整的表达式末尾都是一个顺序点。
完整的表达式可以这样定义:不是另一个更大表达式的子表达式。
比如用作 while 循环中检测条件的表达式:
while (i++ < 10)
cout << i << endl;
在这里,并非是先在 cout 中使用 i 的值,再将其加 1。实际上,表达式 i++ < 10
是一个完整表达式,因此该表达式的末尾是一个顺序点。所以,c++ 确保副作用(将 i 加 1)在程序进入 cout 之前完成。然而,通过使用后缀格式,可确保将 i 同 10 进行比较后再将其值加 1。即 i 加1 的步骤在 i 与 10 进行比较后,进入 cout 之前进行。
此外,应该尽量规避使用类似
y = (1 + x++) + (4 + x++);
这样的语句,因为 c++ 没有规定在每个子表达式后将 x 的值递增,还是在这个表达式计算完毕后才将 x 的值递增。
c++ 11 文档中,不再使用术语“顺序点”而改用“顺序”。
3、组合赋值运算符
操作符 | 作用(L为左操作数,R为右操作数) |
---|---|
+= | 将 L+R 赋给 L |
-= | 将 L-R 赋给 L |
*= | 将 L*R 赋给 L |
/= | 将 L/R 赋给 L |
%= | 将 L%R 赋给 L |
示例程序如下:
#include <iostream>
int main()
{
using namespace std;
int a = 1;
int b = 2;
int c = 3;
int d = 4;
a += b;
cout << a << endl;
c *= d;
cout << c << endl;
return 0;
}
程序输出:
3
12
4、复合语句(语句块)
由于 for 循环的循环体只能是一条语句,如果想要多写几条语句,c++ 提供了一种方法:使用花括号 {} 将语句括起来。示例程序如下:
#include <iostream>
int main()
{
using namespace std;
for (int i = 0; i < 5; i++)
{
int a;
cout << "Enter a number: " << endl;
cin >> a;
cout << "you enter: " << a << endl;
} //使用花括号将多条语句括起来当作一个语句块
return 0;
}
注意:
-
在语句块内部定义一个新的变量,则仅当程序执行该语句块中的语句时,该变量才存在。执行完该语句后,变量将被释放。在语句块外部将不能继续使用该变量的值。
-
如果已经存在一个外部变量,但是在语句块内部又声明了一个变量,那么在语句块内部依旧按照新声明的变量进行。
5、关系表达式
5.1
c++ 提供 6 种关系运算符来对数字进行比较。此外,由于字符用其 ASCII 码表示,因此也可以将这些运算符用于字符。对于所有关系表达式,如果结果为真,则其值将为 TRUE,否则为 FALSE。
以下为关系运算符:
操作符 | 含义 |
---|---|
< | 小于 |
<= | 小于或等于 |
== | 等于 |
> | 大于 |
>= | 大于或等于 |
!= | 不等于 |
5.2
关系表达式在数值计算中可以提升为 int:
x + 3 > y - 2
(x + 3) > y - 2
x + (3 > y) - 2
这样的表达式都成立。由于关系运算符的优先级比算术运算符低,因此表达式 1 和表达式 2 等价。而表达式 3 中,(3 > y)可以提升为整型,其值为 0 或 1。
注意:不要混淆赋值运算符(=)与等于运算符(==)。等于运算符的结果是TRUE 或 FALSE,通常用于 for 循环中的循环终止条件。
6、c-风格字符串的比较
6.1 字符串的比较
现有字符串 “mate”,有另一字符数组名称为 word,想要检测 word 的字符串是不是 “mate”,能使用 word == "mate"
吗?
注意,数组名是数组的地址,因此字符数组名并不代表字符串。因此上面的关系表达式并不是判断两个字符是否相同,而是查看它们是否储存在相同的地址上。
对于 c-风格字符串,应该使用 c-风格字符串库中的 strcmp()函数来比较。该函数接受两个字符串地址作为参数。这意味着参数可以是指针、字符串常量或字符串数组名。如果两个字符串相同,该函数返回零。具体用法参考 《c++ premier plus 第 6 版》第118页。此处仅仅说明不能使用等于算术运算符进行比较c-风格字符串。
以下程序在 for 循环的测试条件中使用了 strcmp() ,该程序通过循环,将字符修改为"mate",即 strcmp() 确定该单词为 “mate” 时终止:
#include <iostream>
#include <cstring>
int main()
{
using namespace std;
char word[5] = "?ate";
for (char ch = 'a'; strcmp(word, "mate"); ch++)
{
cout << word << endl;
word[0] = ch;
}
cout << "After loop ends, word is " << word << endl;
return 0;
}
6.2 字符的比较
字符实际上是整型,因此可以用等于运算符进行比较。如下列表达式:
for (ch = 'a'; ch <= 'z';ch++)
cout << ch;
7、string 类字符串的比较
如果将字符串声明为 string 类,那么可以直接使用关系运算符进行比较。
#include <iostream>
#include <cstring>
int main()
{
using namespace std;
string word = "?ate"; // 声明 string 类字符串
for (char ch = 'a'; word != "mate"; ch++) // string 类字符串可以直接使用关系运算符
{
cout << word << endl;
word[0] = ch;
}
cout << "After loop ends, word is " << word << endl;
return 0;
}