知ing

C++语言程序设计(第4版)

郑莉、董渊、何江舟 编 / 清华大学出版社

浊晦 上传

查看本书

 第 十一 章     流类库与输入/输出

 

11-1 什么叫做流?流的提取和插入是指什么?I/O流在C++中起着怎样的作用?

 

解:

流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动,一般意义下的读操作在流数据抽象中被称为(从流中)提取,写操作被称为(向流中)插入。操作系统是将键盘、屏幕、打印机和通信端口作为扩充文件来处理的,I/O流类就是用来与这些扩充文件进行交互,实现数据的输入与输出。

 

11-2 cerr和clog有何区别?

 

解:

cerr 标准错误输出,没有缓冲,发送给它的内容立即被输出,适用于立即向屏幕输出的错误信息;clog

类似于cerr,但是有缓冲,缓冲区满时被输出,在向磁盘输出时效率更高。

 

11-3

使用I/O流以文本方式建立一个文件test1.txt,写入字符“已成功写入文件!”,用其它字处理程序(例如windows的记事本程序Notepad)打开,看看是否正确写入。

 

解:

#include <fstream.h>

void main()

{

ofstream file1("test.txt");

file1 << "已成功写入文件!";

file1.close();

}

程序运行后test1.txt的内容为:已成功写入文件!

 

11-4 使用I/O流以文本方式打开上一题建立的文件test1.txt,读出其内容显示出来,看看是否正确。

 

解:

#include <fstream.h>

void main()

{

char ch;

ifstream file2("test.txt");

while (file2.get(ch))

cout << ch;

file2.close();

}

程序运行输出:

已成功写入文件!

 

11-5 使用I/O流以文本方式打开上题建立的文件test1.txt,在次此文件后面添加字符“已成功添加字符!”,然后读出整个文件的内容显示出来,看看是否正确。

 

解:

#include <fstream.h>

void main()

{

ofstream file1("test.txt",ios::app);

file1 << "已成功添加字符!";

file1.close ();

char ch;

ifstream file2("test.txt");

while (file2.get(ch))

cout << ch;

file2.close();

}

程序运行输出:

已成功写入文件!已成功添加字符!

 

11-6

定义一个dog类,包含体重和年龄两个成员变量及相应的成员函数,声明一个实例dog1,体重为5,年龄为10,使用I/O流把dog1的状态写入磁盘文件,再声明另一个实例dog2,通过读文件把dog1的状态赋给dog2。分别使用文本方式和二进制方式操作文件,看看结果有何不同;再看看磁盘文件的ASCII码有何不同。

 

解:

以两种方式操作,程序运行结果一样,但磁盘文件的ASCII码不同,使用二进制方式时,磁盘文件的ASCII码为05 00 00 00 0A 00 00

00,使用文本方式时,磁盘文件的ASCII码为05 00 00 00 0D 0A 00 00 00,这是因为此时系统自动把0A转换为了0D 0A。

#include <fstream.h>

class dog

{

public:

dog(int weight, long days):itsWeight(weight),

itsNumberDaysAlive(days){}

~dog(){}

 

int GetWeight()const { return itsWeight; }

void SetWeight(int weight) { itsWeight = weight; }

 

long GetDaysAlive()const { return itsNumberDaysAlive; }

void SetDaysAlive(long days) { itsNumberDaysAlive = days; }

 

private:

int itsWeight;

long itsNumberDaysAlive;

};

int main() // returns 1 on error

{

char fileName[80];

 

cout << "Please enter the file name: ";

cin >> fileName;

ofstream fout(fileName);

// ofstream fout(fileName,ios::binary);

if (!fout)

{

cout << "Unable to open " << fileName << " for writing.\n";

return(1);

}

 

dog Dog1(5,10);

fout.write((char*) &Dog1,sizeof Dog1);

 

fout.close();

ifstream fin(fileName);

// ifstream fin(fileName,ios::binary);

if (!fin)

{

cout << "Unable to open " << fileName << " for reading.\n";

return(1);

}

 

dog Dog2(2,2);

 

cout << "Dog2 weight: " << Dog2.GetWeight() << endl;

cout << "Dog2 days: " << Dog2.GetDaysAlive() << endl;

 

fin.read((char*) &Dog2, sizeof Dog2);

 

cout << "Dog2 weight: " << Dog2.GetWeight() << endl;

cout << "Dog2 days: " << Dog2.GetDaysAlive() << endl;

fin.close();

return 0;

}

