《C++ primer plus》:第五章 循环和关系表达式

  • for循环
  • 表达式和语句
  • 递增运算符和递减运算符:++ 和 - -
  • 组合赋值运算符
  • 复合语句(语句块)
  • 逗号运算符
  • 关系运算符:>、>=、==、<=、< 和 !=
  • while循环
  • typedef工具
  • do while 循环
  • 字符输入方法get()
  • 文件尾条件
  • 嵌套循环和二维数组

1. for循环

for循环是入口条件循环,这意味着在每次执行循环体之前,都将计算测试表达式的值,当测试表达式的值为false时,将不会执行循环体。

for(cin>>x; x==0; cin >>x) ,输入0,才会继续循环,一旦不输入0,就会退出循环。

C++ 11 新特性:基于范围的 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;

符号&表明x是一个引用变量,这个主题将在第8章讨论。就这里而言,这种声明让接下来的代码能够修改数组的内容,而第一种语法不能。

还可以结合使用基于范围的 for 循环和初始化列表:

for (int x : { 3, 5, 2, 8, 6})
	cout << x << " ";
cout << '\n';

2.表达式和语句

x=20

C++将赋值表达式的值定义为左侧成员的值,因此这个表达式的值为20。由于赋值表达式有值,因此可以编写下面这样的语句:

maids = (cooks = 4) + 3;

表达式 cooks=4 的值为4,因此 maids 的值为7。然而,C++虽然允许这样做,但并不意味着应鼓励这种做法。允许存在上述语句的原则也允许编写如下的语句:

x = y = z = 0;

这种方法可以快速地将若干变量设置为相同的值。赋值运算符是从右向左结合的,因此首先将 0 赋给 z,然后将 z=0 赋值给 y,以此类推。

x<y 这样的关系表达式将被判定为 bool 值 true 或 false。

cout 在显示bool值之前将它们转换为 int, 但cout.setf(ios_bass::boolalpha) 函数调用设置了一个标记,该标记命令cout显示 true 和 false,而不是 1 和 0;

注意,表达式和语句概念上的差别,从表达式到语句的转变很容易,只要加分号即可。因此
age = 100是一个表达式,而
age = 100; 是一条语句。

3. 递增运算符 ++ 和递减运算符 - -

前缀版本: ++x, 先加后用

后缀版本: x++, 先用后加

注意:千万不要失去控制,在同一条语句对同一个值递增或者递减多次,例如,下面这条语句在不同的系统上将生成不同的效果:
x = 2 * x++ * (3 - ++ x);

递增递减运算符和指针:
double arr[5] = { 21.1, 32.8, 23.4, 45.2, 37.4};
double *pt = arr;

double x = * ++pt;
先将指向arr[1],再解引用,即x为arr[1]的值;

++ *pt;
先解引用,再递增,即将arr[1]的值加1;

(*pt)++;
将arr[1]的值加1

x = *pt++;
这个要注意,虽然先递增了pt,但是在该表达式中使用pt时,仍然使用pt之前的值,即所谓的先用后加,所以x的值是arr[1]的值,但该语句执行完之后,pt的值将为arr[2]的地址。

4. 组合赋值运算符

+=
-=
*=
/=
%=

5. 复合语句(语句块)

6. 逗号运算符

++j, --i
int i, j;

for (j=0, i = word.size() - 1; j<i; --i, ++j)

7. 关系运算符

<
<=
==
>
>=
!=

关系运算符的优先级比算术运算符低。这意味着表达式:
x + 3 > y - 2
对应于:
(x+3) > (y-2)
而不是:
x + (3>y) -2
由于将bool值提升为int后,表达式(3>y)要么为1, 要么为0,因此第二个和第三个表达式都是有效的。不过C++使第一个表达式等价于第二个表达式。

for 循环的灵活设计让用户很容易出错。如果不小心遗漏了 == 运算符中的一个等号,则 for 循环的测试部分将是一个赋值表达式,而不是关系表达式,此时代码仍然是有效的。这是因为可以将任何有效的C++表达式用作for循环的测试条件。别忘了,非零值为true,零值为false。

C-风格字符串的比较
word == “mate”
这个关系表达式不是判断两个字符串是否相同,而是查看它们是否存储在相同的地址上。
应使用C-风格字符串库中的 strcmp() 函数来比较。该函数接受两个字符串地址作为参数。

虽然不能用关系运算符来比较字符串,但是可以用它们来比较字符,因为字符实际上是整型。

string类能够在下述条件下使用关系运算符:至少有一个操作数为string对象,另一个操作数可以是string对象也可以是c-风格字符串。

但是注意,不同于C-风格字符串,string对象不用空字符来标记字符串末尾,因此不能用空字符来判别是否到达string类字符串的末尾。

