程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C/C++筆試忍法帖04——C/C++語法特性篇

C/C++筆試忍法帖04——C/C++語法特性篇

編輯:C++入門知識

1.Heap與stack的差別
Heap是堆,stack是棧。
Stack的空間由操作系統自動分配/釋放,Heap上的空間手動分配/釋放。
Stack空間有限,Heap是很大的自由存儲區
C中的malloc函數分配的內存空間即在堆上,C++中對應的是new操作符。

程序在編譯期對變量和函數分配內存都在棧上進行,且程序運行過程中函數調用時參數的傳遞也在棧上進行。


2.In C++, what does "explicit" mean? what does "protected" mean?

c++中的explicit關鍵字用來修飾類的構造函數,表明該構造函數是顯式的,在某些情況下,我們要求類的使用者必須顯示調用類的構造函數時就需要使用explicit,反之默認類型轉換可能會造成無法預期的問題。

protected控制的是一個函數對一個類的成員(包括成員變量及成員方法)的訪問權限。protected成員只有該類的成員函數及其派生類的成員函數可以訪問


3.在C++中有沒有純虛構造函數?

構造函數不能是虛的。只能有虛的析構函數


4.在c++的一個類中聲明一個static成員變量有沒有用?

在C++類的成員變量被聲明為static(稱為靜態成員變量),意味著它為該類的所有實例所共享,也就是說當某個類的實例修改了該靜態成員變量,也就是說不管創建多少對象,static修飾的變量只占有一塊內存。其修改值為該類的其它所有實例所見;而類的靜態成員函數也只能訪問靜態成員(變量或函數)。

static是加了訪問控制的全局變量,不被繼承。


5.C/C++編譯器中虛表是如何完成的?


6.在c++中純虛析構函數的作用是什麼?請舉例說明。


7.代碼
void func() {
static int val;
… } 中,變量val的內存地址位於:

A. 已初始化數據段 B.未初始化數據段 C.堆 D.棧


8.In C++, what does "explicit" mean? what does "protected" mean?

c++中的explicit關鍵字用來修飾類的構造函數,表明該構造函數是顯式的,在某些情況下,我們要求類的使用者必須顯示調用類的構造函數時就需要使用explicit,反之默認類型轉換可能會造成無法預期的問題。

protected控制的是一個函數對一個類的成員(包括成員變量及成員方法)的訪問權限。protected成員只有該類的成員函數及其派生類的成員函數可以訪問


9.在C++中有沒有純虛構造函數?

構造函數不能是虛的。只能有虛的析構函數


10.在c++的一個類中聲明一個static成員變量有沒有用?

在C++類的成員變量被聲明為static(稱為靜態成員變量),意味著它為該類的所有實例所共享,也就是說當某個類的實例修改了該靜態成員變量,也就是說不管創建多少對象,static修飾的變量只占有一塊內存。其修改值為該類的其它所有實例所見;而類的靜態成員函數也只能訪問靜態成員(變量或函數)。

static是加了訪問控制的全局變量,不被繼承。


11.MFC中CString是類型安全類麼?

答:不是,其它數據類型轉換到CString可以使用CString的成員函數Format來轉換


12.C++中為什麼用模板類?

答:(1)可用來創建動態增長和減小的數據結構

(2)它是類型無關的,因此具有很高的可復用性。

(3)它在編譯時而不是運行時檢查數據類型,保證了類型安全

(4)它是平台無關的,可移植性


13.函數模板與類模板有什麼區別?

答:函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化必須由程序員在程序中顯式地指定。


14.關於內存對齊的問題以及sizeof()的輸出

答:編譯器自動對齊的原因:為了提高程序的性能,數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的內存,處理器需要作兩次內存訪問;然而,對齊的內存訪問僅需要一次訪問。


15.動態連接庫的兩種方式?

答:調用一個DLL中的函數有兩種方法:

1.載入時動態鏈接(load-time dynamic linking),模塊非常明確調用某個導出函數,使得他們就像本地函數一樣。這需要鏈接時鏈接那些函數所在DLL的導入庫,導入庫向系統提供了載入DLL時所需的信息及DLL函數定位。

2.運行時動態鏈接(run-time dynamic linking),運行時可以通過LoadLibrary或LoadLibraryEx函數載入DLL。DLL載入後,模塊可以通過調用GetProcAddress獲取DLL函數的出口地址,然後就可以通過返回的函數指針調用DLL函數了。如此即可避免導入庫文件了


