

本章内容包括:
• for循环。
• 表达式和语句。
• 递增运算符和递减运算符:++和−−。
• 组合赋值运算符。
• 复合语句(语句块)。
• 逗号运算符。
• 关系运算符:>、>=、==、<=、<和!=。
• while循环。
• typedef工具。
• do while循环。
• 字符输入方法get()。
• 文件尾条件。
• 嵌套循环和二维数组。
C-风格字符串的比较:
#include <iostream>
int main() {
using namespace std;
char word[] = "mate";
bool b = word == "mate";
cout << (int*)word << " " << (int*)"mate" << endl;
cout << b;
return 0;
}
####运行结果#####
00AFF6F4 00479B30
0
以上第五行代码并不能像我们预想的那样工作。
请记住,数组名是数组的地址。同样,用引号括起的字符串常量也是其地址。因此,上面的关系表达式不是判断两个字符串是否相同,而是查看它们是否存储在相同的地址上。两个字符串的地址是否相同呢?答案是否定的,虽然它们包含相同的字符。
可以用strcmp(str1, str2)函数来进行比较,它是按字母表逐一比较,返回0说明str1与str2内容相同,返回-1说明str1<str2,返回正整数说明str1>str2。
用string类字符串,就能直接用==、!=比较:
string s1 = "hello";
string s2 = "hello";
string s3 = "world";
s1==s2; // true
s1==s3; // false
s1!=s3; // true
创建延迟循环clock():
ANSI C和C++库中有一个函数有助于完成这样的工作。这个函数名为clock( ),返回程序开始执行后所用的系统时间。这有两个复杂的问题:首先,clock( )返回时间的单位不一定是秒;其次,该函数的返回类型在某些系统上可能是long,在另一些系统上可能是unsigned long或其他类型。但头文件ctime(较早的实现中为time.h)提供了这些问题的解决方案。首先,它定义了一个符号常量:CLOCKS_PER_SEC,该常量等于每秒钟包含的系统时间单位数。因此,将系统时间除以这个值,可以得到秒数。或者将秒数乘以CLOCKS_PER_SEC,可以得到以系统时间单位为单位的时间。其次,ctime将clock_t作为clock( )返回类型的别名,这意味着可以将变量声明为clock_t类型,编译器将把它转换为long、unsigned int或适合系统的其他类型。
#include <iostream>
#include <ctime> // describes clock() function, clock_t type
int main(){
using namespace std;
cout << "Enter the delay time, in seconds: ";
float secs;
cin >> secs;
clock_t delay = secs * CLOCKS_PER_SEC; // convert to clock ticks
cout << "starting\a\n";
clock_t start = clock();
while (clock() - start < delay) // wait until time elapses
;
cout << "done \a\n";
return 0;
}
Enter the delay time, in seconds: |5
starting
done
输入5,5秒后,输出“done”。该程序以系统时间单位为单位(而不是以秒为单位)计算延迟时间,避免了在每轮循环中将系统时间转换为秒。
循环和文本输入:
使用原始的cin及cin.get(char)进行:
#include <iostream>
int main() {
using namespace std;
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin >> ch;【换成cin.get(ch);可读取空格】 // get a character
while (ch != '#') {
cout << ch;
++count;
cin >> ch;【换成cin.get(ch);】 // get the next character
}
cout << endl << count << " characters read\n";
while (cin.get() != '\n') // 去掉剩余的line
;
return 0;
}
Enter characters; enter # to quit:
|see ken run#really fast
seekenrun /* 空格符没有了!*/
9 characters read
上面的做法合情合理。但为什么程序在输出时省略了空格呢?原因在cin。读取char值时,与读取其他基本类型一样,cin将忽略空格和换行符。因此输入中的空格没有被回显,也没有被包括在计数内。同时也说明:cin>>不仅可以读入到字符数组还可以按字符一一读入。
更为复杂的是,发送给cin的输入被缓冲。这意味着只有在用户按下回车键后,他输入的内容才会被发送给程序。这就是在运行该程序时,可以在#后面输入字符的原因。按下回车键后,整个字符序列将被发送给程序,但程序在遇到#字符后将结束对输入的处理。
通过调试也可证实上述说法,while循环外的cin >> ch;从键盘输入后,接着执行while循环,断点调试其中ch从未等于空格符,说明缓冲区字符是seekenrun#reallyfast,空格确实被忽略掉了,然后while循环内的cin >> ch;只是从缓冲区读取字符,读到#号结束循环。最后的while循环依次读取完了#号后面的所有字符reallyfast,结束此循环,程序结束。
使用cin.get(char)进行补救:通常,逐个字符读取输入的程序需要检查每个字符,包括空格、制表符和换行符。cin所属的istream类(在iostream中定义)中包含一个能够满足这种要求的成员函数。具体地说,成员函数cin.get(ch)读取输入中的下一个字符(即使它是空格),并将其赋给变量ch。使用这个函数调用替换cin>>ch,可以解决上面程序的问题。如果要控制输入字符数,可以使用cin.get(name, ArSize);
文件结尾条件:
使用诸如#等符号来表示输入结束很难令人满意,因为这样的符号可能就是合法输入的组成部分,其他符号(如@和%)也如此。如果输入来自于文件,则可以使用一种功能更强大的技术—检测文件尾(EOF)。C++输入工具和操作系统协同工作,来检测文件尾并将这种信息告知程序。检测EOF时将关闭对输入的进一步读取。
乍一看,读取文件中的信息似乎同cin和键盘输入没什么关系,但其实存在两个相关的地方。首先,很多操作系统(包括Unix、Linux和Windows命令提示符模式)都支持重定向,允许用文件替换键盘输入。例如,假设在Windows中有一个名为gofish.exe的可执行程序和一个名为fishtale的文本文件,则可以在命令提示符模式下输入下面的命令:
gofish < fishtale
很多操作系统都允许通过键盘来模拟文件尾条件。在Unix中,可以在行首按下Ctrl+D来实现;在Windows命令提示符模式下,可以在任意位置按Ctrl+Z + Enter。有些C++实现支持类似的行为,即使底层操作系统并不支持。键盘输入的EOF概念实际上是命令行环境遗留下来的。然而,用于Mac的Symantec C++模拟了UNIX,将Ctrl+D视为仿真的EOF。Metrowerks Codewarrior能够在Macintosh和Windows环境下识别Ctrl+Z。用于PC的Microsoft Visual C++、Borland C++ 5.5和GNU C++ 都能够识别行首的Ctrl + Z,但用户必须随后按下回车键。总之,很多PC编程环境都将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( )测试放在读取后,下面的程序中的设计体现了这一点。它使用的是fail( ),而不是eof( ),因为前者可用于更多的实现中。
#include <iostream>
int main() {
using namespace std;
char ch;
int count = 0;
cin.get(ch);
while (cin.fail() == false) { // test for EOF(放在读取后!)
cout << ch;
++count;
cin.get(ch);
}
cout << endl << count << " characters read\n";
return 0;
}
|The green bird sings in the winter.<Enter>
The green bird sings in the winter.
|Yes, but the crow flies in the dawn.<Enter>
Yes, but the crow flies in the dawn.
^Z<Enter>
73 characters read
^Z是从键盘<Ctrl>+<Z>完成的。统计出的73个字符是包含<Enter>换行符'\n'的,但不包含^Z<Enter>(EOF)。之所以后面有个换行就是因为最后按下<Enter>键换的行。
通过调试发现:在另起的新行<Ctrl>+<Z>+<Enter>后,while里面的cin.get(ch);并未执行而是程序直接cin.fail()==false,跳出while循环。这也是^Z<Enter>不被统计字符的根本原因。下面是另在^Z后追加字符,结果可想而知是不被统计进去的。^Z不在开头会当作特殊字符处理。
|abc<Enter>
abc
|^Zdef<Enter>
4 characters read
'a'、'b'、'c'、'\n'共4个字符。方法cin.get(char)的返回值是一个cin对象。然而,istream类提供了一个可以将istream对象(如cin)转换为bool值的函数;当cin出现在需要bool值的地方(如在while循环的测试条件中)时,该转换函数将被调用。另外,如果最后一次读取成功了,则转换得到的bool值为true;否则为false。这意味着可以将上述while测试改写为这样:
while(cin) // while input is successful
这比!cin.fail()或!cin.eof()更通用,因为它可以检测到其他失败原因,如磁盘故障。
文本文件输入:
如果要对一个两行文本的文件stuff进行读取、回显和计算字符($是Unix提示符,上面程序文件名为textin.cpp):
$ textin < stuff
I am a Unix file. I am proud
to be a Unix file.
48 characters read
$
在C中:
int getchar(): 该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
int putchar(int char): 该函数以无符号 char 强制转换为 int 的形式返回写入的字符,如果发生错误则返回 EOF。
在C++中:
int cin.get(): 用于输入流,读入一个字符并返回它的值。
ostream& cout.put(char ch): 用于输出流,并把字符ch写入流中。
#include <iostream>
int main(void) {
using namespace std;
int ch; // should be int, not char
int count = 0;
while ((ch = cin.get()) != EOF) { // test for end-of-file
cout.put(char(ch));
++count;
}
cout << endl << count << " characters read\n";
return 0;
}
|abc<Enter>
abc
|def<Enter>
def
^Zxyz<Enter>
8 characters read
本文深入探讨C++中的循环结构,包括for、while和do-while循环,以及递增和递减运算符的使用。同时,详细解析C++中的输入输出方法,如cin、cin.get()和文件输入输出,特别关注字符输入方法get()和文件尾条件的处理。文章还介绍了如何使用C++标准库函数clock()创建延迟循环。
3186

被折叠的 条评论
为什么被折叠?