8. while 循环

通常,程序员使用for循环来为循环计数,因为 for 循环格式允许将所有相关的信息——初始值、终止值和更新计数器的方法——放在同一个地方。在无法预先知道循环将执行的次数时,程序员通常会选择 while 循环。

while (test-condition)
body

和for循环一样,while循环也是一种入口条件循环,即每次在执行循环体之前计算测试条件表达式。

类型别名

9. typedef 工具

C++ 为类型建立别名的方式有两种。一种是使用预处理器:

#define BYTE char // preprocessor replaces BYTE with char

这样,预处理器将在编译程序时用 char 替换所有的 BYTE ,从而使 BYTE 成为 char 的别名。

第二种方法是 使用 C++ (和 C) 的关键字 typedef 来创建别名。例如,要将 byte 作为 char 的别名,可以这样做:

typedef typeName aliasName;

换句话说,如果要将 aliasName 作为某种类型的别名,可以声明 aliasName,如同将 aliaName 声明为这种类型的变量那样,然后在声明的前面加上关键字 typedef。例如,要让 byte_pointer 成为 char 指针的别名,可将 byte_pointer 声明为 char 指针,然后在前面加上 typedef:

typedef char * byte_pointer;

也可以使用 #define,但在声明用逗号分隔的一系列变量时,这种方法不适用。例如:

#define FLOAT_POINTER float *
FLOAT_POINTER pa, pb;

预处理器置换将该声明转换为这样:
float * pa, pb; // pa a pointer to float, pb just a float

typedef 方法不会有这样的问题。它能够处理更复杂的类型别名,这使得与使用 #define 相比,使用 typedef 是一种更佳的选择——有时候,这也是唯一的选择。

注意,typedef不会创建新的类型,而只是为已有的类型建立一个新名称。如果将 word 作为 int 的别名,则 cout 将把word 类型的值视为 int 类型。

do while 循环

do while 循环不同于 for 循环和 while循环,是一种出口条件循环,即执行循环体在条件判断之前。

for 循环的空测试条件被默认为 true。

10 .字符输入方法 get()

  1. cin
    cin会忽略空格和换行符
    istream对象提供了一个可以将istream对象(如cin) 转换为 bool 值的函数;当cin出现在需要bool值的地方,该转换函数将被调用。如果最后一次读取成功了,则转换为 true,否则为 false。这意味着可以写:
    while(cin) 用来作为检测是否读取成功的入口条件

  2. cin.get(char);
    cin.get(char)可以修补cin的这个问题
    如果熟悉C语言,可能会以为这存在严重的错误, cin.get(char)调用将一个值放在 char 变量中,这意味着将修改该变量的值。在C语言中,要修改变量的值,必须将变量的地址传递给函数。但在C++中,只要函数将参数声明为引用即可。

  3. ch = cin.get();

11. 文件尾条件

EOF是在文件 iostream 中定义的

判断EOF:
while(cin.fail()==false)
while(cin.eof()==false)
fail()比eof()可用于更多的实现中
或者接改为
while(!cin.fail())
或者直接
while(cin)
while(cin.get(ch))
因为cin和cin.get(ch)都是返回一个istream对象,执行bool转换后变为true(成功读取字符时)或false(到达EOF时)

还可以使用
ch = cin.get()
但是需要注意的是,由于EOF表示的不是有效字符编码,因此可能不与char类型兼容,例如,在有些系统中,char类型是没有符号的,因此char变量不可能为EOF值(-1),由于这种原因,如果使用cin.get()并测试EOF,则必须将返回值赋给int变量,而不是char变量,随之而来的问题就是必须要在显示ch时将其强制转换为char类型。
例如:

int ch;
while( (ch=cin.get())!=EOF){
	cout.put(char(ch));
}

cin.get(ch) 与 cin.get() 的比较

属性cin.get(ch)ch=cin.get()
传递输入字符的方式赋给参数ch将函数返回值赋给ch
用于字符输入时函数的返回值istream对象(执行bool转换后为 true)int类型的字符编码
到达EOF时函数的返回值istream对象(执行bool转换后为 false)EOF

12. 嵌套循环和二维数组

const int Cities = 5;

char * cities[Cities] = {
“Gribble City”,
“Gribbletown”,
“New Gribble”,
“San Gribble”,
“Gribble Vista”
};

char cities[Cities][25] = {
“Gribble City”,
“Gribbletown”,
“New Gribble”,
“San Gribble”,
“Gribble Vista”
};

string cities[Cities] = {
“Gribble City”,
“Gribbletown”,
“New Gribble”,
“San Gribble”,
“Gribble Vista”
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值