程序运行输出:

Please enter the file name: a

Dog2 weight: 2

Dog2 days: 2

Dog2 weight: 5

Dog2 days: 10

 

11-7 观察下面的程序,说明每条语句的作用,看看程序执行的结果。

#include <iostream>

using namespace ::std;

void main()

{

ios_base::fmtflags original_flags = cout.flags(); //1

cout<< 812<<'|';

cout.setf(ios_base::left,ios_base::adjustfield); //2

cout.width(10); //3

cout<< 813 << 815 << '\n';

cout.unsetf(ios_base::adjustfield); //4

cout.precision(2);

cout.setf(ios_base::uppercase|ios_base::scientific); //5

cout << 831.0 ;

 

cout.flags(original_flags); //6

}

 

解:

//1保存现在的格式化参数设置,以便将来恢复这些设置;

//2 把对齐方式由缺省的右对齐改为左对齐;

//3 把输出域的宽度由缺省值0改为10;

//4 清除对齐方式的设置;

//5 更改浮点数的显示设置;

//6 恢复原来的格式化参数设置。

程序运行输出:

812|813 815

8.31E+02

 

11-8 提示用户输入一个十进制整数,分别用十进制、八进制和十六进制形式输出。

 

解:

#include <iostream.h>

void main() {

int n;

cout << "请输入一个十进制整数:";

cin >> n;

cout << "这个数的十进制形式为:" << dec << n << endl;

cout << "这个数的八进制形式为:" << oct << n << endl;

cout << "这个数的十六进制形式为:" << hex << n << endl;

}

程序运行输出:

请输入一个十进制整数:15

这个数的十进制形式为:15

这个数的八进制形式为:17

这个数的十六进制形式为:f

 

11-9 编写程序实现如下功能:打开指定的一个文本文件,在每一行前加行号。

 

解:

//b.cpp

#include <fstream.h>

#include <strstrea.h>

#include <stdlib.h>

void main(int argc, char* argv[])

{

 

strstream textfile;

{

ifstream in(argv[1]);

textfile << in.rdbuf();

}

ofstream out(argv[1]);

 

const int bsz = 100;

char buf[bsz];

int line = 0;

while(textfile.getline(buf, bsz)) {

out.setf(ios::right, ios::adjustfield);

out.width(1);

out << ++line << ". " << buf << endl;

}

}

编译后运行程序b text1.txt

运行前text1.txt的内容为:

aaaaaaaaaaaa

bbbbbbbbbbbb

cccccccccccc

dddddddddddd

eeeeeeeeeeee

ffffffffffff

gggggggggggg

hhhhhhhhhhhh

运行后text1.txt的内容为:

1. aaaaaaaaaaaa

2. bbbbbbbbbbbb

3. cccccccccccc

4. dddddddddddd

5. eeeeeeeeeeee

6. ffffffffffff

7. gggggggggggg

8. hhhhhhhhhhhh

 



第 十二 章     异常处理

 

12-1 什么叫做异常?什么叫做异常处理?

 

解:

当一个函数在执行的过程中出现了一些不平常的情况,或运行结果无法定义的情况,使得操作不得不被中断时,我们说出现了异常。异常通常是用throw关键字产生的一个对象,用来表明出现了一些意外的情况。我们在设计程序时,就要充分考虑到各种意外情况,并给与恰当的处理。这就是我们所说的异常处理。

 

12-2 C++的异常处理机制有何优点?

 

解:

C++的异常处理机制使得异常的引发和处理不必在同一函数中,这样底层的函数可以着重解决具体问题,而不必过多地考虑对异常的处理。上层调用者可以在适当的位置设计对不同类型异常的处理。

 

