招商银行/招银网络科技面经、答案
1、介紹一下static的各種用法,static修飾的變量在別的文件中可以使用嗎
Static修飾全局變量叫做靜態(tài)全局變量,
Static修飾局部變量叫做靜態(tài)局部變量,
Static修飾函數(shù)叫做靜態(tài)函數(shù);
靜態(tài)全局變量:限制變量的作用域,僅在本文件中訪問,其他文件不可訪問;
靜態(tài)局部變量:僅在本函數(shù)體內(nèi)訪問,本文件其他函數(shù)體內(nèi)不可訪問;但靜態(tài)局部變量的值在程序運行期間不會銷毀;
靜態(tài)函數(shù):僅在本文件中調(diào)用,其他文件中不可調(diào)用,即程序員不用擔(dān)心編寫的函數(shù)與其他文件的函數(shù)同名。
總的來說:
(1)在修飾變量的時候,static修飾的靜態(tài)局部變量只執(zhí)行初始化一次,而且延長了局部變量的生命周期,直到程序運行結(jié)束以后才釋放。
(2)static修飾全局變量的時候,這個全局變量只能在本文件中訪問,不能在其它文件中訪問,即便是extern外部聲明也不可以。
(3)static修飾一個函數(shù),則這個函數(shù)的只能在本文件中調(diào)用,不能被其他文件調(diào)用。Static修飾的變量存放在全局?jǐn)?shù)據(jù)區(qū)的靜態(tài)變量區(qū),包括全局靜態(tài)變量和局部靜態(tài)變量,都在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存。初始化的時候自動初始化為0。
(4)不想被釋放的時候,可以使用static修飾。比如修飾函數(shù)中存放在棧空間的數(shù)組。如果不想讓這個數(shù)組在函數(shù)調(diào)用結(jié)束釋放可以使用static修飾。
(5)考慮到數(shù)據(jù)安全性(當(dāng)程序想要使用全局變量的時候應(yīng)該先考慮使用static)
2、static修飾類成員函數(shù)有什么作用
static修飾的函數(shù)叫做靜態(tài)函數(shù),靜態(tài)函數(shù)有兩種,根據(jù)其出現(xiàn)的地方來分類:
如果這個靜態(tài)函數(shù)出現(xiàn)在類里,那么它是一個靜態(tài)成員函數(shù);
靜態(tài)成員函數(shù)的作用在于:調(diào)用這個函數(shù)不會訪問或者修改任何對象(非static)數(shù)據(jù)成員。
其實很好理解,類的靜態(tài)成員(變量和方法)屬于類本身,在類加載的時候就會分配內(nèi)存,可以通過類名直接去訪問;非靜態(tài)成員(變量和方法)屬于類的對象,所以只有在類的對象產(chǎn)生(創(chuàng)建類的實例)時才會分配內(nèi)存,然后通過類的對象(實例)去訪問。
如果它不是出現(xiàn)在類中,那么它是一個普通的全局的靜態(tài)函數(shù)。
這樣的static函數(shù)與普通函數(shù)的區(qū)別是:**用static修飾的函數(shù),限定在本源碼文件中,不能被本源碼文件以外的代碼文件調(diào)用。**而普通的函數(shù),默認(rèn)是extern的,也就是說它可以被其它代碼文件調(diào)用。
在函數(shù)的返回類型前加上關(guān)鍵字static,函數(shù)就被定義成為靜態(tài)函數(shù)。普通 函數(shù)的定義和聲明默認(rèn)情況下是extern的,但靜態(tài)函數(shù)只是在聲明他的文件當(dāng)中可見,不能被其他文件所用。因此定義靜態(tài)函數(shù)有以下好處:
<1> 其他文件中可以定義相同名字的函數(shù),不會發(fā)生沖突。
<2> 靜態(tài)函數(shù)不能被其他文件所用。
3、const用法,const與define區(qū)別,const指針
C++ const 允許指定一個語義約束,編譯器會強(qiáng)制實施這個約束,允許程序員告訴編譯器某值是保持不變的。如果在編程中確實有某個值保持不變,就應(yīng)該明確使用const,這樣可以獲得編譯器的幫助。
1、const與基本數(shù)據(jù)類型
int x = 3;//變量
const int x = 3;//常量
2、const修飾指針變量時:
(1)只有一個const,如果const位于*左側(cè),表示指針?biāo)笖?shù)據(jù)是常量,不能通過解引用修改該數(shù)據(jù);指針本身是變量,可以指向其他的內(nèi)存單元。
(2)只有一個const,如果const位于*右側(cè),表示指針本身是常量,不能指向其他內(nèi)存地址;指針?biāo)傅臄?shù)據(jù)可以通過解引用修改。
(3)兩個const,*左右各一個,表示指針和指針?biāo)笖?shù)據(jù)都不能修改。
3、const與引用
int x = 3;
const int &y = x;
x = 10;//正確
y = 20;//錯誤,const修飾x的別名y,不能更改
例1:
const int x = 3;
int *y = &x; //erro
x是不可變的,但是我們定義的指針是可變的,可變的指針去指向一個不可變的變量,就會存在風(fēng)險,會通過指針y來改變x的值;權(quán)限大的去接受權(quán)限小的,是不可行
二、const與#define的區(qū)別
(1) 編譯器處理方式不同
define宏是在預(yù)處理階段展開。
const常量是編譯運行階段使用。
(2) 類型和安全檢查不同
define宏沒有類型,不做任何類型檢查,僅僅是展開。
const常量有具體的類型,在編譯階段會執(zhí)行類型檢查。
(3) 存儲方式不同
define宏僅僅是展開,有多少地方使用,就展開多少次,不會分配內(nèi)存。(宏定義不分配內(nèi)存,變量定義分配內(nèi)存。)
const常量會在內(nèi)存中分配(可以是堆中也可以是棧中)。
(4)const 可以節(jié)省空間,避免不必要的內(nèi)存分配。 例如:
#define PI 3.14159 //常量宏
const doulbe Pi=3.14159; //此時并未將Pi放入ROM中 …
double i=Pi; //此時為Pi分配內(nèi)存,以后不再分配!
double I=PI; //編譯期間進(jìn)行宏替換,分配內(nèi)存
double j=Pi; //沒有內(nèi)存分配
double J=PI; //再進(jìn)行宏替換,又一次分配內(nèi)存!
const定義常量從匯編的角度來看,只是給出了對應(yīng)的內(nèi)存地址,而不是象#define一樣給出的是立即數(shù),所以,const定義的常量在程序運行過程中只有一份拷貝(因為是全局的只讀變量,存在靜態(tài)區(qū)),而 #define定義的常量在內(nèi)存中有若干個拷貝。
(5) 提高了效率。 編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內(nèi)存的操作,使得它的效率也很高。
(6) 宏替換只作替換,不做計算,不做表達(dá)式求解;
宏預(yù)編譯時就替換了,程序運行時,并不分配內(nèi)存。
const 與 #define的比較
C++ 語言可以用const來定義常量,也可以用 #define來定義常量。但是前者比后者有更多的優(yōu)點:
(1) const常量有數(shù)據(jù)類型,而宏常量沒有數(shù)據(jù)類型。編譯器可以對前者進(jìn)行類型安全檢查。而對后者只進(jìn)行字符替換,沒有類型安全檢查,并且在字符替換可能會產(chǎn)生意料不到的錯誤(邊際效應(yīng))。
(2) 有些集成化的調(diào)試工具可以對const常量進(jìn)行調(diào)試,但是不能對宏常量進(jìn)行調(diào)試。
4、指針和引用的區(qū)別
精簡版:
指針:變量,獨立,可變,可空,替身,無類型檢查;
引用:別名,依賴,不變,非空,本體,有類型檢查;
完整版:
指針從本質(zhì)上講是一個變量,變量的值是另一個變量的地址,指針在邏輯上是獨立的,它可以被改變的,包括指針變量的值(所指向的地址)和指針變量的值對應(yīng)的內(nèi)存中的數(shù)據(jù)(所指向地址中所存放的數(shù)據(jù))。
引用從本質(zhì)上講是一個別名,是另一個變量的同義詞,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化(先有這個變量,這個實物,這個實物才能有別名),而且其引用的對象在其整個生命周期中不能被改變,即自始至終只能依附于同一個變量(初始化的時候代表的是誰的別名,就一直是誰的別名,不能變)。
(1)指針:指針是一個變量,只不過這個變量存儲的是一個地址,指向內(nèi)存的一個存儲單元,即指針是一個實體;而引用跟原來的變量實質(zhì)上是一個東西,只不過是原變量的一個別名而已。如:
int a = 1; int *p = &a;
int a = 1; int &b = a;
1
2
上面定義了一個整型變量和一個指針變量p,該指針變量指向a的存儲單元,即p的值是a存儲單元的地址。
而下面2句定義了一個整型變量a和這個整型a的引用b,事實上a和b是同一個東西,在內(nèi)存占有同一個存儲單元。
(2)可以有const指針,但是沒有const引用;
(3)指針可以有多級,但是引用只能是一級(int **p;合法 而 int &&a是不合法的);
(4)指針的值可以為空,但是引用的值不能為NULL,并且引用在定義的時候必須初始化;
(5)指針的值在初始化后可以改變,即指向其它的存儲單元,而引用在進(jìn)行初始化后就不會再改變了,從一而終。
(6)sizeof引用得到的是所指向的變量(對象)的大小,而sizeof指針得到的是指針本身的大小;
(7)指針和引用的自增(++)運算意義不一樣;
二、相同點
都是地址的概念;
指針指向一塊內(nèi)存,它的內(nèi)容是所指內(nèi)存的地址;
引用是某塊內(nèi)存的別名。
5、什么情況會用到引用傳遞
引用傳遞與值傳遞的區(qū)別就是:引用傳遞的時候,操作的是同一個對象,對現(xiàn)在的操作會改變原來的對象的值;而值傳遞的時候,操作的是原來對象的一個拷貝。對現(xiàn)對象的改變不會改變原來的對象的值
C++中的指針參數(shù)傳遞和引用參數(shù)傳遞
指針參數(shù)傳遞本質(zhì)上是值傳遞,它所傳遞的是一個地址值。值傳遞過程中,被調(diào)函數(shù)的形式參數(shù)作為被調(diào)函數(shù)的局部變量處理,會在棧中開辟內(nèi)存空間以存放由主調(diào)函數(shù)傳遞進(jìn)來的實參值,從而形成了實參的一個副本(替身)。值傳遞的特點是,被調(diào)函數(shù)對形式參數(shù)的任何操作都是作為局部變量進(jìn)行的,不會影響主調(diào)函數(shù)的實參變量的值(形參指針變了,實參指針不會變)。
引用參數(shù)傳遞過程中,被調(diào)函數(shù)的形式參數(shù)也作為局部變量在棧中開辟了內(nèi)存空間,但是這時存放的是由主調(diào)函數(shù)放進(jìn)來的實參變量的地址。被調(diào)函數(shù)對形參(本體)的任何操作都被處理成間接尋址,即通過棧中存放的地址訪問主調(diào)函數(shù)中的實參變量(根據(jù)別名找到主調(diào)函數(shù)中的本體)。因此,被調(diào)函數(shù)對形參的任何操作都會影響主調(diào)函數(shù)中的實參變量。
引用傳遞和指針傳遞是不同的,雖然他們都是在被調(diào)函數(shù)棧空間上的一個局部變量,但是任何對于引用參數(shù)的處理都會通過一個間接尋址的方式操作到主調(diào)函數(shù)中的相關(guān)變量。而對于指針傳遞的參數(shù),如果改變被調(diào)函數(shù)中的指針地址,它將應(yīng)用不到主調(diào)函數(shù)的相關(guān)變量。如果想通過指針參數(shù)傳遞來改變主調(diào)函數(shù)中的相關(guān)變量(地址),那就得使用指向指針的指針或者指針引用。
從編譯的角度來講,程序在編譯時分別將指針和引用添加到符號表上,符號表中記錄的是變量名及變量所對應(yīng)地址。指針變量在符號表上對應(yīng)的地址值為指針變量的地址值,而引用在符號表上對應(yīng)的地址值為引用對象的地址值(與實參名字不同,地址相同)。符號表生成之后就不會再改,因此指針可以改變其指向的對象(指針變量中的值可以改),而引用對象則不能修改。
6、為什么在.h文件中使用#ifdef……
***這是一種防止頭文件被多次包含的預(yù)處理技術(shù),***由于各種原因可能是有問題的。在編譯項目時,編譯每個.cpp文件(通常)。簡單來說,這意味著編譯器會把你的.cpp文件,打開任何文件#included,將它們?nèi)窟B接成一個海量文本文件,然后執(zhí)行語法分析,最后將它轉(zhuǎn)換成一些中間代碼,優(yōu)化/執(zhí)行其他任務(wù),最后生成目標(biāo)架構(gòu)的匯編輸出。因此,如果#included一個.cpp文件下的文件多次,則編譯器將附加文件內(nèi)容兩次,因此如果該文件中有定義,你會收到一個編譯器錯誤,告訴你重新定義了一個變量。FILE_H當(dāng)編譯過程中的預(yù)處理器步驟處理文件時,首次到達(dá)其內(nèi)容時,前兩行將檢查是否已為預(yù)處理器定義。如果沒有,它將定義FILE_H并繼續(xù)處理它和指令之間的代碼#endif。下一次該文件的內(nèi)容被預(yù)處理器看到時,檢查FILE_H將是假的,所以它將立即掃描#endif并繼續(xù)。這樣可以防止重新定義錯誤。它將定義并繼續(xù)處理它和指令之間的代碼
7、什么函數(shù)不能定義為虛函數(shù)
常見的不能聲明為虛函數(shù)的有:普通函數(shù)(非成員函數(shù));靜態(tài)成員函數(shù);內(nèi)聯(lián)成員函數(shù);構(gòu)造函數(shù);友元函數(shù)。
1.為什么C++不支持普通函數(shù)為虛函數(shù)?
普通函數(shù)(非成員函數(shù))只能被overload,不能被override,聲明為虛函數(shù)也沒有什么意思,因此編譯器會在編譯時邦定函數(shù)。
2.為什么C++不支持構(gòu)造函數(shù)為虛函數(shù)?
這個原因很簡單,主要是從語義上考慮,所以不支持。因為構(gòu)造函數(shù)本來就是為了明確初始化對象成員才產(chǎn)生的,然而virtual function主要是為了再不完全了解細(xì)節(jié)的情況下也能正確處理對象。另外,virtual函數(shù)是在不同類型的對象產(chǎn)生不同的動作,現(xiàn)在對象還沒有產(chǎn)生,如何使用virtual函數(shù)來完成你想完成的動作。(這不就是典型的悖論)
3.為什么C++不支持內(nèi)聯(lián)成員函數(shù)為虛函數(shù)?
其實很簡單,那內(nèi)聯(lián)函數(shù)就是為了在代碼中直接展開,減少函數(shù)調(diào)用花費的代價,虛函數(shù)是為了在繼承后對象能夠準(zhǔn)確的執(zhí)行自己的動作,這是不可能統(tǒng)一的。(再說了,inline函數(shù)在編譯時被展開,虛函數(shù)在運行時才能動態(tài)的邦定函數(shù))
4.為什么C++不支持靜態(tài)成員函數(shù)為虛函數(shù)?
這也很簡單,靜態(tài)成員函數(shù)對于每個類來說只有一份代碼,所有的對象都共享這一份代碼,他不歸某個具體對象所有,所以他也沒有要動態(tài)邦定的必要性。
5.為什么C++不支持友元函數(shù)為虛函數(shù)?
因為C++不支持友元函數(shù)的繼承,對于沒有繼承特性的函數(shù)沒有虛函數(shù)的說法。
8、智能指針作用及分類
智能指針是一個類,這個類的構(gòu)造函數(shù)中傳入一個普通指針,析構(gòu)函數(shù)中釋放傳入的指針。智能指針的類都是棧上的對象,所以當(dāng)函數(shù)(或程序)結(jié)束時會自動被釋放。
作用
C++程序設(shè)計中使用堆內(nèi)存是非常頻繁的操作,堆內(nèi)存的申請和釋放都由程序員自己管理。程序員自己管理堆內(nèi)存可以提高了程序的效率,但是整體來說堆內(nèi)存的管理是麻煩的,C++11中引入了智能指針的概念,方便管理堆內(nèi)存。使用普通指針,容易造成堆內(nèi)存泄露(忘記釋放),二次釋放,程序發(fā)生異常時內(nèi)存泄露等問題等,使用智能指針能更好的管理堆內(nèi)存。
智能指針主要用于管理在堆上分配的內(nèi)存,它將普通的指針封裝為一個棧對象。當(dāng)棧對象的生存周期結(jié)束后,會在析構(gòu)函數(shù)中釋放掉申請的內(nèi)存,從而防止內(nèi)存泄漏。
分類:
auto_ptr
在 C++ 語言中,要使用 STL 中的 auto_ptr 對象,必須包含頭文件 memory,該文件包括 auto_ptr 模板。使用通常的模板句法來實例化所需類型的指針。auto_ptr 構(gòu)造函數(shù)是顯式的,不存在從指針到 auto_ptr 對象的隱式類型轉(zhuǎn)換。
auto_ptr(c++98的方案,c++11已經(jīng)拋棄),采用的是所有權(quán)模式。
模板可以通過構(gòu)造函數(shù)將 auto_ptr 對象初始化為一個常規(guī)指針。auto_ptr 是一個智能指針,但其特性遠(yuǎn)比指針要多。值得注意的是,在使用 auto_ptr 時,只能配對使用 new 和 delete。
提示,只能對 new 分配的內(nèi)存使用 auto_ptr 對象,不要對由 new() 分配的或通過聲明變量分配的內(nèi)存使用它。
unique_ptr
unique_ptr實現(xiàn)獨占式擁有或者嚴(yán)格擁有概念,保證同一時間只有一個智能指針可以指向該對象。它對于避免資源泄露特別有用。
shared_ptr
shared_ptr實現(xiàn)共享式擁有概念。多個智能指針可以指向相同對象,該對象和其相關(guān)資源會在最后一個引用被銷毀時候釋放。通過use_count()來查看資源被幾個指針共享。除了可以通過new來構(gòu)造,還可以通過傳入auto_ptr,unique_ptr,weak_ptr來構(gòu)造。當(dāng)我們調(diào)用release()時,當(dāng)前指針會釋放資源所有權(quán),計數(shù)減一。當(dāng)計數(shù)等于0,資源會被釋放。
成員函數(shù):
use_count()返回引用計數(shù)的個數(shù);
unique()返回是否獨占所有權(quán);
swap()交換兩個shared_pt6;
reset()放棄內(nèi)部對象的所有權(quán)或者擁有對象的變更,會引起原來對象的引用計數(shù)的減少;
get()返回內(nèi)部對象的地址。
weak_ptr
weak_ptr是用來解決shared_ptr相互引用時的死鎖問題,如果說兩個shared_ptr相互引用,那么這兩個指針的引用計數(shù)永遠(yuǎn)不可能下降為0,資源永遠(yuǎn)不會釋放。它是對對象的一種弱引用,不會增加對象的引用計數(shù),和shared_ptr之間可以相互轉(zhuǎn)化,shared_ptr可以直接賦值給它,它可以通過調(diào)用lock函數(shù)來獲得shared_ptr。
成員函數(shù)比shared_ptr多了兩個,但是少了get():
expired() 為use_count()為0,返回true,否則返回false;
lock()如果expired為空,返回空的shared_ptr;否則返回一個指向?qū)ο蟮膕hared_ptr;
總結(jié)
不要把一個原生指針給多個智能指針對象管理, 對所有的智能指針對象都成立。
不要把 this 指針給智能指針對象,對所有的智能指針對象(包括 auto_ptr)都成立。
不要在函數(shù)實參里創(chuàng)建智能指針對象。
處理不是 new 創(chuàng)建的對象要小心. 如果確實需要這樣做, 需要智能指針傳遞一個刪除器, 自定義刪除行為。
不要使用 new 創(chuàng)建一個智能指針對象.如 new shared_ptr 。
使用 dynamic_pointer_cast 進(jìn)行轉(zhuǎn)換。
不要 memcpy 智能指針對象。
智能指針對象數(shù)組的使用, 需要自定義釋放器。
將智能指針對象作為函數(shù)參數(shù)傳遞時要小心, 如下面的代碼, 當(dāng)調(diào)用所在的表達(dá)式結(jié)束(即函數(shù)調(diào)用返回)時, 這個臨時對象就被銷毀了, 它所指向的內(nèi)存也被釋放.。
當(dāng)將一個智能指針對象(如 shared_ptr)綁定到一個普通指針時, 就將內(nèi)存管理的責(zé)任交給了這個 shared_ptr. 此后就不應(yīng)該使用內(nèi)置指針來訪問 shared_ptr 所指向的內(nèi)存了。
不能使用 delete 釋放 get 返回的普通指針. get 函數(shù)的設(shè)計是為了向不能使用智能指針的代碼傳遞一個普通指針, 應(yīng)該減少 get 函數(shù)的調(diào)用。
不要使用 get 返回的普通指針來初始化另一個智能指針, 或為另一個智能指針賦值. 顯然如果這樣做, 將導(dǎo)致兩次釋放相同的內(nèi)存, 或者其中一個已經(jīng)將內(nèi)存釋放, 但另一個還在使用。
9、結(jié)構(gòu)體與類、聯(lián)合體的區(qū)別
首先一句話——在C++中,結(jié)構(gòu)體和類沒有什么區(qū)別,唯一的區(qū)別就是:默認(rèn)的訪問權(quán)限和繼承訪問權(quán)限不同。其他的,類能怎么干,結(jié)構(gòu)體也能怎么干!
默認(rèn)訪問權(quán)限:結(jié)構(gòu)體是public,類是private
默認(rèn)繼承訪問權(quán)限:結(jié)構(gòu)體是public,類是private
C++ primer 里面講,union是一種特殊的節(jié)省空間的類。
一個union可以有多個數(shù)據(jù)成員,但是在任意時刻只能有一個數(shù)據(jù)成員有值。
也就是說,當(dāng)我們給某一個數(shù)據(jù)成員賦值之后,該union的其他數(shù)據(jù)成員就變成未定義的狀態(tài)了。
分配給一個union的存儲空間至少要容納他的最大的數(shù)據(jù)成員。
union與class類的區(qū)別:
1、與結(jié)構(gòu)體一樣,union的成員的默認(rèn)訪問權(quán)限是public。
2、union可以定義包括構(gòu)造函數(shù)和析構(gòu)函數(shù)在內(nèi)的成員函數(shù)。
3、既不能作為基類被繼承也不能繼承他人,union是獨立的,所以也不能實現(xiàn)虛函數(shù)。
注意的點:
1、union的數(shù)據(jù)成員可以是類類型, 但不能含有引用類型的成員,因為union的所有數(shù)據(jù)成員是要共享內(nèi)存的。
2、因為一旦給union的一個成員賦值的時候,其他的值就變成未定義的狀態(tài)啦,所以在使用union的時候必須知道當(dāng)前union中存的是什么類型值。
10、OSI七層協(xié)議
我們都知道互聯(lián)網(wǎng)的本質(zhì)是一系列的網(wǎng)絡(luò)協(xié)議,這個協(xié)議就叫做OSI(Open System Interconnect——開放式系統(tǒng)互聯(lián)的含義)協(xié)議。
按照功能不同分工不同,人為的分為七層。實際上這七層是并不存在的,也就是說沒有這些概念,而我們今天提到的七層概念,只是人為的劃分而已。目的是為了讓我們更好地理解這些都是用來做什么的。
物理層
是參考模型的最底層。該層是網(wǎng)絡(luò)通信的數(shù)據(jù)傳輸介質(zhì),由連接不同結(jié)點的電纜與設(shè)備共同構(gòu)成。
主要功能是: 利用傳輸介質(zhì)為數(shù)據(jù)鏈路層提供物理連接,負(fù)責(zé)處理數(shù)據(jù)傳輸并監(jiān)控數(shù)據(jù)出錯率,以便數(shù)據(jù)流的透明傳輸。
數(shù)據(jù)鏈路層
是參考模型的第二層。
主要功能是: 在物理層提供的服務(wù)基礎(chǔ)上,在通信的實體間建立數(shù)據(jù)鏈路連接,傳輸以"幀"為單位的數(shù)據(jù)包,并采用差錯控制與流量控制方法,使用差錯的物理線路變成無差錯的數(shù)據(jù)鏈路。
網(wǎng)絡(luò)層
是參考模型的第三層。
主要功能是: 為數(shù)據(jù)在節(jié)點之間傳輸創(chuàng)建邏輯鏈路,通過路由選擇算法為分組通過通信子網(wǎng)選擇最適當(dāng)?shù)穆窂?#xff0c;以及實現(xiàn)擁塞控制、網(wǎng)絡(luò)互連等功能。
傳輸層
是參考模型的第四層。
主要功能是: 向用戶提供可靠地端到端服務(wù),處理數(shù)據(jù)包錯誤、數(shù)據(jù)包次序,以及其他一些關(guān)鍵傳輸問題。傳輸層向高層屏蔽了下層數(shù)據(jù)通信的細(xì)節(jié)。因此,它是計算機(jī)通信體系結(jié)構(gòu)中關(guān)鍵的一層。
會話層
是參考模型的第五層。
主要功能是: 負(fù)責(zé)維護(hù)兩個結(jié)點之間的傳輸連接,以便確保點到點傳輸不中斷,以及管理數(shù)據(jù)交換等功能。
表示層
是參考模型的第六層
主要功能: 用于處理在兩個通信系統(tǒng)中交換信息的表示方法,主要包括數(shù)據(jù)格式變換、數(shù)據(jù)加密與解密、數(shù)據(jù)壓縮與恢復(fù)等功能。
應(yīng)用層
是參考模型的最高層。
主要功能是: 為應(yīng)用軟件提供了很多服務(wù),比如文件服務(wù)器、數(shù)據(jù)庫服務(wù)、電子郵件與其他網(wǎng)絡(luò)軟件服務(wù)。
11、三次握手
三次握手(Three-way Handshake)其實就是指建立一個TCP連接時,需要客戶端和服務(wù)器總共發(fā)送3個包。進(jìn)行三次握手的主要作用就是為了確認(rèn)雙方的接收能力和發(fā)送能力是否正常、指定自己的初始化序列號為后面的可靠性傳送做準(zhǔn)備。實質(zhì)上其實就是連接服務(wù)器指定端口,建立TCP連接,并同步連接雙方的序列號和確認(rèn)號,交換TCP窗口大小信息。
剛開始客戶端處于 Closed 的狀態(tài),服務(wù)端處于 Listen 狀態(tài)。
進(jìn)行三次握手:
第一次握手:客戶端給服務(wù)端發(fā)一個 SYN 報文,并指明客戶端的初始化序列號 ISN。此時客戶端處于 SYN_SENT 狀態(tài)。
首部的同步位SYN=1,初始序號seq=x,SYN=1的報文段不能攜帶數(shù)據(jù),但要消耗掉一個序號。
第二次握手:服務(wù)器收到客戶端的 SYN 報文之后,會以自己的 SYN 報文作為應(yīng)答,并且也是指定了自己的初始化序列號 ISN(s)。同時會把客戶端的 ISN + 1 作為ACK 的值,表示自己已經(jīng)收到了客戶端的 SYN,此時服務(wù)器處于 SYN_RCVD 的狀態(tài)。
在確認(rèn)報文段中SYN=1,ACK=1,確認(rèn)號ack=x+1,初始序號seq=y。
第三次握手:客戶端收到 SYN 報文之后,會發(fā)送一個 ACK 報文,當(dāng)然,也是一樣把服務(wù)器的 ISN + 1 作為 ACK 的值,表示已經(jīng)收到了服務(wù)端的 SYN 報文,此時客戶端處于 ESTABLISHED 狀態(tài)。服務(wù)器收到 ACK 報文之后,也處于 ESTABLISHED 狀態(tài),此時,雙方已建立起了連接。
確認(rèn)報文段ACK=1,確認(rèn)號ack=y+1,序號seq=x+1(初始為seq=x,第二個報文段所以要+1),ACK報文段可以攜帶數(shù)據(jù),不攜帶數(shù)據(jù)則不消耗序號。
發(fā)送第一個SYN的一端將執(zhí)行主動打開(active open),接收這個SYN并發(fā)回下一個SYN的另一端執(zhí)行被動打開(passive open)。
12、進(jìn)程與線程區(qū)別
進(jìn)程與線程的區(qū)別
線程具有許多傳統(tǒng)進(jìn)程所具有的特征,故又稱為輕型進(jìn)程(Light—Weight Process)或進(jìn)程元;而把傳統(tǒng)的進(jìn)程稱為重型進(jìn)程(Heavy—Weight Process),它相當(dāng)于只有一個線程的任務(wù)。在引入了線程的操作系統(tǒng)中,通常一個進(jìn)程都有若干個線程,至少包含一個線程。
根本區(qū)別:進(jìn)程是操作系統(tǒng)資源分配的基本單位,而線程是處理器任務(wù)調(diào)度和執(zhí)行的基本單位
資源開銷:每個進(jìn)程都有獨立的代碼和數(shù)據(jù)空間(程序上下文),程序之間的切換會有較大的開銷;線程可以看做輕量級的進(jìn)程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程都有自己獨立的運行棧和程序計數(shù)器(PC),線程之間切換的開銷小。
包含關(guān)系:如果一個進(jìn)程內(nèi)有多個線程,則執(zhí)行過程不是一條線的,而是多條線(線程)共同完成的;線程是進(jìn)程的一部分,所以線程也被稱為輕權(quán)進(jìn)程或者輕量級進(jìn)程。
內(nèi)存分配:同一進(jìn)程的線程共享本進(jìn)程的地址空間和資源,而進(jìn)程之間的地址空間和資源是相互獨立的
影響關(guān)系:一個進(jìn)程崩潰后,在保護(hù)模式下不會對其他進(jìn)程產(chǎn)生影響,但是一個線程崩潰整個進(jìn)程都死掉。所以多進(jìn)程要比多線程健壯。
執(zhí)行過程:每個獨立的進(jìn)程有程序運行的入口、順序執(zhí)行序列和程序出口。但是線程不能獨立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制,兩者均可并發(fā)執(zhí)行
13、判斷鏈表有環(huán)
暴力法、哈希表、快慢指針
14、平衡二叉樹定義
如果在二叉查找樹中一開始給定的數(shù)列是有序的,那么在構(gòu)建二叉查找樹時就會形成一條很長的鏈條式的樹,此時對這棵樹的查找復(fù)雜度將會變成O(n),起不到使用二叉查找樹來進(jìn)行數(shù)據(jù)查詢優(yōu)化的目的,于是需要對這顆樹的結(jié)構(gòu)進(jìn)行調(diào)整,使樹的高度在每次插入元素后仍然能保持O(logn)的級別,這樣能讓查詢的時間仍然是O(logn),于是就產(chǎn)生了平衡二叉樹。
平衡二叉樹由前蘇聯(lián)兩位數(shù)學(xué)家提出,因此一般也稱為AVL樹,AVL樹仍然是一顆二叉查找樹,只是在其基礎(chǔ)上增加了“平衡”的要求。所謂平衡是指,對AVL樹的任意結(jié)點來說,其左子樹與右子樹的高度之差的絕對值不超過1,其中左子樹與右子樹的高度之差稱為該結(jié)點的平衡因子
只要能隨時保證每個結(jié)點的平衡因子的絕對值不超過1, AVL的高度就始終能保持O(logn)級別,由于需要對每個結(jié)點都得到平衡因子,因此需要在樹的結(jié)構(gòu)中加入一個變量height,用來記錄以當(dāng)前結(jié)點為根結(jié)點的子樹的高度。
15、用兩個棧實現(xiàn)一個隊列
實現(xiàn)隊列
總結(jié)
以上是生活随笔為你收集整理的招商银行/招银网络科技面经、答案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MTK Modem编译
- 下一篇: matlab振荡环节相频特性,自动控制原