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

其他

  1. 使用空语句时应该加上注释,从而让读这段代码的人知道该语句是有意省略的。
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。三条准则(确定终止条件、初始化条件以及更新条件)都被压缩到了一个循环测试条件中。


posted @ 2025-11-27 19:03  Invinc-Z  阅读(4)  评论(0)    收藏  举报