16.寫出對應要求的指針

1) 一個指向有10個整型數數組的指針(A pointer to an array of 10 integers)
2) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer)
3) 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數( An array of ten pointers to functions that take an integer argument and return an integer )

1) int (*a)[10]; // A pointer to an array of 10 integers
2) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
3) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer


17.關鍵字static的作用是什麼?

這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
1). 在函數體,一個被聲明為靜態的變量在這一函數被調用過程中保持變量內容的持久

2). 在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問,即隱藏的作用。它是一個本地的全局變量。
3). 在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用,即隱藏的作用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用。

4).static的第三個作用是默認初始化為0

其實全局變量也具備這一屬性,
因為全局變量也存儲在靜態數據區。在靜態數據區,內存中所有的字節默認值都是0x00,某些時候這一特點可以減少程序員的工作量。比如初始化一個稀疏矩陣,我們可以一個一個地把所有元素都置0,然後把不是0的幾個元素賦值。如果定義成靜態的,就省去了一開始置0的操作。再比如要把一個字符數組當字符串來用,但又覺得每次在字符數組末尾加’\0’太麻煩。如果把字符串定義成靜態的,就省去了這個麻煩,因為那裡本來就是’\0’。不妨做個小實驗驗證一下


18.關鍵字const是什麼含意?
我只要一聽到被面試者說:“const意味著常數”,我就知道我正在和一個業余者打交道。去年Dan Saks已經在他的文章裡完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什麼和不能做什麼.如果你從沒有讀到那篇文章,只要能說出const意味著“只讀”就可以了。盡管這個答案不是完全的答案,但我接受它作為一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)如果應試者能正確回答這個問題,我將問他一個附加的問題:下面的聲明都是什麼意思?
const int a; //a是一個常整型數
int const a; //a是一個常整型數
const int *a; //一個指向常整型數的指針,整型數是不可修改的,但指針可以
int * const a; //一個指向整型數的常指針,指針指向的整型數是可以修改的,指針不可修改
int const * a const;// 一個指向常整型數的常指針,整型數不可修改,指針也是不可修改的


(主要看const靠近*還是int,不可修改的就是它)
前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最後一個意味著a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。如果應試者能正確回答這些問題,那麼他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字const,也還是能很容易寫出功能正確的程序,那麼我為什麼還要如此看重關鍵字const呢?我也如下的幾下理由:
1). 關鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數為常量是為了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多余的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)
2). 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。
3). 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。


19.關鍵字volatile有什麼含意 並給出三個不同的例子。
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裡的備份。下面是volatile變量的幾個例子:
1). 並行設備的硬件寄存器(如:狀態寄存器)
2). 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
3). 多線程應用中被幾個任務共享的變量
回答不出這個問題的人是不會被雇傭的。我認為這是區分C程序員和嵌入式系統程序員的最基本的問題。嵌入式系統程序員經常同硬件、中斷、RTOS等等打交道,所用這些都要求volatile變量。不懂得volatile內容將會帶來災難。
假設被面試者正確地回答了這是問題(嗯,懷疑這否會是這樣),我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。
1). 一個參數既可以是const還可以是volatile嗎?解釋為什麼。
2). 一個指針可以是volatile 嗎?解釋為什麼。
3). 下面的函數有什麼錯誤:

int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1). 是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
2). 是的。盡管這並不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
3). 這段代碼的有個惡作劇。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器類似下面的代碼:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}

20.What is virtual function ?what is vtable used for?
虛函數主要用於實現多態用,基類的某個函數前加個Virtual 用來告訴編譯系統,遇到這個處理過程時,要等到執行時再確定到底調用哪個類的處理過程;

每一個虛函數都會有一個入口地址,虛函數表保存所有虛函數的入口地址


21.What's the difference between "struct" and "class" in c++?
struct成員默認類型為public,class成員默認類型為private。即為數據的封裝。

如果沒有多態和虛擬繼承,在C++中,struct和class的存取效率完全相同!簡單的說就是,存取class的data member和非virtual function效率和struct完全相同!不管該data member是定義在基類還是派生類的。如果不是為了和C兼容,C++中就不會有struct關鍵字。


22.What do we need to make destructor vitual?why?

