设计循环时的几条指导原则:1)指定循环终止条件 2)在首次测试前初始化条件 3)在条件被再次测试之前更新条件
1 for循环
c++允许在for循环初始化部分中声明和初始化变量,c不允许,这种变量离开循环后就会消失。
#include <string>
string word;
cin>>word;
for(int i = word.size()-1;i>=0;i--) // 反向打印字符串
cout<<word[i];
2 while以及do-while循环
#include <ctime>
// #define clo clock_t
typedef clock_t clo; // 1)2)
float secs;
cin >> secs;
clo delay = secs * CLOCKS_PER_SEC; // 3)
cout << "start!" << endl;
clo start = clock(); // 4)
while(clock() - start < delay); // 时间差,目的等待secs秒
cout << "done!" << endl;
4)处:函数名clock()返回从开始程序到调用clock()函数之间的系统时间,问题是单位不一定是秒,其次他的类型可能是long、unsigned int或其他类型。
1)处:为类型建立别名有两种方式:一种是使用预处理器,格式#define aliasname typeName,缺点有时不适用,如
#define FLOAT_POINT float *
FLOAT_POINT pa,pb;
此时预处理器会将该声明转换为float * pa,pb;,pa是float*类型,而pb是float类型。另一种是关键字typedef来创建别名,格式typedef typeName aliasName;,它能够处理更加复杂的类型别名。
2)处:cctime将clock_t作为clock()返回类型的别名,编译器会将它转换为long、unsigned int或适合系统的其他类型
3)处:CLOCKS_PER_SEC为符号常量,等于每秒包含的系统时间单位数,秒数*CLOCKS_PER_SEC,可以得到以系统时间单位为单位的时间。
3 基于范围的for循环(c++11)
int number[5] = {1,2,3,4,5};
for(int x : number) // 版本1对数组中的元素执行相同的操作
cout << x << endl;
for(int &x : number) // 版本2:x是引用变量,能够修改数组中的内容,版本1不可以
x = 2 * x;
cout << x <<" ";
cout << endl;
4 文本输入与循环
方案一:使用原始的cin进行输入(有问题)
char ch;
int count = 0; // 计数
cin >> ch;
while (ch != '#'){
cout << ch;
count++;
cin >> ch; // 1)
}
cout << endl << count << endl;
// 测试示例
ewr fwe#wer
ewrfwe
6
1)问题:cin会忽略空格、制表符和换行符,因此输入中的空格没有被回显,也没有被包括在计数内。
方案二:使用cin.get(char)修改,缺点是#也有可能是合法输入,此时的程序就出错了。
char ch;
int count = 0; // 计数
cin.get(ch);
while (ch != '#'){
cout << ch;
count++;
cin.get(ch);
}
cout << endl << count << endl;
// 测试示例
wew we# // 这里输入时有tab键
wew we
6
方案三:检测文件尾条件(EOF,被定义为-1,它不表示字符,而是指出没有字符) windows将ctrl+Z视为模拟的EOF,用户还要按回车键结束。
检测到EOF后,cin将两位(eofbit和failbit)都设置为1,可以通过成员函数eof()查看eofbit是否被设置,如果检测到EOF,则cin.eof()将返回bool值true,否则返回false。同样,如果eofbit或failbit被设置为1,则fail()成员函数返回true,否则返回false。eof()和fail()方法报告最近读取结果,应将cin.eof()或cin.fail()测试放在读取之后。
char ch;
int count = 0;
cin.get(ch);
while(cin.fail() == false) // while(!cin.fail())
{
cout << ch;
count++;
cin.get(ch);
}
cout << endl << count << endl;
// 测试示例
qwe ert
qwe ert
^Z
8 // 在qwe ert后有回车键
最终通用版: cin.get(ch)版本
char ch;
int count = 0;
while(cin.get(ch)) // 1)
{
cout << ch;
count++;
}
cout << endl << count << endl;
// 测试示例
wer zxc
wer zxc
^Z
8
1)处:方法cin.get(ch)的返回值是一个cin对象,然而istream类提供一个将istream对象转换为bool值的函数,所以当cin出现在需要bool值的地方时,该转换函数将被调用。在判断循环测试条件时,程序必须首先调用cin.get(ch),如果成功,则将值放入ch中。然后,程序获得函数调用的返回值,即cin。接下来,程序对cin进行bool转换,如果输入成功,则结果为true,否则为false。这时的三条指导原则全部放在while的循环测试条件中。
ch = cin.get()版本
int ch; // 1)
int count = 0;
while((ch = cin.get()) != EOF) // 1)
{
cout.put(char(ch));
count++;
}
cout << endl << count << endl;
// 测试示例
we are Chinese.
we are Chinese.
^Z
16
1)处: char类型可能是没有符号的,因此char变量不可能是-1,测试条件永远不会成立。当使用cin.get()并测试EOF,则必须将返回值赋给int变量,而不是char变量。
以上出现的cin和cout的函数可参考如下博客链接,cin对象中的相同函数名,不同参数列表,为函数重载。
https://blog.csdn.net/vinkuan/article/details/104118391
https://blog.csdn.net/vinkuan/article/details/104215308
5 循环嵌套和二维数组
const char * varieties[NUM] = // 1)2)
{
"fruit",
"snacks",
"drink"
};
double price[NUM][VAL] = { // 3)
{ 10,11,12,13,15 },
{ 21,22,23,24,25},
{ 7,8,9,10,11}
};
for(int varity = 0; varity < NUM; ++varity)
{
cout << varieties[varity] << ":\t";
for(int pri = 0; pri < VAL; ++pri)
cout << price[varity][pri]<<"\t";
cout << endl;
}
// 测试结果
fruit: 10 11 12 13 15
snacks: 21 22 23 24 25
drink: 7 8 9 10 11
1)字符串字面值是常量,所以在声明中使用const关键字,意味着可以用varieties访问字符串,但不可修改它
2)这是字符串指针数组,也可以用char数组的数组和string对象数组,如下
char varieties[NUM][10] = // char数组的数组
{
"fruit",
"snacks",
"drink"
};
const string varieties[NUM] = // string对象数组。可省略const,便可修改字符串
{
"fruit",
"snacks",
"drink"
};