C++之循环、表达式和语句(五)
本文记录了C++中与循环、表达式和语句相关的容易遗忘的一些知识。
表达式和语句
定义
-
一个C++表达式是一个值,或者是值与运算符的组合,并且每个C++表达式都有一个值。从C++的构建方式来看,
-
对表达式进行求值是主要作用,改变变量是副作用。
-
语句没有值。不能将语句赋值给变量,比如for语句、声明语句等。
-
从表达式到语句只是一小步,只需加一个分号。
打破规则
C++ 为 C 语言的循环增加了一项特性,这需要对 for 循环的语法进行一些巧妙的调整。以下是原来的语法:
for (expression; expression; expression)
statement
特别是,for结构的控制部分由三个表达式组成,这些表达式用分号分隔。不过,C++循环允许你做如下之类的事情:
for (int i = 0; i < 5; i++)
也就是说,你可以在for循环的初始化区域声明一个变量。这可能很方便,但它不符合原有的语法,因为声明不是表达式。
for语句的语法已修改为如下形式:
for (for-init-statement condition; expression)
statement
乍一看,这似乎有些奇怪,因为这里只有一个分号,而不是两个。但这是没问题的,因为for初始化语句被认定为一个语句,而一个语句本身就带有分号。至于for-init-statement,它被识别为表达式语句或声明。此语法规则用一个自带分号的语句取代了后跟分号的表达式。
归根结底,这意味着C++程序员希望能够在for循环的初始化部分声明并初始化一个变量,而且他们会不惜对C++语法乃至英语语言做出任何必要的改动来实现这一点。
逗号表达式
- 逗号表达式本身是序列点
- 且有最低的运算符优先级
- 逗号表达式的值是该表达式第二部分的值
i = 20, j = 2 * i // i set to 20, then j set to 40
cata = 17,240; // read as (cats = 17), 240; cata = 17 240 do nothing
cats = (17,240); // cats = 240
其他
- 使用空语句时应该加上注释,从而让读这段代码的人知道该语句是有意省略的。
while(cin >>s && s != sought )
; // 空语句
循环
前缀++与后缀++的效率
如果将值用于某种用途(例如作为函数参数或赋值给变量),那么使用前缀形式还是后缀形式会有所不同。但是,如果递增或递减表达式的值未被使用,情况会怎样呢?例如,x++;和++x;有什么区别呢?
从逻辑上讲,在这两种情况下,使用前缀形式还是后缀形式并没有区别。表达式的值并未被使用,因此唯一的影响就是副作用。这里使用这些运算符的表达式都是完整表达式,所以到程序执行下一步时,对x进行递增的副作用肯定已经完成;前缀形式和后缀形式会产生相同的最终结果。
不过,尽管前缀形式和后缀形式的选择对程序行为没有影响,但这种选择可能会对执行速度产生微小影响。对于内置类型和现代编译器来说,这似乎不是什么问题。但C++允许为类定义这些运算符。在这种情况下,用户定义的前缀函数的工作方式是先递增一个值,然后返回该值。而后缀版本的工作方式是先保存该值的一个副本,对该值进行递增,然后返回保存的副本。因此,对于类来说,前缀版本比后缀版本效率要高一些。
int i = 0, j;
j = ++i; // j = 1, i = 1 :前置版本得到递增之后的值
j = i++; // j = 1, i = 2 :后置版本得到递增之前的值
类型别名
C++有两种方法可以为一种类型建立新名称作为别名。一种是使用预处理器(在编译时进行宏替换):
#define BYTE char // 预处理器将BYTE替换为char
第二种方法是使用C++(以及C语言)的关键字typedef来创建别名。例如,要让byte成为char的别名,可以这样写:
typedef char byte; // 使byte成为char的别名
其一般形式如下:
typedef typeName aliasName;
换句话说,如果你想让别名成为某一特定类型的别名,你可以先像声明该类型的变量一样声明这个别名,然后在声明前面加上typedef关键字。例如,要让byte_pointer成为指向char的指针的别名,你可以先将byte_pointer声明为指向char的指针,然后在前面加上typedef:
typedef char * byte_pointer; // 指向char类型的指针
基于范围的for循环
double prices[5] = {4.99, 10.99, 6.87, 7.99, 8.49};
for (double x : prices)
cout << x << std::endl;
// 修改数组中的值要用引用
for (double &x : prices)
x = x * 0.80; //20% off sale
// 用于初始化列表
for (int x : {3, 5, 2, 8, 6})
cout << x << " ";
cout << ‘\n’;
键盘模拟EOF
Ctrl + Z // Windows
Ctrl + D // Unix Linux
请注意,在Unix及类Unix系统(包括Linux和Cygwin)中,Ctrl+Z会暂停程序的执行;fg命令可使执行恢复。
常用的字符输入习语
while (cin.get(ch)) // while input is successful
{
... // do stuff
}
首先必须执行对cin.get(ch)的调用,若调用成功,就会将一个值存入ch中。然后程序会从该函数调用中获取返回值,这个返回值就是cin。接着,程序会对cin进行bool类型转换,如果输入成功,转换结果为true,否则为false。三条准则(确定终止条件、初始化条件以及更新条件)都被压缩到了一个循环测试条件中。

浙公网安备 33010602011771号