CObject的析構函數設為virtual型,則所有CObject類的派生類的析構函數都將自動變為virtual型,這保證了在任何情況下,不會出現由於析構函數未被調用而導致的內存洩露


23.What to declare member function as const?
void fun1(int a) const;const的作用是指在該函數內部不會改變此類的成員變量(除非該成員變量定義時加上violate關鍵字),否則修改了該成員變量就會報錯.


24.列出兩個情況是必須使用成員初始化列表,而不在構造函數裡面賦值


25.static_cast和dynamic_cast有什麼區別?


26.namespace解決了什麼問題?



27.auto_ptr是什麼東西,有什麼用?


28.New delete 與malloc free 的區別 ( Autodesk)
答案:用malloc 函數不能初始化對象,new 會調用對象的構造函數。Delete 會調用對象的destructor,而free 不會調用對象的destructor.


29. 有哪幾種情況只能用intialization list 而不能用assignment? (Autodesk)
答案:當類中含有const、reference 成員變量;基類的構造函數都需要參數;類中含有其他類的成員對象,而該類的構造函數都需要參數。

30. C++是不是類型安全的? (Autodesk)
答案:不是。兩個不同類型的指針之間可以強制轉換。C#是類型安全的。


31. main 函數執行以前,還會執行什麼代碼? (Autodesk)
答案:

main函數執行之前,主要就是初始化系統相關資源:
1.設置棧指針
2.初始化static靜態和global全局變量,即data段的內容
3.將未初始化部分的全局變量賦初值:數值型short,int,long等為0,bool為FALSE,指針為NULL,等等,即.bss段的內容
4.運行全局構造器,估計是C++中構造函數之類的吧
5.將main函數的參數,argc,argv等傳遞給main函數,然後才真正運行main函數

(1)全局對象的析構函數會在main函數之後執行;

(2)可以用_onexit 注冊一個函數,它會在main 之後執行;


32. 描述一下C++的多態 (microsoft)
答案:C++的多態表現在兩個部分,一個是靜態連編下的函數重載,運算符重載;動態連編下的虛函數、純虛函數(抽象類)

33.請說出const 與#define 相比優點
答案:
(1) const 常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤。
(2) 有些集成化的調試工具可以對const 常量進行調試,但是不能對宏常量進行調試。


34.指針和數組的區別

數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。指針可以隨時指向任意類型的內存塊。
(1)修改內容上的差別
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p 指向常量字符串
p[0] = ‘X’; // 編譯器不能發現該錯誤,運行時錯誤


(2) 用運算符sizeof 可以計算出數組的容量(字節數)。sizeof(p),p 為指針得到的是一個指針變量的字節數,而不是p 所指的內存容量。C++/C 語言沒有辦法知道指針所指的內存容量,除非在申請內存時記住它。注意當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字節
cout<< sizeof(p) << endl; // 4 字節
計算數組和指針的內存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字節而不是100 字節
}


35.類成員函數的重載、覆蓋和隱藏區別
答案:
成員函數被重載的特征:
(1)相同的范圍(在同一個類中);
(2)函數名字相同;
(3)參數不同;
(4)virtual 關鍵字可有可無。
覆蓋是指派生類函數覆蓋基類函數,特征是:
(1)不同的范圍(分別位於派生類與基類);
(2)函數名字相同;
(3)參數相同;
(4)基類函數必須有virtual 關鍵字。
“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)


36.如何打印出當前源文件的文件名以及源文件的當前行號?
答案:
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系統預定義宏,這種宏並不是在某個文件中定義的,而是由編譯器定義的。


37.main 主函數執行完畢後,是否可能會再執行一段代碼,給出說明?
答案:可以,可以用_onexit 注冊一個函數,它會在main 之後執行int fn1(void), fn2(void), fn3(void), fn4 (void);
void main( void )
{
String str("zhanglin");
_onexit( fn1 );
_onexit( fn2 );
_onexit( fn3 );
_onexit( fn4 );
printf( "This is executed first./n" );
}
int fn1()
{
printf( "next./n" );
return 0;
}
int fn2()
{
printf( "executed " );
return 0;
}
int fn3()
{
printf( "is " );
return 0;
}
int fn4()
{
printf( "This " );
return 0;
}
The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.


38.如何判斷一段程序是由C 編譯程序還是由C++編譯程序編譯的?
答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif


39.堆棧溢出一般是由什麼原因導致的?

