outData.open (“results.dat”) ;
这两个都是函数调用,在每个函数调用中,自变量是一个用引号括起来的直接串。第一条语句是一个对名为open函数的调用,这个open与ifstream 数据类型联系在一起,第二条语句是对另一个与ofstream联系在一起的函数(也称为open函数)的调用,就像我们早已经看到的那样,我们使用点标记(如inData .open)来调用与数据类型紧密相联系的某种库函数。
我们的第一个函数调用在流变量inDate与名为Walk.dat的实际磁盘文件之间产生联系,类似的,第二函数调用将流变量outData与磁盘文件result.dat联系在一起。将一个程序的文件(outData)名字和实际的文件(result.dat)名字联系在一起与将一个程序的标准输出设备(cout)名和实际设备(屏幕)联系在一起是非常相同的。
接下来open函数要做的事情取决于文件是一个输入文件还是一个输出文件。具有一个输入的文件,open函数设置文件的读标记到文件中的第一个数据块。
具有一个输出的文件,open函数检查看看文件是否已经存在,如果文件不存在,open为你建立一个新的空文件。如果 文件已经存在,open擦除旧的文件内容,然后在空文件的开始建立写标记器,当输出进行时,每个相继的输出操作,推进写标记器增加数据到文件的末尾。 : int main( ) {
: } 声明 // 打开文件
inData .open(\; outData .open(\; : }
在输入/输出语句中指定文件流
为了使用文件,我们只有一件事要做,就像前面我们说的那样,所有的istream操作对ifstream类型也是有效的,所有的ostream操作对ofstream类型也是有效的。所以,对文件的读或写,在我们的输入和输出语句中,我们需要做的所有事是用适当的文件流变量替代cin或cout。在我们的Walk程序中,我们将使用一条像这样的语句:
inData>>distance1>> distance2>> distance3>> distance4>> scale ;
引导计算机从文件inData中读数据,而不是从cin中读数据。累似地,所有写到文件outData 的输出语句指定到outData而不是cout。如
outData << ”Total mileage for the day is”<< totMiles<< ”miles” << endl ; 使用文件的程序例子
重新设计Walk程序如下所示,现在从文件inData读它的输入并且将它的输出写到文件outData。将这个程序与第100页的原版程序比较,注意,由于数据现在是在执行时间输入,所以名字常量被取消。还要注意设置浮点输出格式,fixed、showpoint和setprecision控制符被应用到outData流变量,不是cout。 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * // Walk 程序
// 这个程序是计算一个城市中四个点之间距离的英里数(近似到一英里 // 的十分之一)
// 按一定比例给出一个地图上的测量值,这个测量值也是输入的 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * #include
#include
#include
float distance1; // 第一个距离的测量值 float distance2; // 第二个距离的测量值 float distance3; // 第三个距离的测量值 float distance4; // 第四个距离的测量值 float scale; // 地图比例 (每英寸英里) float totMiles; // 总的近似英里数 float miles; // 分别的近似英里数
ifstream inData; // 控制以英寸表示的地图距离 ofstream outData; // 控制以英里表示的实际距离 outData << fixed << showpoint // 设置浮点显示 << setprecision(1) ; // 输出格式 // 打开文件
inData .open ( \; outData .open( \; // 获取数据
inData >> distance1 >> distance2 >> distance3 >> distance4 >> scale; // 初始化总的英里 totMiles = 0.O;
// 计算地图上每个距离的英里
miles = float(int(distance1 * scale * 1O.0 + 0.5))/ O.0; outData << \ << \ << \; totMiles = totMiles + miles;
miles = float(int(distance2 * scale * 1O.0 + 0.5))/ 1O.O; outData << \ << \ << \; totMiles = totMiles + miles;
miles = float(int(distance3 * scale * 1O.0 + 0.5))/ 1O.0; outData << \ << \ << \; totMiles = totMiles + miles;
miles = float(int(distance4 * scale * 1O.0 + 0.5))/1O.0: outData << \ << \ << \; totMiles = totMiles + miles;
// 打印总的英里 outData << endl;
outData << \ << \; return O; }
在运行程序之前,你应该使用编辑器建立并保存一个名为Walk.dat的文件作为输入,文件内容可以像这样: 1.5 2.3 5.9 4.0 0.25
运行时输入文件名
直到现在,我们打开用于输入的文件例子已经包含了类似于下列的代码 ifstream inFile ;
inFile .open (“datafile.dat”) ; : :
open函数与ifstream数据类型联系在一起,需要一个自变量来指定磁盘上实际数据文件名,就像上面的例子一样直接使用字符串名,文件名在编译时被修改,因而,程序只能对这个特定的磁盘文件操作。 我们常希望程序更灵活,允许文件名在运行时决定。一般的技巧是,提示用户要使用的文件名,将用户的响应读到变量中,然后将变量作为自变量传送到open函数。原则上,下列代码应该完成我们所要的任务,不幸的是,编译器不允许它。 ifstream inFile ; string filename ;
cout<<”Enter the input file name” ; cin >>filename ;
inFile.open(filename) ; //编译时出错
问题出在open函数不希望一个string 类型的自变量出现,而是希望一个C串出现。一个C串是一个被限制了的串的形式,它的性能在这本书的很后面讨论。一个直接串,如“datafile.dat”, 是以C串出现,这个串作为自变量送到open函数是可接受的。
为了使上面的代码正确,我们需要将串变量转换成一个C串。串数据类型提供了一个名为c_str的有返回值的函数,这个函数应用一个串变量如下: filename .c_str()
这个函数返回C串,这个串等于fileNama变量中的内容,c.str函数的主要目的是允许编程者调用库函数,希望C串,而不是string串作自变量。
使用c_str函数,我们能够编码在运行时输入文件名如下所示。 ifstream infile ; string filename ;
cout<< ”Enter the input file name:” ; cin>>filename ;
inFile .open(filename.c_str()) ;
4.5 输入失效
当一个程序从键盘或一个文件输入数据时,可能会出现错误。输入操作失效是由于输入了无效的数据,在C++术语中,cin流已经进入失效状态。一旦一个流已处于输入失效状态,任何进一步的使用这个流的I/O操作都被认为是空操作——即,它们都无效。对我们来说,不幸的是,计算机不会停止程序或给出任何错
误信息。计算机只是继续执行程序,不经意地忽略掉使用那个流的每个其它的企图。
无效的数据是输入错误的最普通的原因,当你的程序输入一个int值,它只希望在输入流中找到数字,可能前面有一个正号或负号。
假设程序有int变量i , j和k ,它们的内容当前分别是10,20和30,现在程序执行下面两条语句 cin>>i >>j>>k ;
cout<< ”i :”<< ”j :”< 那么程序产生这样的输出: i:1234 j:29 k:30 让我们看看为什么。 记住,当读int或float数据时,抽取运标符>>在读到第一个与它的数据类型不相符的字符(空白字符或其它的字符)时停止,在我们的例子中,对i的输入操作是成功的,计算机从输入流抽取开始4个字符,并且存储整型值1234到i中,读标记器现在是在小数点上。 1234.56 7 89 下一个(对j)的输入操作是失效的,int值不能用小数点开始。输入流现在是处于失效状态,j (20)的当前值保留不变,第三个(对k)的输入操作被忽略,第三个是我们程序中从cin读的所有剩下的语句。 另一种使流处于失效状态的方法是,试图打开一个不存在的输入文件,假设在你磁盘上有一个名为myfile.dat的数据文件,在你的程序中有下列语句: ifstream inFile ; inFile.open(“myfil.dat”) ; inFile >> i >> j >> k ; 在调用open函数中,你错误的拼写了你磁盘文件名,在运行时,企图打开文件失败,这样流文件inFile进入失败状态,接下来(对i , j和k)3个输入操作是空操作。没有发布任何错误信息,程序使用i , j 和k的(未知)内容进行计算,这些计算的结果肯定是混乱的。 第五章 条件、逻辑表达式和选择控制结构 目标: ? 能够构造一个简单的逻辑(布尔)表达式来求一个给定条件的值。 ? 能够构造一个复杂的逻辑表达式来求一个给定条件的值。 ? 能够构造一条If-Then-Else语句来完成一个指定的工作。 ? 能够构造一条If-Then语句来完成一个指定的工作。 ? 能够构造一组If嵌套语句来完成一个指定的工作。 ? 能够为一个模型确定前提条件和事后条件并使用它们执行一个算法过程。 ? 能够跟踪一个C++程序的执行。 ? 能够测试和调试一个C++ 程序。 5.1 控制流程 程序中语句执行的顺序称为控制流程。 控制流程通常是顺序执行的(见图5-1),当我们希望控制流程是非顺序的时候,我们使用控制结构,将控制流程转向指定的语句,而不是物理位置顺序接着的语句。 控制结构:用来交换正常顺序控制流的语句 选择 当我们想要计算机选择两者之一的活动时,我们使用一个选择(或分支)控制结构,我们做一个判断,声称是真还是假,如果判断是真的,计算机执行一条语句,如果为假,计算机执行是一条语句(见图5-2)。 5.2 条件和逻辑表达式 在C++中为了提出一个问题,我们使用一个判断语句。计算机求取判断语句的值,依靠某种内部条件来检查它,看它是真还是假。 布尔数据类型 在C++中,布尔数据类型是仅由两个值组成的标准类型,两个值是常量true和false。保留字bool是Bolean的缩写。布尔数据在程序中用来测试条件,以便计算机能够做出判决(具有一个选择控制结构)。 我们声明布尔类型变量与我们声明其它变量和方法一样,即写数据类型名,然而是标识符.。 bool dataOK; //如果输入数据有效为真 bool done ; //如果过程被做了为真 bool taxable ; //如果项目有销售税为真 每个bool类型变量可以包含两个值:true或fales之一,理解右边开始的true和fales不是变量名,也不是字符串是重要的,它们是C++中特殊的常量,事实上是保留字。 逻辑表达式 在C++中,判断采取逻辑表达式的形式。 一个辑表达式由逻辑值和操作组成,每个逻辑表达式有两个值:true或false之一,这里是一些逻辑表达式的例子. ? 布尔变量或常量 ? 一个表达式接着一个关系操作符再接着一个表达式 ? 一个逻辑表达式接着一个逻辑操作符再接一个逻辑表达式 让我们详细看看每一种形式: 布尔变量和常量 像我们已看到的一样,一个布尔变量是一个声明为bool类型的变量,它可包含一个true值也可包含一个false值,例如,如果dataOK是一个布尔变量,那么, dataOK = true; 是一个有效的赋值语句。 关系运算符 另一个赋一个值给布尔变量的方法是:用一个关系运算符设置这个值等于两个表达式比较的结果,关系运算符测试两个表达式值之间的关系。 让我们看一个例子,在下列程序段中,lessThan是一个布尔变量,i和j 是int变量: cin >> i >>j ; lessThan = ( i < j ); // 如果i < j赋true给lessThan 比较两个值,我们判断它们之间存在的关系(像“小于”),如果关系存在,判断为真,如果关系不存在,判断为假,这些是C++中我们可以测试的关系: 运算符 关系测试 = = 等于 != 不等于 > 大于 < 小于 >= 大于或等于 <= 小于或等于