12-3 举例throw 、try、catch语句的用法?

 

解:

throw语句用来引发异常,用法为:

throw 表达式;

例如: throw 1.0E-10;

catch语句用来处理某中类型的异常,它跟在一个try程序块后面处理这个try程序块产生的异常,如果一个函数要调用一个可能会引发异常的函数,

并且想在异常真的出现后处理异常,就必须使用try语句来捕获异常。

例如:

try{

语句 //可能会引发多种异常

}

catch(参数声明1)

{

语句 //异常处理程序

}

 

12-4

设计一个异常Exception抽象类,在此基础上派生一个OutOfMemory类响应内存不足,一个RangeError类响应输入的数不在指定范围内,实现并测试这几个类。

 

解:

源程序:

#include <iostream.h>

class Exception

{

public:

Exception(){}

virtual ~Exception(){}

virtual void PrintError() = 0;

};

class OutOfMemory : public Exception

{

public:

OutOfMemory(){}

~OutOfMemory(){}

virtual void PrintError();

};

void OutOfMemory::PrintError()

{

cout << "Out of Memory!!\n";

}

class RangeError : public Exception

{

public:

RangeError(unsigned long number){BadNum = number;}

~RangeError(){}

virtual void PrintError();

virtual unsigned long GetNumber() { return BadNum; }

virtual void SetNumber(unsigned long number) {BadNum = number;}

private:

unsigned long BadNum;

};

void RangeError::PrintError()

{

cout << "Number out of range. You used " << GetNumber() << " !\n";

}

 

void fn1();

unsigned int * fn2();

void fn3(unsigned int *);

int main()

{

try

{

fn1();

}

 

catch (Exception& theException)

{

theException.PrintError();

}

return 0;

}

unsigned int * fn2()

{

unsigned int *n = new unsigned int;

if (n == 0)

throw OutOfMemory();

return n;

}

void fn1()

{

unsigned int *p = fn2();

 

fn3(p);

cout << "The number is : " << *p << endl;

delete p;

}

void fn3(unsigned int *p)

{

long Number;

cout << "Enter an integer(0~~1000): ";

cin >> Number;

 

if (Number > 1000 || Number < 0)

throw RangeError(Number);

*p = Number;

}

程序运行输出:

Enter an integer(0~~1000): 56

The number is : 56

Enter an integer(0~~1000): 2000

Number out of range. You used 2000 !

 

 

12-5 练习使用try、catch语句,在程序中用new分配内存时,如果操作未成功,则用try语句触发一个字符型异常,用catch语句捕获此异常。

 

解:

#include <iostream.h>

void main()

{

char *buf;

try

{

buf = new char[512];

if( buf == 0 )

throw "内存分配失败!";

}

catch( char * str )

{

cout << "有异常产生:" << str << endl;

}

}

 

12-6

定义一个异常类CException,有成员函数Reason(),用来显示异常的类型,定义函数fn1()触发异常,在主函数的try模块中调用fn1(),在catch模块中捕获异常,观察程序的执行流程。

 

解:

#include <iostream.h>

class CException

{

public:

CException(){};

~CException(){};

const char *Reason() const { return "CException类中的异常。"; }

 

};

void fn1()

{

cout<< "在子函数中触发CException类异常" << endl;

throw CException();

}

void main()

{

cout << "进入主函数" << endl;

try

{

cout << "在try模块中,调用子函数" << endl;

fn1();

}

catch( CException E )

{

cout << "在catch模块中,捕获到CException类型异常:";

cout << E.Reason() << endl;

}

catch( char *str )

{

cout << "捕获到其它类型异常:" << str << endl;

}

cout << "回到主函数,异常已被处理" << endl;

}

程序运行输出:

进入主函数

在try模块中,调用子函数

在子函数中触发CException类异常

在catch模块中,捕获到CException类型异常:CException类中的异常。

回到主函数,异常已被处理

 


查看更多