動態申請的內存忘記釋放,即new和delete沒有成對出現。

層次太深的遞歸調用


40. 寫出float x 與“零值”比較的if語句。
if(x>-0.000001 && x<0.000001)


41. 一語句實現x是否為2的若干次冪的判斷
位運算法:

int i = 512; cout << boolalpha << ((i & (i - 1)) ? false : true) << endl;


42.交換兩個變量的值,不使用第三個變量。即a=3,b=5,交換之後a=5,b=3;
有兩種解法, 一種用算術算法, 一種用^(異或)
a = a + b;
b = a - b;
a = a - b;
or
a = a^b;// 只能對int,char..
b = a^b;
a = a^b;
or
a ^= b ^= a;


43.c和c++中的struct有什麼不同?
c和c++中struct的主要區別是c中的struct不可以含有成員函數,而c++中的struct可以。c++中struct和class的主要區別在於默認的存取權限不同,struct默認為public,而class默認為private


44.純虛函數如何定義?使用時應注意什麼?
virtual void f()=0;
是接口,子類必須要實現


45.要對絕對地址0x100000賦值,我們可以用
(unsigned int*)0x100000 = 1234;
那麼要是想讓程序跳轉到絕對地址是0x100000去執行,應該怎麼做?
*((void (*)( ))0x100000 ) ( );
首先要將0x100000強制轉換成函數指針,即:
(void (*)())0x100000
然後再調用它:
*((void (*)())0x100000)();
用typedef可以看得更直觀些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();


46.已知一個數組table,用一個宏定義,求出數據的元素個數
#define NTBL
#define NTBL (sizeof(table)/sizeof(table[0]))


47.請寫一個C函數,若處理器是Big_endian的則返回0;若是Little_endian的則返回1

int checkCPU()
{
  union w
   {

int a;
    char b;

}c;

   c.a = 1;
   return (c.b == 1);
 }
}

48.C++中引用與指針的區別;
答:1 引用實際上是所引用的對象或變量的別名,而指針是包含所指向對象或變量的地址的變量。

2 引用在定義時必須初始化,而指針在定義時不初始化。
3 不可以有努NULL的引用,而可以有指向NULL的指針。
4 引用在初始化後不可以改變引用關系,而指針可以隨時指向其他對象(非const指針)。

49.以下關鍵字的含義與用法:
extern,extern “C”,static,explicit,register,#undef,#ifndef

在C++中引用C語言中的函數和變量,在包含C語言頭文件(假設為cExample.h)時,需進行下列處理:

extern "C"

{

#i nclude "cExample.h" }

#undef 是在後面取消以前定義的宏定義


50.從語法上,在C++中(只討論C++中)。class和struct做類型定義時只有兩點區別:
(一)默認繼承權限。如果不明確指定,來自class的繼承按照private繼承處理,來自struct的繼承按照public繼承處理;
(二)成員的默認訪問權限。class的成員默認是private權限,struct默認是public權限。


51.下面函數的返回值(微軟)

int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}

假定x = 9999。 答案:8

思路:將x轉化為2進制,看含有的1的個數。

52.交換兩個數的宏定義

交換兩個參數值的宏定義為:. #define SWAP(a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b);


53.下面的代碼輸出是什麼,為什麼?

void foo(void)

{

unsigned int a = 6;

int b = -20;

(a+b > 6) puts("> 6") : puts("<= 6");

}

這個問題測試你是否懂得C語言中的整數自動轉換原則,我發現有些開發者懂得極少這些東西。不管如何,這無符號整型問題的答案是輸出是“>6”。原因是當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換為無符號類型。因此-20變成了一個非常大的正整數,所以該表達式計算出的結果大於6


54.結構與聯合有和區別?

(1).結構和聯合都是由多個不同的數據類型成員組成, 但在任何同一時刻, 聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間), 而結構的所有成員都存在(不同成員的存放地址不同)。
(2).對於聯合的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存在了, 而對於結構的不同成員賦值是互不影響的。


55.宏與內聯函數的區別

1.內聯函數在運行時可調試,而宏定義不可以;
2.編譯器會對內聯函數的參數類型做安全檢查或自動類型轉換(同普通函數),而宏定義則不會;
3.內聯函數可以訪問類的成員變量,宏定義則不能;
4.在類中聲明同時定義的成員函數,自動轉化為內聯函數。

56.頭文件中的 ifndef/define/endif 干什麼用?

