?第 十一 章 ? ? 流類庫與輸入/輸出
?
11-1 什么叫做流?流的提取和插入是指什么?I/O流在C++中起著怎樣的作用?
?
解:
流是一種抽象,它負責在數(shù)據(jù)的生產(chǎn)者和數(shù)據(jù)的消費者之間建立聯(lián)系,并管理數(shù)據(jù)的流動,一般意義下的讀操作在流數(shù)據(jù)抽象中被稱為(從流中)提取,寫操作被稱為(向流中)插入。操作系統(tǒng)是將鍵盤、屏幕、打印機和通信端口作為擴充文件來處理的,I/O流類就是用來與這些擴充文件進行交互,實現(xiàn)數(shù)據(jù)的輸入與輸出。
?
11-2 cerr和clog有何區(qū)別?
?
解:
cerr 標準錯誤輸出,沒有緩沖,發(fā)送給它的內(nèi)容立即被輸出,適用于立即向屏幕輸出的錯誤信息;clog
類似于cerr,但是有緩沖,緩沖區(qū)滿時被輸出,在向磁盤輸出時效率更高。
?
11-3
使用I/O流以文本方式建立一個文件test1.txt,寫入字符“已成功寫入文件!”,用其它字處理程序(例如windows的記事本程序Notepad)打開,看看是否正確寫入。
?
解:
#include <fstream.h>
void main()
{
ofstream file1("test.txt");
file1 << "已成功寫入文件!";
file1.close();
}
程序運行后test1.txt的內(nèi)容為:已成功寫入文件!
?
11-4 使用I/O流以文本方式打開上一題建立的文件test1.txt,讀出其內(nèi)容顯示出來,看看是否正確。
?
解:
#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,在次此文件后面添加字符“已成功添加字符!”,然后讀出整個文件的內(nèi)容顯示出來,看看是否正確。
?
解:
#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類,包含體重和年齡兩個成員變量及相應(yīng)的成員函數(shù),聲明一個實例dog1,體重為5,年齡為10,使用I/O流把dog1的狀態(tài)寫入磁盤文件,再聲明另一個實例dog2,通過讀文件把dog1的狀態(tài)賦給dog2。分別使用文本方式和二進制方式操作文件,看看結(jié)果有何不同;再看看磁盤文件的ASCII碼有何不同。
?
解:
以兩種方式操作,程序運行結(jié)果一樣,但磁盤文件的ASCII碼不同,使用二進制方式時,磁盤文件的ASCII碼為05 00 00 00 0A 00 00
00,使用文本方式時,磁盤文件的ASCII碼為05 00 00 00 0D 0A 00 00 00,這是因為此時系統(tǒng)自動把0A轉(zhuǎn)換為了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 觀察下面的程序,說明每條語句的作用,看看程序執(zhí)行的結(jié)果。
#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保存現(xiàn)在的格式化參數(shù)設(shè)置,以便將來恢復(fù)這些設(shè)置;
//2 把對齊方式由缺省的右對齊改為左對齊;
//3 把輸出域的寬度由缺省值0改為10;
//4 清除對齊方式的設(shè)置;
//5 更改浮點數(shù)的顯示設(shè)置;
//6 恢復(fù)原來的格式化參數(shù)設(shè)置。
程序運行輸出:
812|813 815
8.31E+02
?
11-8 提示用戶輸入一個十進制整數(shù),分別用十進制、八進制和十六進制形式輸出。
?
解:
#include <iostream.h>
void main() {
int n;
cout << "請輸入一個十進制整數(shù):";
cin >> n;
cout << "這個數(shù)的十進制形式為:" << dec << n << endl;
cout << "這個數(shù)的八進制形式為:" << oct << n << endl;
cout << "這個數(shù)的十六進制形式為:" << hex << n << endl;
}
程序運行輸出:
請輸入一個十進制整數(shù):15
這個數(shù)的十進制形式為:15
這個數(shù)的八進制形式為:17
這個數(shù)的十六進制形式為:f
?
11-9 編寫程序?qū)崿F(xiàn)如下功能:打開指定的一個文本文件,在每一行前加行號。
?
解:
//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的內(nèi)容為:
aaaaaaaaaaaa
bbbbbbbbbbbb
cccccccccccc
dddddddddddd
eeeeeeeeeeee
ffffffffffff
gggggggggggg
hhhhhhhhhhhh
運行后text1.txt的內(nèi)容為:
1. aaaaaaaaaaaa
2. bbbbbbbbbbbb
3. cccccccccccc
4. dddddddddddd
5. eeeeeeeeeeee
6. ffffffffffff
7. gggggggggggg
8. hhhhhhhhhhhh
?
第 十二 章 ? ??異常處理
?
12-1 什么叫做異常?什么叫做異常處理?
?
解:
當一個函數(shù)在執(zhí)行的過程中出現(xiàn)了一些不平常的情況,或運行結(jié)果無法定義的情況,使得操作不得不被中斷時,我們說出現(xiàn)了異常。異常通常是用throw關(guān)鍵字產(chǎn)生的一個對象,用來表明出現(xiàn)了一些意外的情況。我們在設(shè)計程序時,就要充分考慮到各種意外情況,并給與恰當?shù)奶幚怼_@就是我們所說的異常處理。
?
12-2 C++的異常處理機制有何優(yōu)點?
?
解:
C++的異常處理機制使得異常的引發(fā)和處理不必在同一函數(shù)中,這樣底層的函數(shù)可以著重解決具體問題,而不必過多地考慮對異常的處理。上層調(diào)用者可以在適當?shù)奈恢迷O(shè)計對不同類型異常的處理。
?
12-3 舉例throw 、try、catch語句的用法?
?
解:
throw語句用來引發(fā)異常,用法為:
throw 表達式;
例如: throw 1.0E-10;
catch語句用來處理某中類型的異常,它跟在一個try程序塊后面處理這個try程序塊產(chǎn)生的異常,如果一個函數(shù)要調(diào)用一個可能會引發(fā)異常的函數(shù),
并且想在異常真的出現(xiàn)后處理異常,就必須使用try語句來捕獲異常。
例如:
try{
語句 //可能會引發(fā)多種異常
}
catch(參數(shù)聲明1)
{
語句 //異常處理程序
}
?
12-4
設(shè)計一個異常Exception抽象類,在此基礎(chǔ)上派生一個OutOfMemory類響應(yīng)內(nèi)存不足,一個RangeError類響應(yīng)輸入的數(shù)不在指定范圍內(nèi),實現(xiàn)并測試這幾個類。
?
解:
源程序:
#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 練習(xí)使用try、catch語句,在程序中用new分配內(nèi)存時,如果操作未成功,則用try語句觸發(fā)一個字符型異常,用catch語句捕獲此異常。
?
解:
#include <iostream.h>
void main()
{
char *buf;
try
{
buf = new char[512];
if( buf == 0 )
throw "內(nèi)存分配失敗!";
}
catch( char * str )
{
cout << "有異常產(chǎn)生:" << str << endl;
}
}
?
12-6
定義一個異常類CException,有成員函數(shù)Reason(),用來顯示異常的類型,定義函數(shù)fn1()觸發(fā)異常,在主函數(shù)的try模塊中調(diào)用fn1(),在catch模塊中捕獲異常,觀察程序的執(zhí)行流程。
?
解:
#include <iostream.h>
class CException
{
public:
CException(){};
~CException(){};
const char *Reason() const { return "CException類中的異常。"; }
?
};
void fn1()
{
cout<< "在子函數(shù)中觸發(fā)CException類異常" << endl;
throw CException();
}
void main()
{
cout << "進入主函數(shù)" << endl;
try
{
cout << "在try模塊中,調(diào)用子函數(shù)" << endl;
fn1();
}
catch( CException E )
{
cout << "在catch模塊中,捕獲到CException類型異常:";
cout << E.Reason() << endl;
}
catch( char *str )
{
cout << "捕獲到其它類型異常:" << str << endl;
}
cout << "回到主函數(shù),異常已被處理" << endl;
}
程序運行輸出:
進入主函數(shù)
在try模塊中,調(diào)用子函數(shù)
在子函數(shù)中觸發(fā)CException類異常
在catch模塊中,捕獲到CException類型異常:CException類中的異常。
回到主函數(shù),異常已被處理
?