Posted on 2008-04-23 10:39
silentneil 閱讀(976)
評論(1) 編輯 收藏 引用
1 編程基礎(chǔ)
1.1 基本概念
1. 的理解:const char*, char const*, char*const的區(qū)別問題幾乎是C++面試中每次 都會有的題目。 事實上這個概念誰都有只是三種聲明方式非常相似很容易記混。 Bjarne在他的The C++ Programming Language里面給出過一個助記的方法: 把一個聲明從右向左讀。 const
char * const cp; ( * 讀成 pointer to )
cp is a const pointer to char
const char * p;
p is a pointer to const char;
char const * p;
同上因為C++里面沒有const*的運算符,所以const只能屬于前面的類型。
2. 指針c
int *p[n];-----指針數(shù)組,每個元素均為指向整型數(shù)據(jù)的指針。
int (*)p[n];------p為指向一維數(shù)組的指針,這個一維數(shù)組有n個整型數(shù)據(jù)。
int *p();----------函數(shù)帶回指針,指針指向返回的值。
int (*)p();------p為指向函數(shù)的指針。
3. 數(shù)組越界問題
下面這個程序執(zhí)行后會有什么錯誤或者效果:
#define MAX 255
int main()
{
unsigned char A[MAX],i;
for (i=0;i<=MAX;i++)
A[i]=i;
}
解答:MAX=255,數(shù)組A的下標范圍為:0..MAX-1,這是其一,其二 當i循環(huán)到255時,循環(huán)內(nèi)執(zhí)行: A[255]=255;這句本身沒有問題,但是返回for (i=0;i<=MAX;i++)語句時,由于unsigned char的取值范圍在(0..255),i++以后i又為0了..無限循環(huán)下去.
注:char類型為一個字節(jié),取值范圍是[-128,127],unsigned char [0 ,255]
4. 和strcpy 的根本區(qū)別? C++:memset ,memcpy
#include "memory.h"
memset用來對一段內(nèi)存空間全部設(shè)置為某個字符,一般用在對定義的字符串進行初始化為‘ '或‘\0';例:char a[100];memset(a, '\0', sizeof(a));
memcpy用來做內(nèi)存拷貝,你可以拿它拷貝任何數(shù)據(jù)類型的對象,可以指定拷貝的數(shù)據(jù)長度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),會造成b的內(nèi)存地址溢出。
strcpy就只能拷貝字符串了,它遇到'\0'就結(jié)束拷貝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串長度(第一個‘\0'之前)是否超過50位,如超過,則會造成b的內(nèi)存地址溢出。
strcpy
原型:extern char *strcpy(char *dest,char *src);
用法:#include
功能:把src所指由NULL結(jié)束的字符串復制到dest所指的數(shù)組中。
說明:src和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來容納src的字符串。
返回指向dest的指針。
memcpy
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include
功能:由src所指內(nèi)存區(qū)域復制count個字節(jié)到dest所指內(nèi)存區(qū)域。
說明:src和dest所指內(nèi)存區(qū)域不能重疊,函數(shù)返回指向dest的指針。
Memset
原型:extern void *memset(void *buffer, char c, int count);
用法:#include
功能:把buffer所指內(nèi)存區(qū)域的前count個字節(jié)設(shè)置成字符c。
說明:返回指向buffer的指針。
5. 是干什么用的ASSERT()
ASSERT ()是一個調(diào)試程序時經(jīng)常使用的宏,在程序運行時它計算括號內(nèi)的表達式,如果表達式為FALSE (0), 程序?qū)蟾驽e誤,并終止執(zhí)行。如果表達式不為0,則繼續(xù)執(zhí)行后面的語句。這個宏通常原來判斷程序中是否出現(xiàn)了明顯非法的數(shù)據(jù),如果出現(xiàn)了終止程序以免導致嚴重后果,同時也便于查找錯誤。例如,變量n在程序中不應該為0,如果為0可能導致錯誤,你可以這樣寫程序:
......
ASSERT( n != 0);
k = 10/ n;
......
ASSERT只有在Debug版本中才有效,如果編譯為Release版本則被忽略。
assert()的功能類似,它是ANSI C標準中規(guī)定的函數(shù),它與ASSERT的一個重要區(qū)別是可以用在Release版本中。
6. ("pause");系統(tǒng)的暫停程序,按任意鍵繼續(xù),屏幕會打印,"按任意鍵繼續(xù)。。。。。" 省去了使用getchar();system
7. 請問C++的類和C里面的struct有什么區(qū)別?
c++中的類具有成員保護功能,并且具有繼承,多態(tài)這類oo特點,而c里的struct沒有
8. 請講一講析構(gòu)函數(shù)和虛函數(shù)的用法和作用?
析構(gòu)函數(shù)也是特殊的類成員函數(shù),它沒有返回類型,沒有參數(shù),不能隨意調(diào)用,也沒有重載。知識在類對象生命期結(jié)束的時候,由系統(tǒng)自動調(diào)用釋放在構(gòu)造函數(shù)中分配的資源。這種在運行時,能依據(jù)其類型確認調(diào)用那個函數(shù)的能力稱為多態(tài)性,或稱遲后聯(lián)編。另:析構(gòu)函數(shù)一般在對象撤消前做收尾工作,比如回收內(nèi)存等工作,虛擬函數(shù)的功能是使子類可以用同名的函數(shù)對父類函數(shù)進行重載,并且在調(diào)用時自動調(diào)用子類重載函數(shù),如果是純虛函數(shù),則純粹是為了在子類重載時有個統(tǒng)一的命名而已。
9. 全局變量和局部變量有什么區(qū)別?實怎么實現(xiàn)的?操作系統(tǒng)和編譯器是怎么知道的?
全局變量的生命周期是整個程序運行的時間,而局部變量的生命周期則是局部函數(shù)或過程調(diào)用的時間段。其實現(xiàn)是由編譯器在編譯時采用不同內(nèi)存分配方法。全局變量在main函數(shù)調(diào)用后,就開始分配,如果是靜態(tài)變量則是在main函數(shù)前就已經(jīng)初始化了。而局部變量則是在用戶棧中動態(tài)分配的(還是建議看編譯原理中的活動記錄這一塊)
10. 是多少尉的系統(tǒng)?在數(shù)據(jù)總線上是怎么實現(xiàn)的?8086
8086系統(tǒng)是16位系統(tǒng),其數(shù)據(jù)總線是20位。
1.2 程序設(shè)計
1. 編寫用C語言實現(xiàn)的求n階階乘問題的遞歸算法:
long int fact(int n)
{
int x;
long int y;
if(n<0)
{
printf("error!");
}
if(n==0)
return 1;
x=n-1;
y=fact(x);
return (n*y);
}
2. 二分查找算法:
1) 遞歸方法實現(xiàn):
int BSearch(elemtype a[],elemtype x,int low,int high)
/*在下屆為low,上界為high的數(shù)組a中折半查找數(shù)據(jù)元素x*/
{
int mid;
if(low>high) return -1;
mid=(low+high)/2;
if(x==a[mid]) return mid;
if(x<a[mid]) return(BSearch(a,x,low,mid-1));
else return(BSearch(a,x,mid+1,high));
}
2) 非遞歸方法實現(xiàn):
int BSearch(elemtype a[],keytype key,int n)
{
int low,high,mid;
low=0;high=n-1;
while(low<=high)
{
mid=(low+high)/2;
if(a[mid].key==key) return mid;
else if(a[mid].key<key) low=mid+1;
else high=mid-1;
}
return -1;
}
3. 遞歸計算如下遞歸函數(shù)的值(斐波拉契):
f(1)=1
f(2)=1
f(n)=f(n-1)+f(n-2) n>2
解:
int f(int n)
{
int i,s,s1,s2;
s1=1;/*s1用于保存f(n-1)的值*/
s2=1;/*s2用于保存f(n-2)的值*/
s=1;
for(i=3;i<=n;i++)
{
s=s1+s2;
s2=s1;
s1=s;
}
return(s);
}
4. 交換兩個數(shù),不用第三塊兒內(nèi)存:
int a = ……;
int b = ……;
a = a + b;
b = a - b;
a = a - b;
5. 冒泡排序:
void BubbleSort(elemtype x[],int n)
{
int i,j;
elemtype temp;
for(i=1;i<n;i++)
for(j=0;j<n-i;j++)
{
if(x[j].key>x[j+1].key)
{
temp=x[j];
x[j]=x[j+1];
x[j+1]=temp;
}
}
}
6. 語言 文件讀寫c
#include "stdio.h"
main()
{
FILE *fp;
char ch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"w")==NULL)
{
printf("cann't open file\n");
exit(0);
}
ch=getchar();
while(ch!='#')
{
fputc(ch,fp);
putchar(ch);
ch=getchar();
}
fclose(fp);
}
7. 編程winsocket
#include <Winsock2.h>
#include <stdio.h>
void main()
{
WORDwVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1,1);
err = WSAStartup(wVersionRequested,&wsaData);
if( err != 0)
{
return;
}
if(LOBYTE( wsaData.wVersion ) != 1||
HIBYTE( wsaData.wVersion) != 1)
{
WSACleanup();
return;
}
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
listen(sockSrv,5);
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
while(1)
{
SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
char sendBuf[100];
sprint(sendBuf,"Welcome %s to http://www.sunxin.org",
inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[100];
recv(sockConn,recvBuf);
printf("%s\n",recvBuf);
closesocket(sockConn);
WSACleanup();
}
}
注:這是Server端;File->New->Win32 Console Application,工程名:TcpSrv;然后,F(xiàn)ile->New->C++ Source File,文件名:TcpSrv;在該工程的Setting的Link的Object/library modules項要加入ws2_32.lib
#include <Winsock2.h>
#include <stdio.h>
void main()
{
WORDwVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1,1);
err = WSAStartup(wVersionRequested,&wsaData);
if( err != 0)
{
return;
}
if(LOBYTE( wsaData.wVersion ) != 1||
HIBYTE( wsaData.wVersion) != 1)
{
WSACleanup();
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_porthtons(6000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
char recvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
send(sockClient,"This is zhangsan",strlen("This is zhangsan")+1,0);
closesocket(sockClient);
WSACleanup();
}
注:這是Client端;File->New->Win32 Console Application,工程名:TcpClient;然后,F(xiàn)ile->New->C++ Source File,文件名:TcpClient;同理,在該工程的Setting的Link的Object/library modules項要加入ws2_32.lib
8. 類的知識
C++
#include <iostream.h>
class human
{
public:
human(){ human_num++;};
static int human_num;
~human()
{
human_num--;
print();
}
void print()
{
cout<<"human num is: "<<human_num<<endl;
}
protected:
private:
};
int human::human_num = 0;
human f1(human x)
{
x.print();
return x;
}
int main(int argc, char* argv[])
{
human h1;
h1.print();
human h2 = f1(h1);
h2.print();
return 0;
}
輸出:
1
1
0
0
-1
-2
----------------------------
分析:
human h1; //調(diào)用構(gòu)造函數(shù),---hum_num = 1;
h1.print(); //輸出:"human is 1"
human h2 = f1(h1); //再調(diào)用f1(h1)的過程中,由于函數(shù)參數(shù)是按值傳遞對象,調(diào)用默認的復制構(gòu)造函數(shù),它并沒有對hum_num++,所以hum_num 仍= 1,所以x.print()輸出:"human is 1"; 在推出f1函數(shù)時,要銷毀X,調(diào)用析構(gòu)函數(shù)(human_num--),輸出:"human is 0"(,由于該函數(shù)返回一個human 對象,所以又調(diào)用默認構(gòu)造函數(shù),創(chuàng)建一個臨時對象(human_num = 0;),把臨時對象賦給h2,又調(diào)用默認構(gòu)造函數(shù)( human_num = 0); h2.print(); //輸出: human is 0;
//在退出main()函數(shù)是,先銷毀h2,調(diào)用析構(gòu)函數(shù)(human_num--),輸出"human_num is -1" 然后銷毀h1,調(diào)用析構(gòu)函數(shù)(--),輸出"human_num is -2"
1.3 Windows的消息機制
1. 的消息機制1Windows
Windows是一個消息(Message)驅(qū)動系統(tǒng)。Windows的消息提供了應用程序之間、應用程序與Windows系統(tǒng)之間進行通信的手段。應用程序想要實現(xiàn)的功能由消息來觸發(fā),并且靠對消息的響應和處理來完成。
Windows系統(tǒng)中有兩種消息隊列:系統(tǒng)消息隊列和應用程序消息隊列。計算機的所有輸入設(shè)備由Windows監(jiān)控。當一個事件發(fā)生時,Windows先將輸入的消息放入系統(tǒng)消息隊列中,再將消息拷貝到相應的應用程序消息隊列中。應用程序的消息處理程序?qū)⒎磸蜋z測消息隊列,并把檢測到的每個消息發(fā)送到相應的窗口函數(shù)中。這便是一個事件從發(fā)生至到達窗口函數(shù)必須經(jīng)歷的過程。
必須注意的是,消息并非是搶占性的,無論事件的緩急,總是按照到達的先后派對,依次處理(一些系統(tǒng)消息除外),這樣可能使一些實時外部事件得不到及時處理。
2. 的消息機制2Windows
Windows中的消息是放在對應的進程的消息隊列里的。可以通過GetMessage取得,并且對于一般的消息,此函數(shù)返回非零值,但是對于WM_QUIT消息,返回零。可以通過這個特征,結(jié)束程序。當取得消息之后,應該先轉(zhuǎn)換消息,再分發(fā)消息。所謂轉(zhuǎn)換,就是把鍵盤碼的轉(zhuǎn)換,所謂分發(fā),就是把消息分發(fā)給對應的窗口,由對應的窗口處理消息,這樣對應窗體的消息處理函數(shù)就會被調(diào)用。兩個函數(shù)可以實現(xiàn)這兩個功能:TranslateMessage和 DispatchMessage。
另外,需要注意,當我們點擊窗口的關(guān)閉按鈕關(guān)閉窗口時,程序并沒有自動退出,而是向程序發(fā)送了一個WM_DESTROY消息(其實過程是這樣的,首先向程序發(fā)送WM_CLOSE消息,默認的處理程序是調(diào)用DestroyWindow銷毀窗體,從而引發(fā)WM_DESTROY消息),此時在窗體中我們要響應這個消息,如果需要退出程序,那么就要向程序發(fā)送WM_QUIT消息(通過PostQuitMessage實現(xiàn))。一個窗體如果想要調(diào)用自己的消息處理函數(shù),可以使用SendMessage向自己發(fā)消息。
如上所述,大部分(注意是大部分)的消息是這樣傳遞的:首先放到進程的消息隊列中,之后由GetMessage取出,轉(zhuǎn)換后,分發(fā)給對應的窗口。這種消息成為存儲式消息。存儲式消息基本上是使用者輸入的結(jié)果,以擊鍵(如WM_KEYDOWN和WM_KEYUP訊息)、擊鍵產(chǎn)生的字符(WM_CHAR)、鼠標移動(WM_MOUSEMOVE)和鼠標按鈕(WM_LBUTTONDOWN)的形式給出。存儲式消息還包含時鐘消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。但是也有的消息是直接發(fā)送給窗口的,它們被稱為非存儲式消息。例如,當WinMain調(diào)用 CreateWindow時,Windows將建立窗口并在處理中給窗口消息處理函數(shù)發(fā)送一個WM_CREATE消息。當WinMain調(diào)用 ShowWindow時,Windows將給窗口消息處理函數(shù)發(fā)送WM_SIZE和WM_SHOWWINDOW消息。當WinMain調(diào)用 UpdateWindow時,Windows將給窗口消息處理函數(shù)發(fā)送WM_PAINT消息。
2 網(wǎng)絡(luò)知識
2.1 OSI和TCP/IP
1. 的七層網(wǎng)絡(luò)結(jié)構(gòu)圖(功能及特點)OSI
1) 物理層:為數(shù)據(jù)鏈路層提供物理連接,在其上串行傳送比特流,即所傳送數(shù)據(jù)的單位是比特。此外,該層中還具有確定連接設(shè)備的電氣特性和物理特性等功能。
2) 數(shù)據(jù)鏈路層:負責在網(wǎng)絡(luò)節(jié)點間的線路上通過檢測、流量控制和重發(fā)等手段,無差錯地傳送以幀為單位的數(shù)據(jù)。為做到這一點,在每一幀中必須同時帶有同步、地址、差錯控制及流量控制等控制信息。
3) 網(wǎng)絡(luò)層:為了將數(shù)據(jù)分組從源(源端系統(tǒng))送到目的地(目標端系統(tǒng)),網(wǎng)絡(luò)層的任務就是選擇合適的路由和交換節(jié)點,使源的傳輸層傳下來的分組信息能夠正確無誤地按照地址找到目的地,并交付給相應的傳輸層,即完成網(wǎng)絡(luò)的尋址功能。
4) 傳輸層:傳輸層是高低層之間銜接的接口層。數(shù)據(jù)傳輸?shù)膯挝皇菆笪模攬笪妮^長時將它分割成若干分組,然后交給網(wǎng)絡(luò)層進行傳輸。傳輸層是計算機網(wǎng)絡(luò)協(xié)議分層中的最關(guān)鍵一層,該層以上各層將不再管理信息傳輸問題。
5) 會話層:該層對傳輸?shù)膱笪奶峁┩焦芾矸铡T趦蓚€不同系統(tǒng)的互相通信的應用進程之間建立、組織和協(xié)調(diào)交互。例如,確定是雙工還是半雙工工作。
6) 表示層:該層的主要任務是把所傳送的數(shù)據(jù)的抽象語法變換為傳送語法,即把不同計算機內(nèi)部的不同表示形式轉(zhuǎn)換成網(wǎng)絡(luò)通信中的標準表示形式。此外,對傳送的數(shù)據(jù)加密(或解密)、正文壓縮(或還原)也是表示層的任務。
7) 應用層:該層直接面向用戶,是OSI中的最高層。它的主要任務是為用戶提供應用的接口,即提供不同計算機間的文件傳送、訪問與管理,電子郵件的內(nèi)容處理,不同計算機通過網(wǎng)絡(luò)交互訪問的虛擬終端功能等。
2. (功能及特點)TCP/IP
1) 網(wǎng)絡(luò)接口層:這是TCP/IP協(xié)議的最低一層,包括有多種邏輯鏈路控制和媒體訪問協(xié)議。網(wǎng)絡(luò)接口層的功能是接收IP數(shù)據(jù)報并通過特定的網(wǎng)絡(luò)進行傳輸,或從網(wǎng)絡(luò)上接收物理幀,抽取出IP數(shù)據(jù)報并轉(zhuǎn)交給網(wǎng)際層。
2) 網(wǎng)際網(wǎng)層(IP層):該層包括以下協(xié)議:IP(網(wǎng)際協(xié)議)、ICMP(Internet Control Message Protocol,因特網(wǎng)控制報文協(xié)議)、ARP(Address Resolution Protocol,地址解析協(xié)議)、RARP(Reverse Address Resolution Protocol,反向地址解析協(xié)議)。該層負責相同或不同網(wǎng)絡(luò)中計算機之間的通信,主要處理數(shù)據(jù)報和路由。在IP層中,ARP協(xié)議用于將IP地址轉(zhuǎn)換成物理地址,RARP協(xié)議用于將物理地址轉(zhuǎn)換成IP地址,ICMP協(xié)議用于報告差錯和傳送控制信息。IP協(xié)議在TCP/IP協(xié)議組中處于核心地位。
3) 傳輸層:該層提供TCP(傳輸控制協(xié)議)和UDP(User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議)兩個協(xié)議,它們都建立在IP協(xié)議的基礎(chǔ)上,其中TCP提供可靠的面向連接服務,UDP提供簡單的無連接服務。傳輸層提供端到端,即應用程序之間的通信,主要功能是數(shù)據(jù)格式化、數(shù)據(jù)確認和丟失重傳等。
4) 應用層:TCP/IP協(xié)議的應用層相當于OSI模型的會話層、表示層和應用層,它向用戶提供一組常用的應用層協(xié)議,其中包括:Telnet、SMTP、DNS等。此外,在應用層中還包含有用戶應用程序,它們均是建立在TCP/IP協(xié)議組之上的專用程序。
3. 參考模型和TCP/IP參考模型的區(qū)別:OSI
1) OSI模型有7層,TCP/IP只有4層;
2) OSI先于協(xié)議出現(xiàn),因此不會偏向于任何一組特定的協(xié)議,通用性更強,但有些功能不知該放哪一層上,因此不得不加入一些子層;TCP/IP后于協(xié)議出現(xiàn),僅是將已有協(xié)議的一個描述,因此兩者配合的非常好;但他不適合其他的協(xié)議棧,不容易描述其他非TCP/IP的網(wǎng)絡(luò);
3) OSI中網(wǎng)絡(luò)層同時支持無連接和面向連接的通信,但在傳輸層上只支持面向連接的通信;TCP/IP中網(wǎng)絡(luò)層只支持無連接通信,傳輸層同時支持兩種通信;
4) 在技術(shù)發(fā)生變化時,OSI模型比TCP/IP模型中的協(xié)議更容易被替換。
4. 請你詳細的解釋一下IP協(xié)議的定義,在哪個層上面,主要有什么作用? TCP與UDP呢?
解:與IP協(xié)議配套使用的還有三個協(xié)議:
ARP-地址解析協(xié)議
RARP-逆地址解析協(xié)議
ICMP-因特網(wǎng)控制報文協(xié)議ICMP
IP協(xié)議-網(wǎng)際協(xié)議
IP地址、IP包頭
2.2 交換機和路由器
1. 請問交換機和路由器分別的實現(xiàn)原理是什么?分別在哪個層次上面實現(xiàn)的?
將網(wǎng)絡(luò)互相連接起來要使用一些中間設(shè)備(或中間系統(tǒng)),ISO的術(shù)語稱之為中繼(relay)系統(tǒng)。根據(jù)中繼系統(tǒng)所在的層次,可以有以下五種中繼系統(tǒng):
1) 物理層(即常說的第一層、層L1)中繼系統(tǒng),即轉(zhuǎn)發(fā)器(repeater)。
2) 數(shù)據(jù)鏈路層(即第二層,層L2),即網(wǎng)橋或橋接器(bridge)。
3) 網(wǎng)絡(luò)層(第三層,層L3)中繼系統(tǒng),即路由器(router)。
4) 網(wǎng)橋和路由器的混合物橋路器(brouter)兼有網(wǎng)橋和路由器的功能。
5) 在網(wǎng)絡(luò)層以上的中繼系統(tǒng),即網(wǎng)關(guān)(gateway).
當中繼系統(tǒng)是轉(zhuǎn)發(fā)器時,一般不稱之為網(wǎng)絡(luò)互聯(lián),因為這僅僅是把一個網(wǎng)絡(luò)擴大了,而這仍然是一個網(wǎng)絡(luò)。高層網(wǎng)關(guān)由于比較復雜,目前使用得較少。因此一般討論網(wǎng)絡(luò)互連時都是指用交換機和路由器進行互聯(lián)的網(wǎng)絡(luò)。本文主要闡述交換機和路由器及其區(qū)別。
2. 第二層交換機和路由器的區(qū)別:
傳統(tǒng)交換機從網(wǎng)橋發(fā)展而來,屬于OSI第二層即數(shù)據(jù)鏈路層設(shè)備。它根據(jù)MAC地址尋址,通過站表選擇路由,站表的建立和維護由交換機自動進行。路由器屬于OSI第三層即網(wǎng)絡(luò)層設(shè)備,它根據(jù)IP地址進行尋址,通過路由表路由協(xié)議產(chǎn)生。因特網(wǎng)的路由選擇協(xié)議:內(nèi)部網(wǎng)關(guān)協(xié)議IGP和外部網(wǎng)關(guān)協(xié)議EGP
3. 第三層交換機和路由器的區(qū)別:
在第三層交換技術(shù)出現(xiàn)之前,幾乎沒有必要將路由功能器件和路由器區(qū)別開來,他們完全是相同的:提供路由功能正在路由器的工作,然而,現(xiàn)在第三層交換機完全能夠執(zhí)行傳統(tǒng)路由器的大多數(shù)功能。
綜上所述,交換機一般用于LAN-WAN的連接,交換機歸于網(wǎng)橋,是數(shù)據(jù)鏈路層的設(shè)備,有些交換機也可實現(xiàn)第三層的交換。路由器用于WAN-WAN之間的連接,可以解決異性網(wǎng)絡(luò)之間轉(zhuǎn)發(fā)分組,作用于網(wǎng)絡(luò)層。他們只是從一條線路上接受輸入分組,然后向另一條線路轉(zhuǎn)發(fā)。這兩條線路可能分屬于不同的網(wǎng)絡(luò),并采用不同協(xié)議。相比較而言,路由器的功能較交換機要強大,但速度相對也慢,價格昂貴,第三層交換機既有交換機線速轉(zhuǎn)發(fā)報文能力,又有路由器良好的控制功能,因此得以廣播應用。
3 高質(zhì)量編程C/C++
一、請?zhí)顚態(tài)OOL , float, 指針變量與“零值”比較的 if 語句。(10 分)
請寫出 BOOL flag 與“零值”比較的 if 語句。(3 分)
標準答案:
if ( flag )
if ( !flag )
如下寫法均屬不良風格,不得分。
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)
請寫出 float x 與“零值”比較的 if 語句。(4 分)
標準答案示例:
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
不可將浮點變量用“==”或“!=”與數(shù)字
比較,應該設(shè)法轉(zhuǎn)化成“>=”或“<=”此
類形式。
如下是錯誤的寫法,不得分。
if (x == 0.0)
if (x != 0.0)
請寫出 char *p 與“零值”比較的 if 語句。(3 分)
標準答案:
if (p == NULL)
if (p != NULL)
如下寫法均屬不良風格,不得分。
if (p == 0)
if (p != 0)
if (p)
if (!)
二、以下為Windows NT 下的32 位C++程序,請計算sizeof 的值(10 分)
void Func ( char str[100])
{
請計算
sizeof( str ) = 4 (2 分)
}
char str[] = “Hello” ;
char *p = str ;
int n = 10;
請計算
sizeof (str ) = 6 (2 分)
sizeof ( p ) = 4 (2 分)
sizeof ( n ) = 4 (2 分)
void *p = malloc( 100 );
請計算
sizeof ( p ) = 4 (2 分)
三、簡答題(25 分)
1、頭文件中的 ifndef/define/endif 干什么用?(5 分)
答:防止該頭文件被重復引用。
2、#include <filename.h> 和 #include “filename.h” 有什么區(qū)別?(5 分)
答:對于#include <filename.h> ,編譯器從標準庫路徑開始搜索 filename.h
對于#include “filename.h” ,編譯器從用戶的工作路徑開始搜索 filename.h
3、const 有什么用途?(請至少說明兩種)(5 分)
答:(1)可以定義 const 常量,(2)const 可以修飾函數(shù)的參數(shù)、返回值,甚至函數(shù)的定義體。被const 修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性。
4、在C++ 程序中調(diào)用被 C 編譯器編譯后的函數(shù),為什么要加 extern “C”? (5 分)
答:C++語言支持函數(shù)重載,C 語言不支持函數(shù)重載。函數(shù)被C++編譯后在庫中的名字
與C 語言的不同。假設(shè)某個函數(shù)的原型為: void foo(int x, int y);該函數(shù)被C 編譯器編譯后在庫中的名字為_foo ,而C++編譯器則會產(chǎn)生像_foo_int_int 之類的名字。C++提供了C 連接交換指定符號extern“C”來解決名字匹配問題。
5、請簡述以下兩個for 循環(huán)的優(yōu)缺點(5 分)
for (i=0; i<N; i++)
{
if (condition)
DoSomething();
else
DoOtherthing();
}
if (condition)
{
for (i=0; i<N; i++)
DoSomething();
}
else
{
for (i=0; i<N; i++)
DoOtherthing();
}
優(yōu)點:程序簡潔
缺點:多執(zhí)行了N-1 次邏輯判斷,并且
打斷了循環(huán)“流水線”作業(yè),使得編譯
器不能對循環(huán)進行優(yōu)化處理,降低了效
率。
優(yōu)點:循環(huán)的效率高
缺點:程序不簡潔
四、有關(guān)內(nèi)存的思考題(每小題5 分,共20 分)
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
請問運行Test 函數(shù)會有什么樣的結(jié)果?
答:程序崩潰。
因為GetMemory 并不能傳遞動態(tài)內(nèi)存,
Test 函數(shù)中的 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 函數(shù)會有什么樣的結(jié)果?
答:可能是亂碼。
因為GetMemory 返回的是指向“棧內(nèi)存”
的指針,該指針的地址不是 NULL,但其原
現(xiàn)的內(nèi)容已經(jīng)被清除,新內(nèi)容不可知。
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 函數(shù)會有什么樣的結(jié)果?
答:(1)能夠輸出hello;(2)內(nèi)存泄漏
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
請問運行Test 函數(shù)會有什么樣的結(jié)果?
答:篡改動態(tài)內(nèi)存區(qū)的內(nèi)容,后果難以預
料,非常危險。
因為free(str);之后,str 成為野指針,
if(str != NULL)語句不起作用。
五、編寫strcpy 函數(shù)(10 分)
已知strcpy 函數(shù)的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest 是目的字符串,strSrc 是源字符串。
(1)不調(diào)用C++/C 的字符串庫函數(shù),請編寫函數(shù) strcpy
char *strcpy(char *strDest, const char *strSrc);
{
assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
char *address = strDest; // 2分
while( (*strDest++ = * strSrc++) != ‘\0’ ) // 2分
NULL ;
return address ; // 2分
}
(2)strcpy 能把strSrc 的內(nèi)容復制到strDest,為什么還要char * 類型的返回值?
答:為了實現(xiàn)鏈式表達式。 // 2 分
例如 int length = strlen( strcpy( strDest, “hello world”) );
六、編寫類String 的構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)(25 分)
已知類String 的原型為:
class String
{
public:
String(const char *str = NULL); // 普通構(gòu)造函數(shù)
String(const String &other); // 拷貝構(gòu)造函數(shù)
~ String(void); // 析構(gòu)函數(shù)
String & operate =(const String &other); // 賦值函數(shù)
private:
char *m_data; // 用于保存字符串
};
請編寫String 的上述4 個函數(shù)。
標準答案:
// String 的析構(gòu)函數(shù)
String::~String(void) // 3 分
{
delete [] m_data;
// 由于m_data 是內(nèi)部數(shù)據(jù)類型,也可以寫成 delete m_data;
}
// String 的普通構(gòu)造函數(shù)
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);
}
}
// 拷貝構(gòu)造函數(shù)
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);
}
// 賦值函數(shù)
String & String::operate =(const String &other) // 13 分
{
// (1) 檢查自賦值 // 4 分
if(this == &other)
return *this;
// (2) 釋放原有的內(nèi)存資源 // 3 分
delete [] m_data;
// (3)分配新的內(nèi)存資源,并復制內(nèi)容 // 3 分
int length = strlen(other.m_data);
m_data = new char[length+1]; // 若能加 NULL 判斷則更好
strcpy(m_data, other.m_data);
// (4)返回本對象的引用 // 3 分
return *this;
}