經典基礎C++筆試題(附答案)
一、選擇題
1.?若用數組名作為函數調用時的實參,則實際上傳遞給形參的是(?A?)
A.?數組首地址
B.?數組的第一個元素值
C.?數組中全部元素的值
D.?數組元素的個數
2.?有關函數重載的正確說法是(?B?)
A.?函數名不同,但參數的個數和類型相同
B.?函數名相同,但參數的個數不同或參數的類型不同
C.?函數名相同,參數的個數和類型相同
D.?函數名相同,函數的返回值不同,而與函數的參數和類型無關
3.?已知int?a[3][2]={3,2,1};?則表達式“a[0][0]/a[0][1]/a[0][2]”的值是(B)
A.?0.166667
B.?1
C.?0
D.??錯誤的表達式
4.?要禁止修改指針p本身,又要禁止修改p所指向的數據,這樣的指針應定義為( D )
A.?const?char?*p="ABCD";
B.?char?const?*p="ABCD";
C.?char?*const?p="ABCD";
D.?const?char?*?const?p="ABCD";
5.?對靜態成員的不正確描述是(?C??)
A.?靜態成員不屬于對象,是類的共享成員
B.?靜態數據成員要在類外定義和初始化
C.?調用靜態成員函數時要通過類或對象激活,所以靜態成員函數擁有this指針
D.?非靜態成員函數也可以操作靜態數據成員
6.?下面函數原型聲明中,(?B??)聲明了fun為純虛函數
A.?void?fun()=0;
B.?virtual?void?fun()=0;
C.?virtual?void?fun();
D.?virtual?void?fun(){};
7.?在排序方法中,關鍵碼比較次數與記錄地初始排列無關的是(?D?)
A.?Shell排序
B.?歸并排序
C.?直接插入排序
D.?選擇排序
8.?一個棧的入棧序列是A,B,C,D,E,則棧的不可能的輸出序列是(?C?)
A.?EDCBA;
B.?DECBA;
C.?DCEAB;
D.?ABCDE
二、填空題
1.求下面函數的返回值?_____
int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
2.?以下三條輸出語句分別輸出什么?_____
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char* str5 = "abc";
const char* str6 = "abc";
cout << boolalpha << ( str1==str2 ) << endl; // 輸出什么?
cout << boolalpha << ( str3==str4 ) << endl; // 輸出什么?
cout << boolalpha << ( str5==str6 ) << endl; // 輸出什么?
答:分別輸出false,false,true。str1和str2都是字符數組,每個都有其自己的存儲區,它們的值則是各存儲區首地址,不等;str3和str4同上,只是按const語義,它們所指向的數據區不能修改。str5和str6并非數組而是字符指針,并不分配存儲區,其后的“abc”以常量形式存于靜態數據區,而它們自己僅是指向該區首地址的指針,相等。
3.請給出如下程序的結果
int a = 3;
int b = a << 3;
3*2^3 = 24
a?=?__3__?,?b?=?__24__?。
4.請給出如下程序的結果
#define MAX_NUM 100+200
int nTemp = MAX_NUM*10;
則?Temp?=?__2100__?。
5.?程序的運行結果為___
void Func(char str[100])
{
printf("%d\n", sizeof(str));
}
數組作為函數的形參退化為指針
答:4
分析:?指針長度
6.?程序的運行結果為____
int sum(int a)
{
auto int c=0;
static int b=3;
c+=1;
b+=2;
return(a+b+c);
}
void main()
{
int I;
int a=2;
for(I=0;I<5;I++)
{
printf("%d,", sum(a));
}
}
//?static會保存上次結果,記住這一點,剩下的自己寫
輸出:8,10,12,14,16,
7.?程序的運行結果為____
unsigned short array[]={1,2,3,4,5,6,7};
int i = 3;
*(array + i) = ?
答:?4
8.寫出以下程序的執行結果:
static char *s[]= {"black","white","yellow","violet"};
char **ptr[]={s+3,s+2,s+1,s},***p=ptr;
**++p;
printf("%s\n",*++*++p+3);
分析:注意指針++的區別,以及*p+1與*(p+1)的區別
三、問答題
1、頭文件中的?ifndef/define/endif?干什么用?
答:防止該頭文件被重復引用。
2.?C++中為什么用模板類。
答:(1)可用來創建動態增長和減小的數據結構
(2)它是類型無關的,因此具有很高的可復用性。
(3)它在編譯時而不是運行時檢查數據類型,保證了類型安全
(4)它是平臺無關的,可移植性
(5)可用于基本數據類型
3.?說一說C與C++的內存分配方式?
(1)從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在,如全局變量,static變量。
(2)在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。
(3)從堆上分配(動態內存分配)程序在運行的時候用malloc或new申請任意多少的內存,程序員負責在何時用free或delete釋放內存。動態內存的生存期自己決定,使用非常靈活。
4.?關鍵字static的作用是什么?
這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
(1)在函數體,一個被聲明為靜態的變量在這一函數被調用過程中維持其值不變。
(2)在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。
(3)在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用。
大多數應試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,因為他顯然不懂得本地化數據和代碼范圍的好處和重要性。
5.?面向對象的三個基本特征,并簡單敘述之?
(1)封裝:將客觀事物抽象成類,每個類對自身的數據和方法實行protection(private,?protected,public)
(2)?繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現代碼)、接口繼承?(僅使用屬性和方法,實現滯后到子類實現)。前兩種(類繼承)和后一種(對象組合=>接口繼承以及純虛函數)構成了功能復用的兩種方式。
(3)多態:是將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
6.?局部變量能否和全局變量重名?
答:能,局部會屏蔽全局。要用全局變量,需要使用"::"?;局部變量可以與全局變量同名,在函數內引用這個變量時,會用到同名的局部變量,而不會用到全局變量。對于有些編譯器而言,在同一個函數內可以定義多個同名的局部變量,比如在兩個循環體內都定義一個同名的局部變量,而那個局部變量的作用域就在那個循環體內。
7.?重載(overload)和重寫(overried,有的書也叫做“覆蓋”)的區別?
答:從定義上來說:
重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數類型不同,或許兩者都不同)。
重寫:是指子類重新定義復類虛函數的方法。
從實現原理上來說:
重載:編譯器根據函數不同的參數表,對同名函數的名稱做修飾,然后這些同名函數就成了不同的函數。
重寫:當子類重新定義了父類的虛函數后,父類指針根據賦給它的不同的子類指針,動態的調用屬于子類的該函數,這樣的函數調用在編譯期間是無法確定的(調用的子類的虛函數的地址無法給出)。
8.?new?delete?與malloc?free?的聯系與區別?
答案:都是在堆(heap)上進行動態的內存操作。用malloc函數需要指定內存分配的字節數并且不能初始化對象,new?會自動調用對象的構造函數。delete?會調用對象的destructor,而free?不會調用對象的destructor.
9.?什么是死鎖?其條件是什么?怎樣避免死鎖?
答案:死鎖的概念:在兩個或多個并發進程中,如果每個進程持有某種資源而又都等待別的進程釋放它或它們現在保持著的資源,在未改變這種狀態之前都不能向前推進,稱這一組進程產生了死鎖。通俗地講,就是兩個或多個進程被無限期地阻塞、相互等待的一種狀態。
死鎖產生的原因主要是:??系統資源不足;??進程推進順序非法。
產生死鎖的必要條件:
(1)互斥(mutualexclusion),一個資源每次只能被一個進程使用;
(2)不可搶占(nopreemption),進程已獲得的資源,在未使用完之前,不能強行剝奪;
(3)占有并等待(hold?andwait),一個進程因請求資源而阻塞時,對已獲得的資源保持不放;
(4)環形等待(circularwait),若干進程之間形成一種首尾相接的循環等待資源關系。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
死鎖的解除與預防:理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久占據系統資源。此外,也要防止進程在處于等待狀態的情況下占用資源。因此,對資源的分配要給予合理的規劃。
死鎖的處理策略:鴕鳥策略、預防策略、避免策略、檢測與恢復策略。
10.?ARP?是地址解析協議,簡單語言解釋一下工作原理。
答:
(?1?)首先,每個主機都會在自己的?ARP?緩沖區中建立一個?ARP?列表,以表示?IP?地址和?MAC?地址之間的對應關系。
(?2?)當源主機要發送數據時,首先檢查?ARP?列表中是否有對應?IP?地址的目的主機的?MAC?地址,如果有,則直接發送數據,如果沒有,就向本網段的所有主機發送?ARP?數據包,該數據包包括的內容有:源主機?IP?地址,源主機?MAC?地址,目的主機的?IP?地址。
(?3?)當本網絡的所有主機收到該?ARP?數據包時,首先檢查數據包中的?IP?地址是否是自己的?IP?地址,如果不是,則忽略該數據包,如果是,則首先從數據包中取出源主機的?IP?和?MAC?地址寫入到?ARP?列表中,如果已經存在,則覆蓋,然后將自己的?MAC?地址寫入?ARP?響應包中,告訴源主機自己是它想要找的?MAC?地址。
(?4?)源主機收到?ARP?響應包后。將目的主機的?IP?和?MAC?地址寫入?ARP?列表,并利用此信息發送數據。如果源主機一直沒有收到?ARP?響應數據包,表示?ARP?查詢失敗。
廣播發送?ARP?請求,單播發送?ARP?響應。
11、請定義一個宏,比較兩個數a、b的大小,不能使用大于、小于、if語句
#define?Max(a,b)??(?a/b)?a:b
12.?分別寫出BOOL,int,float,指針類型的變量a?與“零”的比較語句。
答案:
BOOL : if ( !a ) or if(a)
int : if ( a == 0)
float : const EXPRESSION EXP = 0.000001
if ( a < EXP && a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)
13.?已知strcpy的函數原型:char?*strcpy(char?*strDest,?const?char?*strSrc)其中strDest?是目的字符串,strSrc?是源字符串。不調用C++/C?的字符串庫函數,請編寫函數?strcpy。
答案:
/*
編寫strcpy函數(10分)
已知strcpy函數的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不調用C++/C的字符串庫函數,請編寫函數 strcpy
(2)strcpy能把strSrc的內容復制到strDest,為什么還要char * 類型的返回值?
答:為了 實現鏈式表達式。 // 2分
例如 int length = strlen( strcpy( strDest, “hello world”) );
*/
#include
#include
char*strcpy(char*strDest, constchar*strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
char* address = strDest; // 2分
while( (*strDest++=*strSrc++) !='\0' )// 2分
NULL;
return address ; // 2分
}
14.?已知鏈表的頭結點head(有內容),寫一個函數把這個鏈表逆序
Node * ReverseList(Node *head) //鏈表逆序
{
if ( head == NULL || head->next == NULL )
return head;
Node *p1 = head ;
Node *p2 = p1->next ;
Node *p3 = p2->next ;
p1->next = NULL ;// 頭結點的next指向NULL
while ( p3 != NULL )
{
p2->next = p1 ;// 逆序
p1 = p2 ;// 三個指針分別后移一位
p2 = p3 ;
p3 = p3->next ;
}
p2->next = p1 ;
head = p2 ;// 作為新的頭結點
return head ;
}
15.?寫個函數交換兩個指針。
#include
using namespace std;
void ex(char **a,char **b)
{
char *c;
c=*a;
*a=*b;
*b=c;
}
int main()
{
char *pt=”pt\n”;
char *pt_another=”pt_another\n”;
cout< ex(&pt,&pt_another); cout< system(“pause”); } C++ 數據結構
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。