答:防止該頭文件被重復引用。


57.#include 和 #include “filename.h” 有什麼區別?(5分)

答:對於#include ,編譯器從標准庫路徑開始搜索 filename.h

對於#include “filename.h” ,編譯器從用戶的工作路徑開始搜索 filename.h


58.const 有什麼用途?(請至少說明兩種)(5分)

答:(1)可以定義 const 常量

(2)const可以修飾函數的參數、返回值,甚至函數的定義體。被const修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性。


59.在C++ 程序中調用被 C編譯器編譯後的函數,為什麼要加 extern “C”? (5分)

答:C++語言支持函數重載,C語言不支持函數重載。函數被C++編譯後在庫中的名字與C語言的不同。假設某個函數的原型為: void foo(int x, int y);

該函數被C編譯器編譯後在庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字。

C++提供了C連接交換指定符號extern“C”來解決名字匹配問題。



60.關於C語言的內存的思考

void GetMemory(char *p)

{

p = (char *)malloc(100);

}

void Test(void)

{

char *str = NULL;

GetMemory(str);

strcpy(str, "hello world");

printf(str);

}

請問運行Test函數會有什麼樣的結果?

答:程序崩潰。

因為GetMemory並不能傳遞動態內存,

Test函數中的 str一直都是 NULL。

strcpy(str, "hello world");將使程序崩潰。

char *GetMemory(void)

{

char p[] = "hello world";

return p;

}

void Test(void)

{

char *str = NULL;

str = GetMemory();

printf(str);

}

請問運行Test函數會有什麼樣的結果?

答:可能是亂碼。

因為GetMemory返回的是指向“棧內存”的指針,該指針的地址不是 NULL,但其原現的內容已經被清除,新內容不可知。

void GetMemory2(char **p, int num)

{

*p = (char *)malloc(num);

}

void Test(void)

{

char *str = NULL;

GetMemory(&str, 100);

strcpy(str, "hello");

printf(str);

}

請問運行Test函數會有什麼樣的結果?

答:

(1)能夠輸出hello

(2)內存洩漏

void Test(void)

{

char *str = (char *) malloc(100);

strcpy(str, “hello”);

free(str);

if(str != NULL)

{

strcpy(str, “world”);

printf(str);

}

}

請問運行Test函數會有什麼樣的結果?

答:篡改動態內存區的內容,後果難以預料,非常危險。

因為free(str);之後,str成為野指針,

if(str != NULL)語句不起作用。

61.編寫類String的構造函數、析構函數和賦值函數(25分)

已知類String的原型為:

class String

{

public:

String(const char *str = NULL); // 普通構造函數

String(const String &other); // 拷貝構造函數

~ String(void); // 析構函數

String & operate =(const String &other); // 賦值函數

private:

char *m_data; // 用於保存字符串

};

請編寫String的上述4個函數。

標准答案:

// String的析構函數

String::~String(void) // 3分

{

delete [] m_data;

// 由於m_data是內部數據類型,也可以寫成 delete m_data;

}

// String的普通構造函數

String::String(const char *str) // 6分

{

if(str==NULL)

{

m_data = new char[1]; // 若能加 NULL 判斷則更好

*m_data = ‘ 0’;

}

else

{

int length = strlen(str);

m_data = new char[length+1]; // 若能加 NULL 判斷則更好

strcpy(m_data, str);

}

}

// 拷貝構造函數

String::String(const String &other) // 3分

{

int length = strlen(other.m_data);

m_data = new char[length+1]; // 若能加 NULL 判斷則更好

strcpy(m_data, other.m_data);

}

// 賦值函數

String & String::operate =(const String &other) // 13分

{

// (1) 檢查自賦值 // 4分

if(this == &other)

return *this;

// (2) 釋放原有的內存資源 // 3分

delete [] m_data;

// (3)分配新的內存資源,並復制內容 // 3分

int length = strlen(other.m_data);

m_data = new char[length+1]; // 若能加 NULL 判斷則更好

strcpy(m_data, other.m_data);

// (4)返回本對象的引用 // 3分

return *this;

}

62.編寫strcpy函數(10分)

已知strcpy函數的原型是

char *strcpy(char *strDest, const char *strSrc);

其中strDest是目的字符串,strSrc是源字符串。

(1)不調用C++/C的字符串庫函數,請編寫函數 strcpy

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved