今天时间上传时间有点晚,原因是理解书中其中程序费了不小时间。这一章后面又是关于文件的简单输出输入,学C的时候这一部分没多大学,所以是完全是陌生的,也费了点时间。
2011-10-04(Branching Statements and Logical Operations)
1、value == variable和variable == value。以前看到过在优快云论坛java板块上有个帖子问这两种形式有什么区别。理论上,二者没任何区别,前提是你书写正确。假设把“==”误写成“=”,当然这个假设有点无理:在写错的情况下,什么事情都有可能发生,能把所有的后果都讨论完,然后说有什么区别?好了,再来看这个假设,前者value = variable编译器是报错的,后者variable = value返回的是等号左边的值。C++中,如果value等于零,恒为false;如果value不等于零,恒为true,这往往与程序员的愿意相反,比如:
int num = 3;
if(num == 4)cout << "true";
else cout << "false";
“==”情况下,正常。而如果写成“=”,那么,无论num等于什么,总是打印true,而编译器是不会报错的。所以在C++环境下,还是采用value == variable的形式,为自己可能的粗心提个醒。java环境下,两者形式皆好,根据习惯,因为if语句里面不允许除boolean型数据外的其他类型。2、逻辑操作符的一些事项。
① OR和AND运算优先级都低于关系操作符;
②NOT优先级高于所有关系操作符合算术操作符;
③AND优先级高于OR。不过为了清晰明了,必要的时候加上括号;
④从左往右计算逻辑表达式,如此某些情况下可以减少运算次数;
⑤在有头文件 ciso646 情况下,可用 and 、 or 和 not 代替 &&、|| 和 ! 。
3、输入异常处理。试想,如果一个程序要你输入整型,你却输入了一个字符,会发生错误。如果要避免这种情况,一般的做法是将输入的数据进行判断,确定为所要类型后再使用。这个方法有两个问题:①判断是有判断的对象,这个对象就是储存了数据的变量。好,既然可能是出现多种类型,程序应该拿什么类型的变量接收数据以适应所以可能的类型呢?②判断的准则不清。也就是说:
typeName temp; //What is the typeName?
cin >> temp;
if(test-expression) //What is the test-expression
{ /*show error info */}
幸运的是,以
cin
为中心的输入函数在输入数据不正确的情况下,可以返回一个
bool
型数据:输入数据格式正确,可返回
true
,否则为
false
。I、输入类型测试。现已学的的输入函数有:
cin >> variable; //接收各种类型数据
cin.get()或cin.get(char); //接收单个字符、字符串
cin.getline(); //接收字符串
getline(cin,string); //string对象接收字符串
可以借助下列测试程序测试:
#include <iostream>
int main()
{
using namespace std;
int a ; //a可以是任意类型
if(!(cin >> a))
cout << "Wrong data\n";
else
cout << "Right data: " << a << endl;
return 0;
}
下面是测试结果(约定:(
int,float
)=1表示,a的类型是,float是输入类型或者是具体数据,1表示输入数据正确,0表示不正确):①如果a是整型或浮点,只要输入数据不是字符(非数字类型字符)、字符串(没有数字前缀)、EOF或超过该类型可储存的最大值,打印Right data。如( int, char )=0,( int, string )=0,( int, "56aba" )=1,( int, double )=1,( unsigned int, -2 )=1,后面两种情况数据会丢失:前者,小数部分被截去;后者, a = INT_MAX - 2 - 1 。
②如果a是 char、string或char[] ,除EOF外的任何数据都打印Right data。对于 char 型,总是取输入数据的头个字符。如( char, 5.6 ),a='5';( char, "abc" ),a='a';
③如表:
函数\类型 | int | float | char | string | EOF(CTRL+Z) |
cin.get() | Right data | Right data | Right data | Right data | Wrong data |
cin.getline() | Right data | Right data | Right data | Right data | Wrong data |
getline(cin,string) | Right data | Right data | Right data | Right data | Wrong data |
上述结论中用得最多的是:( int, char )和( int, int )之间的关系,以及(anyType, EOF)=0。
II、实例(来自教材)。功能是输入5个 int 值,并输入平均值。如果输入的有字符串,即要求重新输入。
#include <iostream>
const int Max = 5;
int main()
{
using namespace std;
int golf[Max];
cout << "Please enter your golf scores.\n";
cout << "You must enter " << Max << " rounds.\n";
int i;
for (i = 0; i < Max; i++)
{
cout << "round #" << i+1 << ": ";
while (!(cin >> golf[i]))
{
cin.clear();
while(cin.get() != '\n');
cout << "Please enter a number: ";
}
}
// calculate average
double total = 0.0;
for (i = 0; i < Max; i++)
total += golf[i];
// report results
cout << total / Max << " = average score "<< Max << " rounds\n";
return 0;
}
一次输入输出如下:
Please enter your golf scores.
You must enter 5 rounds.
round #1: 89
round #2: 90
round #3: 76
round #4: right?
Please enter a number: 90
round #5: 80
85 = average score 5 rounds
由于 while(!(cin >> golf[i])) 中的条件语句是顺序点,必须完成条件语句中的所有表达式才能进行判断。在输入 int 型的情况下, !(cin >> golf[i])=false ,循环不执行。输入的是字符串(或者字符)执行循环,循环的第一条语句是 cin.clear() ,其作用是恢复 cin 正常输入功能,即 cin 在读取输入流中非正常数据后,“安抚” cin 受伤的心灵,让她重新投入读取工作。
第十六行: while(cin.get() != '\n') ;是关键,作用是去除错误数据。比如此例。非正常数据是:'r''i''g''h''t''?'这五个字符通过循环做一定次数(次数由'\n'决定)地字符读取操作 cin.get() ,使垃圾数据从输入流中消失(字符被 cin.get() 读取即视为消失)。
当然这个程序还有不足之处,如果输入的是浮点或是56ac等有数字前缀的字符串时,会发生错误:
Please enter your golf scores.
You must enter 5 rounds.
round #1: 56.5
round #2: Please enter a number: 56abc
round #3: Please enter a number: 56
round #4: 56
round #5: 56
56 = average score 5 rounds
原因是, cin >> glof[i] 读取56.6或56abc都是正常,没有执行循环语句。但golf[i]只读取了一部分,剩下的(56.6剩下".6";56abc剩下"abc")留给了 cin >> golf[i+1] ,数据不合法,执行循环,把不合法数据去除,之后执行第17行。也就是说 “round #2:” 和 “56abc”之间已经在后台执行循环了,当然这个循环并没有为golf数组输入数据,只留下一句话,对后面的平均值无影响。从程序的健壮性来说,"56.6"、"56abc"都是非法数据,应该被去除而不是被程序读取。
III、总结。从前面 cin 表现的一些性质看, cin 是个千方百计使得数据合法的家伙。就算要的是整型,而输入的是浮点,它都要把"点"和"小数"留在输入流中,自己只读取整数部分。以后在解释一些现象的时候要以这个为原则。
4、cout的关于精度新参数。就像 cout << hex 一样,可以通过相应的设置控制浮点型数据的现实。从网上看到一篇介绍,挺好,复制粘贴过来了:
#include <iostream>
#include <iomanip>
using namespace std;
int main( void )
{
const double value = 12.3456789;
cout << value << endl; // 默认以6精度,所以输出为 12.3457
cout << setprecision(4) << value << endl; // 改成4精度,所以输出为12.35
cout << setprecision(8) << value << endl; // 改成8精度,所以输出为12.345679
cout << fixed << setprecision(4) << value << endl; // 加了fixed意味着是固定点方式显示,所以这里的精度指的是小数位,输出为12.3457
cout << value << endl; // fixed和setprecision的作用还在,依然显示12.3457
cout.unsetf( ios::fixed ); // 去掉了fixed,所以精度恢复成整个数值的有效位数,显示为12.35
cout << value << endl;
cout.precision( 6 ); // 恢复成原来的样子,输出为12.3457
cout << value << endl;
}
地址:戳之5、简单的文件I/O。文件的输出和输入与 cout 、 cin 对应。
I、输出。先给一个例子:
#include <iostream>
#include <fstream>
int main()
{
using namespace std;
ofstream outFile;
char path[10] = "test.txt";
outFile.open(path); //or outFile.open("test.txt")
outFile << "离散数学\n";
outFile << "計算機圖形學";
outFile.close();
return 0;
}
结果是在当前文件夹创建了test.txt文件,并有相应内容。步骤:
①包含头文件 fstream (第2行);
②创建一个 ofstream 对象(第7行,所创建的对象相等于 cout ,同样需要名称空间std);
③将该 ofstream 对象同一个文件关联起来(第9行)。通常使用 open() 。函数 open() 接收一个字符串,可以字符数组,也可以是 string 对象;
④像使用 cout 一样使用 ofstream 对象(第10-11行)。
II。输入。输入对应于cin,与输出一样需要创建一个 ifstream 对象,而后对这个对象进行与cin相似的操作。输入涉及到多个问题:所要打开文件是否存在、所读取数据是否合法、什么时候停止读取等。
①检验文件是否存在用is_ open() 方法,文件不存在时,返回 false ;
②检验数据的合法性:使用 good() 方法,配合 fail() 使用。
③检验文件末尾: eof() 或者 fail() 。
假设文件test.txt包含数据:45 55 89 45 ch 60
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
int main()
{
using namespace std;
int count = 0, value, sum = 0;
ifstream inFile;
string path = "test.txt";
inFile.open(path);
if(!inFile.is_open())
{
cout << "Could not open the file " << path << endl;
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
inFile >> value;
while(inFile.good())
{
count++;
sum += value;
inFile >> value;
}
if(inFile.eof())cout << "End-Of-File\n";
else if(inFile.fail()) cout << "Data Not Match\n";
else cout << "Unknow Reason of stopping reanding\n";
cout << "The number of data in this file: " << count << endl;
cout << "Sum: " << sum << endl;
cout << "Average: " << double(sum)/count << endl;
inFile.close();
return 0;
}
输出:Data Not Match
The number of data in this file: 4
Sum: 234
Average: 58.5
①头文件 cstdlib 用于支持程序的第17行,当 is_open() 返回 true 时,执行 exit(EXIT_FAILURE) ,退出程序;
②第20行, good() 用于读取数据是否正常;
③26、27行, eof() 只能判断是否达到EOF, fail() 可以检查EOF和类型不匹配。