第5章 循环和关系表达式
1.关于循环
-
关于bool值输出true和false还是1和0的问题
cout在显示bool值之前默认将它们转换为int,但如果需要使用输出true或false字符串来表示真假的话,只需要设置如下语句:
cout.setf(ios_base::boolalpha);
语句,更老一点的c++可能是cout.setf(ios:boolalpha);
-
可以在for循环语句中声明循环变量i,i作用域仅限于该循环语句。
for (int i = 0; i < 5; i++) cout << "C++ knows loops.\n"; cout << i << endl; //错误,此时i未定义!
-
可以使用const来定义一个常量变量,并用它来声明数组和引用数组长度。
#include <iostream>
const int Arsize = 16; //全局变量
int main()
{
long fact[Arsize];
for (int i = 0; i < Arsize; i++)
std::cout << fact[i] << endl;
return 0;
}
- for循环可以用来打印字符串
#include <iostream>
#include <cstring> //老版本需使用string.h
int main()
{
using namespace std;
cout << "Enter a word:"
string word;
cin >> word;
for (int i = word.size - 1; i >= 0; i--)
cout << word[i];
cout << endl;
return 0;
- 在一个表达式中不要对同一个变量使用2次以上的自增或自减运算符,因为系统不确定运算表达式的哪个部分
x = 2 * x++ * (3 - ++x); //不确定先计算x++还是++x,容易发生歧义的表达式,结果未知
-
对于内置类型(int、long等)来说,自增和自减运算符无论放在前面或后面其效率是一样的。但对于用户自定义的类型,前缀或后缀是这样解释的:
- 前缀运算符重载意义:将值加1,然后返回结果。
- 后缀运算符重载意义:首先复制一个副本,将其加1,然后再返回结果。
所以,相比较而言,前缀的效率要高于后缀。
-
前缀递增、前缀递减和解引用*的优先级相同,从右到左进行结合;后缀递增、后缀递减的优先级相同,但比前缀运算符的优先级高,以从左到右进行结合;
*++pt; //先将pt加1,然后取值;
++*pt; //先取pt存储的值,然后将该值加1,pt的值不变。
*pt++; //取出pt指向的值,然后将pt加1
-
逗号表达式可用在for循环控制语句的第一部分,用来同时声明两个变量。逗号表达式是优先级最低的,其值等于逗号后面一个表达式的值。但可以肯定的是,系统一定会先算逗号前面的表达式,然后再算逗号后面的表达式。
-
传统字符数组的比较需要借助strcmp(str1, str2)函数,而string类定义的字符串对象可以直接使用>、<、==、!=等关系运算符与字符串常量或string类变量进行比较。
-
可以使用clock()函数和有限循环创建精确延时函数,clock()函数返回程序开始运行以来所用的系统时间,但系统时间并不以秒为单位。所以在ctime头文件(早期版本在time.h)中定义了一个符号常量
CLOCK_PER_SEC
,它表示每秒钟的系统时钟数。同时也定义了clock()函数返回值类型为clock_t,编译器会自动将它转换为long、unsigned int或其它合适的类型。
#include <iostream>
#include <ctime> //老版本中使用#include <time.h>
int main()
{
using namespace std;
float secs = 2.5;
clock_t delay = secs * CLOCK_PER_SEC;
clock_t start = clock();
while (clock() - start < delay)
;
//至此延时了2.5秒。
cout << secs << "seconds had pasted." << endl;
return 0;
}
- C++11新增了一种循环
基于范围的for循环。如下例所示:
double prices[5] = {4.1, 2.3, 4.5, 6.2, 5.3};
for (double x : prices)
cout << x << std::endl;
x在数组prices范围内依次代表数组各元素值。同时为了能够修改数组元素,可以使用引用符&,见如下例子:
double prices[5] = {4.1, 2.3, 4.5, 6.2, 5.3};
for (double &x : prices)
x += 2.0;
//将数组中的每个元素加上2.0
2.关于类型别名
- 一种是采用#define宏定义方法,预处理器将在编译时进行宏替换,例如:
#define BYTE char
将在编译时对所有BYTE替换成char. - 另一种是采用typedef关键字创建类型别名,例如
#typedef char byte
,此后就可以使用byte来定义char类型变量了。 - 当需要在同一条语句中连续定义变量时,第一种方法就会造成错误,而第二种方法不会:
#define FLOAT_PTR float *
FLOAT_PTR pa, pb;
//经过预处理后语句2将会变成:float * pa, pb;
//而此时,pa是指针,pb却是float变量。
typedef float* float_ptr;
float_ptr pa, pb; //不会有上述问题
- 所以,良好的编程规范要求每条语句声明或定义一个变量!!!
3.关于cin.get()函数
该函数有三种函数原型(函数重载),即有3种不同的参数:cin.get(void)、cin.get(char &ch)、cin.get(char * array_name, int size )。
- cin.get(void):从输入缓冲队列中取一个字符并返回int类型(该字符的ASCII码), 若遇到文件尾, 则返回EOF。
- cin.get(char &ch):从输入缓冲队列中取一个字符,并存入char型参数ch中,并返回一个cin对象. 不同于C的是,此处不需要提供字符变量ch的地址,而是直接使用字符变量名ch,原因是C++采用了变量引用. 当遇到EOF时,ch将不被赋值, 函数返回false.
- 通过包含头文件cstdio(老版本使用stdio.h), 就可以使用getchar或putchar函数. 在C++中, cout.put(ch)用来输出字符ch. 其工作方式类似C语言中的putchar(ch), 只不过其参数为char, 而不是int
-
cin.get(char * array_name, int size):从输入队列中取得字符串存入字符数组array_name中,直到遇到回车或长度超过size。若遇到回车,其将回车符返还给输入序列。所以,一般使用
cin.get(array_name, size).get()
的方式来丢弃回车符,以避免影响下一条输入语句。
4.关于文件结束符EOF
- 不同系统下,通过键盘输入表达EOF
- Unix和Mac:在行首按下Ctrl + D
- Windows命令提示符下: 在任意位置按下Ctrl + Z和Enter键.
- GNU C++及VC++和BC++5.5: 行首按下Ctrl + Z和Enter键.
- C++中,cin有两个类函数来检测是否到达文件尾:eof()和fail(),当读取到EOF时,二者均返回true,否则返回false. 需要注意的是,这两个函数都是报告最近一次读取的字符,所以它们必须放在读取语句后.
#include <iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cin.get(ch);
while (cin.fail() == false)
{
cout << ch;
++count;
cin.get(ch);
}
cout << endl << count << "chars read\n";
return 0;
}
- cin.clear()可以重置输入流,即清空输入缓冲.
- 常见的字符输入程序:
char ch;
while (cin.get(ch)) //当读取失败或读到EOF时,cin.get(ch)返回false
{
...
}
或者
char ch;
cin.get(ch);
while (!cin.fail())
{
...
cin.get(ch);
}
或者
int ch; //cin.get()返回int型
while ((ch = cin.get()) != EOF)
{
cout.put(char(ch)); //其参数必须是char型
}
cout << endl;
网友评论