C++提供三种循环:for循环、while循环和do while循环。
int i;
for (i = 0; i < 5; i++)
cout << "C++ knows loops.\n";
该循环首先将整数变量i设置为0:
i = 0
这是循环的初始化部分,然后,循环测试部分检查i是否小于5:
i < 5
如果确实小于5,则程序执行接下来的语句–循环体:
cout << "C++ knows loops.\n";
然后程序使用循环更新部分将i加1:
i++
接下来,循环开始了新的周期,将新的i值与5比较。
for循环的组成部分完成步骤:
1、设置初始值;
2、执行测试,判断循环是否应当继续进行;
3、执行循环操作;
4、更新用于测试的值。
1.表达式和语句
for语句的控制部分使用了3个表达式。
maids = (cooks = 4) + 3;
表达式cooks=4的值为4,因此maids的值为7。下面的语句由也是允许的:
x = y = z = 0;
这种方法可以快速地将若干个变量设置为相同的值。优先级表表明,赋值运算符是从右向左结合的,因此首先将0赋给z,然后将z=0赋给y,依次类推。
从表达式到语句的转换很容易,只要加上分号即可,因此下面是一个表达式:
age = 100
而下面一条语句:
age = 100;
更准确地说,这是一条表达式语句。只要加上分号,所有的表达式都可以成为语句,但不一定编程有意义。例如:
roents + 6;
编译器允许这样的语句,但它没有完成任何有用的工作。程序仅仅计算和,而没有使用得到的结果。
2.非表达式和语句
下面语句是一个表达式:
int toad;
而int toad不是表达式,因为它没有值。因此,下面的代码非法:
eggs = int toad * 1000;
同样不能把for循环赋给变量,for循环不是表达式,因此没有值,也不能给它赋值。
3、修改规则
C++对C循环的基础上添加了一项特性,要求对for循环句法做一些微妙的调整:
for (int i = 0; i < 5; i++)
也就是说,可以在for循环的初始化部分中声明变量。
使用for循环计算并存储前n个阶乘:
formore.cpp
#include
const int ArSize = 16;
int main()
{
using namespace std;
long long f[ArSize];
f[0] = f[1] = 1;
for (int i = 2; i < ArSize; i++)
f[i] = i * f[i-1];
for (int i = 0; i < ArSize; i++)
cout << i << "! = " << f[i] << endl;
return 0;
}
结果:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
定义一个const值来表示数组中的元素个数是个好办法。如果要扩展处理20个阶乘,则只需要修改ArSize的值为20,而不需要在程序将16修改为20。
到现在为止,循环示例每一轮循环计数加1或减1。可以通过修改更新表达式来修改步长:
int by = 3;
for (int i = 0; i < 9; i = i + by)
cout << i << endl;
for循环提供了一种依次访问字符串随的每个字符的方式。
forstr1.cpp
#include
#include
using namespace std;
int main()
{
cout << "Enter a word:\n";
string word;
cin >> word;
for (int i = word.size() - 1; i >= 0; i--)
cout << word[i];
cout << "\nBye.\n";
return 0;
}
结果:
Enter a word:
animal
lamina
Bye.
在本例子中,可以使用string对象,也可以使用char数组,因为它们都可以使用数组表示法来访问字符串中的字符。
两个运算符都要两种变体,前缀版本位于操作数前面,如++x;后缀版本位于操作数后面,如x++,两个版本对操作数的影响是相同的,但是影响的时间不同。
plus_one.cpp
#include
int main()
{
using namespace std;
int a = 20;
int b = 20;
cout << "a = " << a << "; b = " << b << endl;
cout << "a++ = " << a++ << "; ++b = " << ++b << endl;
cout << "a = " << a << "; b = " << b << endl;
return 0;
}
结果:
a = 20; b = 20
a++ = 20; ++b = 21
a = 21; b = 21
a++意味着使用a当前值计算,然后将a的值加一;而b++的意思是先将b的值加1,然后使用新的值来计算表达式。例如:
int x = 5;
int y = ++x; //y的值为6
int z = 5;
int y = z++; //y的值为5
递增和递减运算符都是漂亮的小型运算符,不过千万不要失去控制,在同一条语句对同一个值递增或递减多次。问题在于,规则“使用后修改”和“修改后使用”可能变得模糊不清。下面的语句在不同的系统中将生成不同的结果:
x = 2 * x++ * (3 - ++x);
对于这种语句,C++没有定义正确的行为。
副作用指的是在计算表达式时对某些东西(如存储在变量中的值)进行了修改;顺序点是程序执行过程中的一个点。在C++中,语句中的分号就是一个顺序点,这意味着程序处理下一条语句之前,赋值运算符、递增运算符和递减运算符执行所有的修改都必须完成。
完整的表达式:不另一个更大表达式的子表达式。完整的表达式例子有:表达式语句中的表达式部分以及用作while循环中检测条件的表达式。
while (guest++ < 10)
cout << guest << endl;
在这里,可以认为“使用值,然后递增”,意味着先在cout语句中使用guest的值,再将其值加1。然而,表达式guest++ < 10是一个完整的表达式,因为它是一个while循环的测试条件,因此该表达式的末尾是一个顺序点。所以,C++确保副作用(将guest加1)在程序进入cout之前完成。然而,通过使用后缀格式,可确保将guest同10进行比较后再将其值加1。
现在看如下语句:
y = (4 + x++) + (6 + x++);
表达式4 + x++不是一个完整的表达式,因此C++不保证x的值在计算子表达式4+x++后立刻增加1。在这个例子中,整条赋值语句是一个完整表达式,而分号表示了顺序点,因此C++只保证程序执行到下一条语句之前,x的值将被递增两次。
C++中,没有规定是在计算每个子表达式之后将x的值递增,还是整个表达式计算完毕才将x的值递增,鉴于此,应避免使用这样的表达式。
在C++11文档中,不再使用术语”顺序点“,因为这个概念难以用于讨论多线程执行。反而,使用了术语”顺序“,他表示有些事情在其他事件前发生。
x++;
++x;
从逻辑上说,上述情形下,使用前缀和后缀表达式没有区别,即当表达式的值未被使用时,因此只存在副作用。
C++允许针对类定义这些运算符,在这种情况下,用户定义前缀函数:将值加1,然后返回结果;但后缀版本首先复制一个副本,将其加去,然后将复制的副本返回。因此,对于类而言,前缀版本的效率比后缀版本的效率高。
总之,对于内置类型,采用哪种格式都不会有差别;但对于用户定义的类型,如果有用户定义的递增和递减运算符,作为前缀格式的效率高。
将递增运算符用户指针时,将把指针的值增加其指向的数据类型占用的字节数,这种规则适用于指针递增和递减:
double arr[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
double *pt = arr;
++pt;
也可以结合使用这些运算符和*运算符来修改指针所指向的值。
前缀运算符的从右到左结合规则意味着 ∗ \ast ∗++pt的含义如下:现将++应用于pt(因为++位于 ∗ \ast ∗的右边),然后将 ∗ \ast ∗应用于被递增后的pt:
double x = *++pt; //指向arr[2],值为23.4
另一方面,++*pt意味着先取pt所指向的值,然后将这个值加1:
++*pt; //指向arr[2],值为24.4
接下来,看看下面的组合:
(*pt)++;
圆括号指出,首先对指针解除引用,得到24.4,然后,运算符将这个值递增到25.4,pt仍指向arr[2]。最后,看下面组合:
x = *pt++;
后缀用算符的优先级高,这意味着将运算符用户pt,而不是 ∗ \ast ∗pt,因此对指针递增。然而,后缀运算符意味着将对原来的地址(&arr[2])而不是递增后的新地址解除引用,因此 ∗ \ast ∗pt++的值为arr[2],即25.4,当该语句执行完毕后,pt的值将为arr[3]。
C++有一种合并加法和赋值的运算符:
i += by;
int pa[3] = {1,2,3};
pa[1] += 1;
*(pa + 1) += 2;
pa += 1;
组合赋值运算符
| 操作符 | 作用(L为左操作数,R为右操作数)|
|—|
| += | L+R赋给L |
| -= | L-R赋给L |
| ∗ \ast ∗= | L ∗ \ast ∗R赋给L |
| /= | L/R赋给L |
| %= | L%R赋给L |
int sum = 0;
int number;
for (int i =1; i <= 5; i++)
{
cout << "Value: " << i << ": ";
cin >> number;
sum += number;
}
编译器将忽略缩进,因此需要使用花括号来说明是for中的语句块。如果在语句块中定义一个新的变量,则仅当程序执行该语句块中的语句时,该变量存在。执行完该语句块,变量将被释放。
注意,在外部定义的变量,在语句块内部也是被定义了。
语句块允许把两条或更多条语句放到按C++句法只能放到一条语句的地方。逗号运算符对表达式完成同样的任务,允许将两个表达式放到C++句法只允许放一个表达式的地方。例如:假设有一个循环,每轮都将一个变量加1,而另一个变量减1:
++j,--i
逗号并不总是逗号运算符,例如,下面这个声明中的逗号将变量列表中的相邻的名称分开:
int i, j;
实现将一个string类对象的内容反转。
forstr2.cpp
#include
#include
using namespace std;
int main()
{
cout << "Enter a word: ";
string word;
cin >> word;
char temp;
int i,j;
for(j = 0, i = word.size() - 1; j < i; --i, ++j)
{
temp = word[i];
word[i] = word[j];
word[j] = temp;
}
cout << word << endl;
return 0;
}
结果:
Enter a word:
animal
lamina
注意声明i,j的位置在循环之前,因为不能用逗号运算符将两个声明组合起来。这是因为声明已经将逗号用于其他用途–风格列表中的变量。也可以使用一个声明语句表达式来创建并初始化两个变量,但这样看起来有点乱:
int j = 0, i = word.size() - 1;
在这种情况下,逗号只是一个分隔符。
如果在for内部声明temp:
char temp = word[i];
这样,temp在每轮循环中都将被分配和释放,这比在循环外声明temp的速度慢一些。另一方面,如果在循环内部声明,则它将在循环结束后释放。
逗号运算符其他用途
i = 20, j = 2 * i //其中i=20,j=40
首先,它确保先计算第一个表达式,然后计算第二个表达式(换句话说,逗号运算符是一个顺序点)。其次C++规定,逗号表达式的值是第二部分的值。例如,上面表达式的值为40,因为j=2 ∗ \ast ∗i的值为40。
在所有的运算符中,逗号运算符的优先级最低。例如,下面的语句:
cata = 12, 120;
被解释为:
(cata = 12), 120;
也就是说cata为12,120不起作用。然而,由于括号的优先级最高,下面的表达式:
cats = (12, 120);
将cats设置为120—逗号右侧的表达式值。
不等于: !=
等于: ==
小于等于: <=
大于等于: >=
关系运算符的优先级比算术运算符地:
x + 2 > y -2
观察下面两者的输出:
itn A[5] = {20, 20, 10, 20 ,1}
for (int i = 0 ; A[i] == 20; i++) //输出前两个20
cout << i << endl;
for (int i = 0; A[i] = 20; i++) //因为这里使用赋值,所有程序会一直输出20,导致程序崩溃
cout << i << endl;
第二个循环,一直输出20,直到程序崩溃,电脑死机。
由于C++将C-风格字符串视为地址,因此如果使用关系运算符来比较它们,将无法得到满意的结果。相反,应使用C-风格字符串库的strcmp()函数来比较。该函数接受两个字符串地址作为参数。这意味着参数可以是指针、字符串常量或字符数组名。如果两个字符串相同,则函数返回0;如果第一个字符串按字母排在第二个字符串前面,则函数返回一个负数;如果第一个字符串按字幕顺序排在第二个字符串之后,则函数返回一个正数。
实际上,”按系统排序顺序“比”按字母顺序“更准确,这意味着字符根据字符的系统编码来进行比较。例如:使用ASCII码时,所有大写字母的编码都要小于小写字母,所以按排序顺序,大写字母将位于小写字母前面。因此,字符串”Zoo“在字符串”aviary“之前。根据编码进行比较还意味着大写字母和小写字母是不同的。
虽然不能用关系运算符来比较字符串,但可以用来比较字符,因为字符实际上是整型。
for (ch = 'a'; ch <= 'z'; ch++)
cout <
compstr1.cpp
#include
#include
int main()
{
using namespace std;
char word[5] = "?ate";
for (char ch = 'a'; strcmp(word, "mate"); ch++)
{
cout << word << endl;
word[0] = ch;
}
cout << "After loop ends, word is :" << word << endl;
return 0;
}
结果:
?ate
aate
bate
cate
date
eate
fate
gate
hate
iate
jate
kate
late
After loop ends, word is :mate
如果str1和str2相等,作则下面的表达式为true:
strcmp(str1,str2) == 0
如果str1和str2不相等,则下面两个表达式都是true:
strcmp(str1,str2) != 0
strcmp(str1,str2)
如果str1在str2的前面,则下面表达式为true:
strcmp(str1,str2) < 0;
如果str在str2的后面,则下面表达式为true:
strcmp(str1,str2) > 0;
如果使用sting类字符串而不是C-字符串,比较起来简单些。
compstr2.cpp
#include
int main()
{
using namespace std;
string word = "?ate";
for (char ch = 'a'; word != "mate"; ch++)
{
cout << word << endl;
word[0] = ch;
}
cout << "After loop ends, word is :" << word << endl;
return 0;
}
string类重载运算符!=的方式可以在下面条件下使用它:至少一个操作数为string对象,另一个操作数可以是string对象,也可以是C-风格字符串。
while循环是没有初始化和更新部分的for循环,它只有测试条件和循环体:
while (test-condition)
body
首先,程序计算圆括号内的测试条件表达式,如果该表达式为true,则执行循环体中的语句。如果希望循环最终能够结束,循环体中的代码必须完成某种影响测试条件表达式的操作。
while.cpp
#include
const int ArSize = 20;
int main()
{
using namespace std;
char name[ArSize];
cout << "Your first name: ";
cin >> name;
cout << "Here is your name, verticalized and ASCIIized:\n";
int i = 0;
while(name[i] != '\0')
{
cout << name[i] << " : " << int(name[i]) << endl;
i++;
}
return 0;
}
结果:
Your first name: zxp
Here is your name, verticalized and ASCIIized:
z : 122
x : 120
p : 112
如果没有循环体中的i++来更新测试表达式的值,循环会一直停留在第一个数组元素上,导致死循环。测试条件还可以修改为:
while(name[i])
程序的工作方式不变,对于编译器生成代码的速度将更快。由于name[i]是常规字符,其值为该字符的编码–非零值或true,当name[i]为空值时,其编码值为0或false。
打印字符的ASCII码,必须通过强制类型转换将name[i]转换为整型。
在C++中,for和while循环本质上是相同的,例如:
for (init-expression; test-expression; update-expression)
{
statements
}
可以改写成:
init-expression;
while (test-expression)
{
statements
update-expression
}
两者区别:
通常,使用for循环来循环计数,因为for循环格式允许将所有相关的信息—初始值、终止值和更新计算的方式放在同一个地方。在无法预先直到循环执行次数时,使用while循环。
设计循环时,三条原则:
注意分号使用:
while (i < 10);
{
cout << i;
i++;
}
这将是一个空循环,分号将结束while循环。
有时候,让程序等待一段时间很有用。while循环可用于这个目的。早期的技术是让计算机进行计数,以等待一段时间:
long waite = 0;
while (waite < 10000)
waite++;
这种方法的问题是,当计算机处理的速度发生变化,必须修改计数限制。更好的办法是让系统时钟来往常这种工作。
C++库中有一个函数有助于完成这项工作,这个函数名叫clock(),返回程序开始执行后所用的系统时间。这有两个复杂的问题:首先,clock()返回时间的单位不一定是秒,其次,该函数的返回类型在某些系统可能是long,在另一些习俗可能是unsigned long或其他类型。
但头文件ctime(早期的time.h)提供了解决这些问题的解决方案。首先,定义一个符号常量—CLOCKS_PER_SEC,该常量等于每秒钟包含的系统时间单位数,因此系统时间除以这个值,可以得到秒数。或者将秒数乘以CLOCKS_PER_SEC,可以得到系统时间单位为单位的时间。其次,ctime将clock作为clock()返回类型的别名,这意味着可以将变量声明为clock_t类型,编译器将把它转换为long、unsigned int或适合系统的其他类型。
waiting.cpp
#include
#include
int main()
{
using namespace std;
cout << "Enter the delay time, in seconde: ";
float secs;
cin >> secs;
clock_t delay = secs * CLOCKS_PER_SEC;
cout << "starting\a\n";
clock_t start = clock();
while (clock() - start < delay);
cout << "done \a\n";
return 0;
}
结果:
Enter the delay time, in seconde: 5
starting
done
该程序以系统时间单位为单位计算延迟时间,避免了在每轮循环中将系统时间转换为秒。
类型别名
C++为类型建立别名的方式有两种。一种是使用预处理器:
#define BYTE char //注意没有分号
这样,预处理器将在编译程序时使用char替换所有的BYTE,从而使BYTE成为char的别名。
第二种方式是使用C++(和C)的关键字typedef来创建别名。例如,将byte作为char的别名,可以这样做:
typedef char byte;
要让byte_pointer成为char指针的表明,可以将byte_pointer声明为char指针,然后在前面加上关键字typedef:
typedef char * byte_pointer;
也可以使用#define,不过声明一系列变量时,这种方法不适用,例如:
#define FLOAT_POINTER float *;
FLOAT_POINTER pa pb;
预处理器置换该声明为这样:
float *pa, pb;
typedef方法不会有这样的问题。它能够处理更复杂的类型别名,这使得与使用#define相比,typedef是一种更佳的选择。
注意,typedef不会创建新类型,只是为已有的类型建立一个新名称。
编写程序对比两者:
#include
#define char_point char *
typedef char * byte_pointer;
int main()
{
using namespace std;
byte_pointer pa, pb;
cout << "typedef: \n";
cout << sizeof(pa) << endl;
cout << sizeof(pb) << endl;
char_point pc, pd;
cout << "#define:\n ";
cout << sizeof(pc) << endl;
cout << sizeof(pd) << endl;
return 0;
}
结果:
typedef:
8
8
#define:
8
1
do while循环不同于介绍过的两种循环,因为它是出口条件循环,即这种循环将首先执行循环体,然后判定测试表达式,决定是否应该继续执行循环。句法如下:
do
body
while (test-expression);
通常,入口条件循环比出口条件循环好,因为入口条件循环在循环开始之前对条件进行检查。但有时do while测试更合理,例如,请求用户输入时,程序必须先获取输入然后对它进行测试。
dowhile.cpp
#include
using namespace std;
int main()
{
int n;
cout << "Enter number: ";
do{
cin >> n;
} while(n != 7);
cout << "Yes, 7 is my favorite.\n";
return 0;
}
结果:
Enter number: 3
4
7
Yes, 7 is my favorite.
奇特的for循环
int i = 0;
for (;;)
{
i++;
if (30 >= i)
break;
}
另一种变体:
int i = 0;
for(;;i++)
{
if (30 >= i)
break;
}
上述代码基于这样一个事实:for循环中的空测试条件被视为true。这些例子不易于阅读,也不能用作编写循环的通用模型。第一个例子的功能在do while循环中将表达得更清晰:
int i = 0;
do{
i++
} while(i <= 30);
第二个例子使用while循环可以表达得更清晰:
while(i < 30)
{
i++;
}
基于范围的for循环,简化了一种常见的循环任务:对数组或容器类(vector或array)的每个元素执行相同的操作:
double prices[5] = {4.99, 10.99, 1.99, 7.99, 8.99};
for (double x: price)
cout << x << endl;
其中x最初表示数组price的第一个元素。显示第一个元素后,不断执行循环,而x依次表示数组的其他元素。因此,上述代码显示全部5个元素。
要修改数组的元素,需要使用不同的循环变量语法:
for (double &x : prices)
x = x * 0.80;
符号&表明x是一个引用变量。还可以结合使用基于for循环和初始化列表:
for (int x : {3, 5, 2, 6})
cout << x << " ";
cout << endl;
Linux下使用C++11编译程序(rangefor.cpp):
g++ -std=c++11 rangefor.cpp
cin对象支持3种不同模式的单字符输入,其用户接口各不相同。下面介绍while循环中使用这三种模式:
程序通过选择某个特殊的字符–哨兵字符,来作为停止表示,程序知道合适停止读取。例如下面程序遇到#字符时停止输入。
textcin1.cpp
#include
using namespace std;
int main()
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: \n";
cin >> ch;
while (ch != '#')
{
cout << ch;
++ count;
cin >> ch;
}
cout << endl << count << " characters read. \n";
return 0;
}
结果:
Enter characters, enter # to quit:
zxp is handsome # read here
zxpishandsome
13 characters read.
程序在输出时省略了空格,原因是cin在读取char值时,与读取其他类型一样,cin将忽略空格和换行。因此输入中的空格没有被回显,也没有被包括在计数内。
只有按下回车键,用户输入的内容才会被发送给程序,这就是在运行程序时,可以在#后输入字符的原因。
通常,逐个字符读取时,程序需要检查每个字符,包括空格、制表符和换行符。cin所属的istream类中包括一个能够满足这种要求的成员函数。具体说,成员函数cin.get(char)读取输入中的下一个字符(即使它是空格),并将其赋值给变量ch。
textcin2.cpp
#include
using namespace std;
int main()
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: \n";
cin.get(ch);
while (ch != '#')
{
cout << ch;
++ count;
cin.get(ch);
}
cout << endl << count << " characters read. \n";
return 0;
}
结果:
Enter characters, enter # to quit:
zxp is handosome # read here
zxp is handosome
17 characters read.
现在程序回显了每个字符,并将全部字符计算在内,其中包括空格。
cin.get(ch)调用一个值放在ch变量中,这意味着将修改该变量的值。在C语言中,要修改变量的值,必须将变量的地址传递给函数,即cin.get(&ch)。当在C++中,只要函数将参数声明为引用即可。引用是C++在C上新增的一种类型。
前面使用过:
cin.get(name, ArSize).get();
相当于两行:
cin.get(name., ArSize);
cin.get();
而本节,使用的为:
cin.get(ch);
从上面可以看出,cin.get()的参数可以为空,可以是一个char类型的变量,甚至还可以是两个参数:一个整型,一个char型。这是因为C++支持函数重载。函数重载允许创建多个同名函数,条件是它们的参数列表不同。例如:如果在C++中使用cin.get(name, Arsize),则编译器将找到使用char*和int作为参数的cin.get()版本;如果使用cin.get(ch),则编译器将使用接受一个char参数的版本。
前面的输入程序通过使用#符号来表示输入结束,这样难令人满意,因为这样的符号可能就是合法的输入的组成部分。如果输入来自一个文件,则可以使用一种功能更强大的计数—检测文件末尾(EOF)。C++输入工具和操作系统协同工作,来检测文件末尾并将这种信息告知程序。
检测到EOF后,cin将两位(eofbit和failbit)都设置为1。可以通过成员函数eof()来查看eofbit是否被设置;如果检测到EOF,则cin.eof()将返回true,否则返回false。同样,如果failbit被设置为1,则fail()成员函数返回true,否则返回false。注意:eof和fail方法报告最近读取的结果;即它们事后报告,而不是预先报告,因此应当cin.eof()或cin.fail()测试应放在读取后。一般使用fail(),其可用于更多的实现中。
textcin3.cpp
#include
using namespace std;
int main()
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: \n";
cin.get(ch);
while (cin.fail() == false)
{
cout << ch;
++ count;
cin.get(ch);
}
cout << endl << count << " characters read. \n";
return 0;
}
结果:
Enter characters, enter # to quit:
yes yes it is very good
yes yes it is very good
no no i don't agree
no no i don't agree
//此处使用快捷键ctrl+d(Linux系统),windows系统使用Ctrl+z
44 characters read.
注意:Windows下面Ctrl+z就相当于EOFLinux下面Ctrl+d相当于EOF。
1. EOF结束输入
cin方法检测到EOF时,将设置cin对象中一个指示EOF条件的标记。设置这个标记后,cin将不读取输入,再次调用cin也不管用。对于文件输入是有道理,因为程序不应读取超出文件末尾的内容。
然而对于键盘输入,有可能使用模拟EOF来结束循环,但稍后要读取其他输入,cin.clear()方法可能清除EOF标记,使输入继续进行。不过在某些系统中(比如:Linux),输入快捷键将结束输入和输出,而cin.clear()将无法恢复输入和输出。
2. 常见的字符输入做法
cin.get(ch);
while (cin.fail() == false)
{
cout << ch;
++ count;
cin.get(ch);
}
可以将上述代码使用一些简洁方式。!运算符将true切换为false或将false切换为true。比如:
while (!cin.fail())
方法cin.get(char)的返回值是一个cin对象。然而,istream类提供了一个可以将istreamd对象(cin)转换为bool值得函数;但cin出现在需要是bool值得地方(while循环得测试条件中)时,该转换函数被调用。意味着可以改写为:
while (cin)
这比cin.eof()和cin.fail()更通用,因为cin还可以检测到其他失败的原因,比如磁盘故障。
最后,由于cin.get(char)的返回值为cin,因此可以将循环简写为:
while (cin.get(ch))
{}
这样,cin.get(char)只被调用一次,而不是两次:循环前一次,循环后一次。为判断循环测试条件,程序必须先调用cin.get(ch),如果成功,则将值放入ch中,然后,程序获得函数的返回值,即cin。接下来,程序对cin进行bool转换,如果输入成功,则结果为true,否则为false。
C语言中字符I/O函数–getchar()和putchar(),它们仍旧适用,只要包含头文件stdio.h(或cstdio)即可。也可以使用istream和iostream中类似的成员。
不接受任何参数的cin.get()成员函数将返回输入中的下一个字符:
int ch;
ch = cin.get();
该函数的工作方式与C语言中getchar()相似,将字符编码作为int值返回,而cin.get(ch)返回一个对象,而不是读取的字符。同样,可以使用cout.put()函数来显示字符:
cout.put(ch);
该函数的工作方式与C语言中的putchar()类似,只不过其参数类型为char,而不是int。C++实现提供了三种原型:put(char),put(signed char),put(unsigned char)。给put一个int类型将导致错误类型,但可以通过强制类型转换实现:cin.put(char(ch))。
当函数到达EOF时,cin.get()将返回一个符号常量EOF表示的特殊值。该常量是在头文件iostream中定义的。通常,EOF被定义为-1,但没必要知道实际值,而必需在程序中使用EOF即可。
cin.get(ch);
while (ch != EOF)
{
cout << ch;
++ count;
cin.get(ch);
}
由于EOF表示的不是有效字符编码,因此可能不与char类型兼容,例如:在有些系统中,char类型是没有符号的,因此char变量不可能为EOF值(-1)。由于这种原因,如果使用cin.get()并测试EOF,则必须将返回值赋给int类型,而不是char类型。但是,如果将ch的类型声明为int,而不是char,则必须在显示ch时强制转换为char类型。
textcin5.cpp
#include
using namespace std;
int main()
{
int ch;
int count = 0;
while ((ch = cin.get()) != EOF)
{
cout.put(ch);
count++;
}
cout << endl << count << " characters read.\n";
return 0;
}
结果:
the smalller
the smalller
good boy
good boy
//按下快捷键ctrl+d
22 characters read.
循环条件,如果写成如下形式:
while ( ch = cin.get() != EOF)
由于!=的优先级高于=,因此程序首先对cin.get()的返回值和EOF进行比较。比较的的结果为false或true,而这些bool值被转换为0或1,并赋值给ch。
ch=cin.get()和cin.get(ch)的区别
| 属性 | cin.get(ch) | ch = cin.get() |
|—|
| 传递输入字符的方式 | 赋给参数ch | 将函数返回值赋给ch |
| 用于字符输入时函数的返回值 | istrem对象(执行bool转换后为true) | int类型的字符编码 |
| 达到EOF时函数的返回值 | istream对象(执行bool转换后为false) | EOF |
cin.get(ch1).get(ch2)
这是可行的,因为函数cin.get(ch1)返回一个cin对象,然后便可以通过该对象调用get(ch2)。
二维数组的声明如下:
int maxtemps[4][5];
该声明意味着maxtemps是一个包含4个元素的数组,其中每个元素都是一个由5个整数组成的数组。表达式maxtemps[0]是maxtemps数组e第一个元素,因此maxtemps[0]本身就是一个由5个int组成的数组。maxtemps[0]数组的第一个元素是maxtemps[0][0],该元素是int元素。可以认为第一个下标表示行,第二个下标表示列。
假设要打数组的所有内容:
for (int row = 0; row < 4; row++)
{
for (int col = 0; col < 5; col++)
cout << maxtemps[row][col] << "\t";
cout << endl;
}
创建二维数组时,可以初始化其所有元素:
int maxtemps[4][5] =
{
{1,2,3,4,5},
{2,3,4,5,6},
{3,4,5,6,7},
{4,5,6,7,8},
};
nested.cpp
#include
using namespace std;
const int Cities = 5;
const int Years = 4;
int main()
{
const char * cities[Cities] =
{
"Griblle",
"Gribbletown",
"New Gribble",
"San Gribble",
"Gribble Vista"
};
int maxtemps[Years][Cities] =
{
{1,2,3,4,5},
{2,3,4,5,6},
{3,4,5,6,7},
{4,5,6,7,8},
};
cout << "Maximum tempeartures for 2008-2011\n";
for (int city = 0; city < Cities; city++)
{
cout << cities[city] << ": \t";
for (int year = 0; year < Years; year++)
cout << maxtemps[year][city] << "\t";
cout << endl;
}
return 0;
}
结果:
Maximum tempeartures for 2008-2011
Griblle: 1 2 3 4
Gribbletown: 2 3 4 5
New Gribble: 3 4 5 6
San Gribble: 4 5 6 7
Gribble Vista: 5 6 7 8
C++提供三种循环:for循环、while循环和do while循环。