本篇參考網(wǎng)上及自身的面試經(jīng)驗(yàn),總結(jié)一些高頻考察的Linux C/C++知識(shí)點(diǎn)耗绿,方便后續(xù)查閱總結(jié)吓妆。
一、C/C++編程基礎(chǔ)
C++多態(tài)的實(shí)現(xiàn)
virtual關(guān)鍵字修飾基類(lèi)的成員函數(shù)宣渗,派生類(lèi)中重寫(xiě)此函數(shù)抖所,實(shí)現(xiàn)多態(tài)
- static_cast
static_cast<type>(expression)
該運(yùn)算符把 expression 轉(zhuǎn)換為 type 類(lèi)型,主要用于基本數(shù)據(jù)類(lèi)型之間的轉(zhuǎn)換痕囱,如把 uint 轉(zhuǎn)換為 int田轧,把 int 轉(zhuǎn)換為 double 等。
另外鞍恢,static_cast 還可用于類(lèi)層次結(jié)構(gòu)中傻粘,基類(lèi)和派生類(lèi)之間指針或引用的轉(zhuǎn)換,但也要注意:
static_cast 進(jìn)行上行轉(zhuǎn)換是安全的帮掉,即把派生類(lèi)的指針轉(zhuǎn)換為基類(lèi)的弦悉;
static_cast 進(jìn)行下行轉(zhuǎn)換是不安全的,即把基類(lèi)的指針轉(zhuǎn)換為派生類(lèi)的蟆炊。
注:static_cast 沒(méi)有運(yùn)行時(shí)類(lèi)型檢查來(lái)保證轉(zhuǎn)換的安全性稽莉,需要程序員來(lái)判斷轉(zhuǎn)換是否安全。
uint x = 1;
int y = static_cast<int>(x); // 轉(zhuǎn)換正確
int x = 1;
double y = static_cast<double>(x); // 轉(zhuǎn)換正確
// 上行轉(zhuǎn)換涩搓,派生類(lèi)→基類(lèi)
Derive* d = new Derive();
Base* b = static_cast<Base*>(d);
// 下行轉(zhuǎn)換污秆,基類(lèi)→派生類(lèi)
Base* b = new Base();
Derive* d = static_cast<Derive*>(b);
const_cast
const_cast<type>(expression)
主要是用來(lái)去除復(fù)合類(lèi)型中const和volatile屬性(沒(méi)有真正去除)。expression 和 type 的類(lèi)型需要保持一致昧甘。dynamic_cast
dynamic_cast<type>(expression)
主要用于類(lèi)層次間的上行轉(zhuǎn)換或下行轉(zhuǎn)換良拼。在進(jìn)行上行轉(zhuǎn)換時(shí),dynamic_cast 和 static_cast 的效果是一樣的充边,但在下行轉(zhuǎn)換時(shí)庸推,dynamic_cast 具有類(lèi)型檢查的功能,比 static_cast 更安全。reinterpret_cast
reinterpret_cast<type>(expression)
該運(yùn)算符可以把一個(gè)指針轉(zhuǎn)換成一個(gè)整數(shù)贬媒,也可以把一個(gè)整數(shù)轉(zhuǎn)換成一個(gè)指針刮吧。
限制變量或函數(shù)作用域
被static關(guān)鍵字修飾的全局函數(shù)或者變量具有文件作用域,即只在當(dāng)前文件中可見(jiàn)掖蛤。保持變量?jī)?nèi)容的持久
被static修飾的變量會(huì)被存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)杀捻,生命周期也為從定義直至程序結(jié)束。對(duì)于局部變量蚓庭,即使在函數(shù)退出后該靜態(tài)變量依然存在致讥,然而卻也無(wú)法訪問(wèn)。此外器赞,static修飾的變量一生只會(huì)被初始化一次垢袱。默認(rèn)初始化為0
因?yàn)楸籹tatic修飾的變量會(huì)被存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū),所以才有了這個(gè)一條港柜。因?yàn)殪o態(tài)存儲(chǔ)區(qū)的變量會(huì)被默認(rèn)初始化為0请契。
除此之外,在C++中夏醉,static也可以類(lèi)成員變量和類(lèi)成員函數(shù)爽锥。
類(lèi)的靜態(tài)成員函數(shù)是屬于整個(gè)類(lèi)而非類(lèi)的對(duì)象,所以它沒(méi)有this指針畔柔,這就導(dǎo)致 了它僅能訪問(wèn)類(lèi)的靜態(tài)數(shù)據(jù)和靜態(tài)成員函數(shù)氯夷。
靜態(tài)成員函數(shù)不含有this指針,所以可以作為回調(diào)函數(shù)靶擦。但同時(shí)為了可以訪問(wèn)類(lèi)的成員變量可以將對(duì)象的this指針當(dāng)做實(shí)參傳入回調(diào)函數(shù)中腮考。
靜態(tài)成員函數(shù)在類(lèi)定義體外定義時(shí)不能加static關(guān)鍵字修飾,因?yàn)槌蓡T函數(shù)本是類(lèi)作用域玄捕,而在類(lèi)外用static修飾會(huì)將其作用于擴(kuò)大為文件作用域踩蔚,所以是不合理的。
靜態(tài)成員變量并不像一般的成員變量在構(gòu)造函數(shù)中初始化枚粘,而是在類(lèi)的實(shí)現(xiàn)文件中初始化馅闽,即必須在.cpp文件中初始化,否則在程序鏈接時(shí)會(huì)出錯(cuò)赌结,重定義捞蛋,且初始化時(shí)無(wú)需再使用static關(guān)鍵字修飾孝冒。
static修飾的const成員變量可以再類(lèi)中被定義時(shí)初始化柬姚。
利用static只會(huì)被初始化一次的特性,可以實(shí)現(xiàn)單例對(duì)象庄涡。
extern 有什么作用
extern用在變量或者函數(shù)的聲明前量承,用來(lái)說(shuō)明“此變量/函數(shù)是在別處定義的,要在此處引用”。extern聲明既不是定義撕捍,也不分配存儲(chǔ)空間拿穴。說(shuō)一說(shuō)const關(guān)鍵字
const關(guān)鍵字告訴了編譯器,它修飾的目標(biāo)值不能被改變忧风,如果代碼中發(fā)現(xiàn)有類(lèi)似改變?cè)撟兞康牟僮髂敲淳幾g器就會(huì)捕捉這個(gè)錯(cuò)誤。修飾函數(shù)時(shí)狮腿,
好的編程習(xí)慣告誡程序員腿宰,當(dāng)不需要改變的變量,最好使用const修飾缘厢,例如非頭文件定義的常量吃度,最好用const而非define。sizeof 和 strlen 的區(qū)別
- sizeof會(huì)將空字符\0計(jì)算在內(nèi)贴硫,而strlen不會(huì)將空字符\0計(jì)算在內(nèi)椿每;
- sizeof會(huì)計(jì)算到字符串最后一個(gè)空字符\0并結(jié)束,而strlen如果遇到第一個(gè)空字符\0的話就會(huì)停止并計(jì)算遇到的第一個(gè)空字符\0前面的長(zhǎng)度英遭。
#define 只是在預(yù)處理階段簡(jiǎn)單的做字符替換间护,其可以實(shí)現(xiàn)宏函數(shù)和變量等;const是在編譯挖诸、運(yùn)行階段起作用兑牡,修飾變量。
const 定義的常數(shù)是變量也帶類(lèi)型税灌,#define 定義的只是個(gè)常數(shù) 不帶類(lèi)型均函。
#define只是簡(jiǎn)單的字符串替換,沒(méi)有類(lèi)型檢查菱涤。而const有對(duì)應(yīng)的數(shù)據(jù)類(lèi)型苞也,是要進(jìn)行判斷的,可以避免一些低級(jí)的錯(cuò)誤粘秆。
#define屬于預(yù)處理如迟,會(huì)占用代碼空間;const+類(lèi)型定義屬于變量定義攻走,占用數(shù)據(jù)段空間殷勘。
一個(gè)指針可以是 volatile 嗎
可以。volatile關(guān)鍵詞修飾的變量意思為值可能會(huì)改變昔搂,指針是可以改變的玲销,與const關(guān)鍵詞相反。定義和聲明的區(qū)別
聲明是將一個(gè)名稱引入程序摘符,定義提供了一個(gè)實(shí)體在程序中的唯一描述贤斜。什么是野指針
訪問(wèn)一個(gè)已銷(xiāo)毀或者訪問(wèn)受限的內(nèi)存區(qū)域的指針策吠。野指針的使用,可能會(huì)引起程序崩潰瘩绒,且無(wú)法用NULL檢測(cè)野指針猴抹。指針和引用的區(qū)別
指針是一個(gè)變量,存儲(chǔ)的是一個(gè)地址锁荔,指向內(nèi)存的一個(gè)存儲(chǔ)單元蟀给,指針變量占用內(nèi)存;
引用是原變量的一個(gè)別名阳堕,跟原來(lái)的變量實(shí)質(zhì)上是同一個(gè)東西坤溃,引用變量不占用內(nèi)存。簡(jiǎn)述指針常量與常量指針區(qū)別
指針常量:本質(zhì)是一個(gè)常量嘱丢,而用指針修飾它薪介。指針常量的值是指針,這個(gè)值因?yàn)槭浅A吭阶ぃ圆荒鼙毁x值汁政。
常量指針:又叫常指針,可以理解為常量的指針缀旁,也即這個(gè)是指針记劈,但指向的是個(gè)常量,這個(gè)常量是指針的值(地址)并巍,而不是地址指向的值目木。引用作為函數(shù)參數(shù)以及返回值的好處
在內(nèi)存中不產(chǎn)生被返回值的副本。(注意:正是因?yàn)檫@點(diǎn)原因懊渡,所以返回一個(gè)局部變量的引用是不可取的刽射。因?yàn)殡S著該局部變量生存期的結(jié)束,相應(yīng)的引用也會(huì)失效剃执,產(chǎn)生runtime error!)-
內(nèi)存管理32位.png
stack棧區(qū):專門(mén)用來(lái)實(shí)現(xiàn)函數(shù)調(diào)用-棧結(jié)構(gòu)的內(nèi)存塊誓禁。相對(duì)空間下(可以設(shè)置大小,Linux 一般默認(rèn)是8M肾档,可通過(guò) ulimit –s 查看)摹恰,系統(tǒng)自動(dòng)管理,從高地址往低地址怒见,向下生長(zhǎng)俗慈。
內(nèi)存映射區(qū):包括文件映射和匿名內(nèi)存映射, 應(yīng)用程序的所依賴的動(dòng)態(tài)庫(kù)遣耍,會(huì)在程序執(zhí)行時(shí)候闺阱,加載到內(nèi)存這個(gè)區(qū)域,一般包括數(shù)據(jù)(data)和代碼(text);通過(guò)mmap系統(tǒng)調(diào)用配阵,可以把特定的文件映射到內(nèi)存中馏颂,然后在相應(yīng)的內(nèi)存區(qū)域中操作字節(jié)來(lái)訪問(wèn)文件內(nèi)容,實(shí)現(xiàn)更高效的IO操作棋傍;匿名映射救拉,在glibc中malloc分配大內(nèi)存的時(shí)候會(huì)用到匿名映射。這里所謂的“大”表示是超過(guò)了MMAP_THRESHOLD 設(shè)置的字節(jié)數(shù)瘫拣,它的缺省值是 128 kB亿絮,可以通過(guò) mallopt() 去調(diào)整這個(gè)設(shè)置值。還可以用于進(jìn)程間通信IPC(共享內(nèi)存)麸拄。
heap堆區(qū):主要用于用戶動(dòng)態(tài)內(nèi)存分配派昧,空間大,使用靈活拢切,但需要用戶自己管理蒂萎,通過(guò)brk系統(tǒng)調(diào)用控制堆的生長(zhǎng),向高地址生長(zhǎng)淮椰。
BBS段和DATA段:用于存放程序全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)五慈,一般未初始化的放在BSS段(統(tǒng)一初始化為0,不占程序文件的空間)主穗,初始化的放在data段泻拦,只讀數(shù)據(jù)放在rodata段(常量存儲(chǔ)區(qū))。
text段:主要存放程序二進(jìn)制代碼忽媒。
共同點(diǎn):
- 都是從堆上申請(qǐng)空間架曹,并且需要用戶手動(dòng)釋放。
不同點(diǎn):
malloc和free是函數(shù)闹瞧,new和delete是操作符
malloc申請(qǐng)的空間不會(huì)初始化音瓷,new可以初始化
malloc申請(qǐng)空間時(shí),需要手動(dòng)計(jì)算空間大小并傳遞夹抗,new只需在其后跟上空間的類(lèi)型即可绳慎。
malloc的返回值為void*, 在使用時(shí)必須強(qiáng)轉(zhuǎn),new不需要漠烧,因?yàn)閚ew后跟的是空間的類(lèi)型杏愤。
malloc申請(qǐng)空間失敗時(shí),返回的是NULL已脓,因此使用時(shí)必須判空珊楼,new不需要,但是new需要捕獲異常度液。
申請(qǐng)自定義類(lèi)型對(duì)象時(shí)厕宗,malloc/free只會(huì)開(kāi)辟空間画舌,不會(huì)調(diào)用構(gòu)造函數(shù)與析構(gòu)函數(shù),而new在申請(qǐng)空間后會(huì)調(diào)用構(gòu)造函數(shù)完成對(duì)象的初始化已慢,delete在釋放空間前會(huì)調(diào)用析構(gòu)函數(shù)完成空間中資源的清理曲聂。
delete和delete[]的區(qū)別
delete只會(huì)調(diào)用一次析構(gòu)函數(shù),而delete []會(huì)調(diào)用每一個(gè)成員的析構(gòu)函數(shù)佑惠。簡(jiǎn)述 strcpy朋腋、sprintf 與 memcpy 的區(qū)別
操作對(duì)象不同,strcpy 的兩個(gè)操作對(duì)象均為字符串; sprintf 的操作源對(duì)象可以是多種數(shù)據(jù)類(lèi)型膜楷,目的操作對(duì)象是字符串; memcpy 的兩個(gè)對(duì)象就是兩個(gè)任意可操作的內(nèi)存地址旭咽,并不限于何種數(shù)據(jù)類(lèi)型。C++的空類(lèi)有哪些成員函數(shù)
一個(gè)默認(rèn)構(gòu)造函數(shù)赌厅、一個(gè)拷貝默認(rèn)構(gòu)造函數(shù)穷绵、一個(gè)默認(rèn)拷貝賦值操作符和一個(gè)默認(rèn)析構(gòu)函數(shù)。這些函數(shù)只有在第一次被調(diào)用時(shí)特愿,才會(huì)被編譯器創(chuàng)建请垛。所有這些函數(shù)都是inline和public的。
構(gòu)造一個(gè)對(duì)象的時(shí)候洽议,必須知道對(duì)象的實(shí)際類(lèi)型宗收,而虛函數(shù)行為是在運(yùn)行期間確定實(shí)際類(lèi)型的。而在構(gòu)造一個(gè)對(duì)象時(shí)亚兄,由于對(duì)象還未構(gòu)造成功混稽。編譯器無(wú)法知道對(duì)象 的實(shí)際類(lèi)型,是該類(lèi)本身审胚,還是該類(lèi)的一個(gè)派生類(lèi)匈勋,或是更深層次的派生類(lèi)。無(wú)法確定膳叨。洽洁。。
虛函數(shù)的執(zhí)行依賴于虛函數(shù)表菲嘴。而虛函數(shù)表在構(gòu)造函數(shù)中進(jìn)行初始化工作饿自,即初始化vptr,讓他指向正確的虛函數(shù)表龄坪。而在構(gòu)造對(duì)象期間昭雌,虛函數(shù)表還沒(méi)有被初始化,將無(wú)法進(jìn)行健田。
- 深拷貝和淺拷貝的區(qū)別
淺拷貝: 與拷貝對(duì)象共享同一片內(nèi)存烛卧。只復(fù)制對(duì)象的基本類(lèi)型,對(duì)象類(lèi)型,仍屬于原來(lái)的引用。
深拷貝: 申請(qǐng)新的內(nèi)存妓局,并將目標(biāo)對(duì)象復(fù)制到新的內(nèi)存总放。
- 知道STL嗎呈宇,挑兩個(gè)你最常用的容器說(shuō)一說(shuō)
容器分為兩大類(lèi): 順序容器和關(guān)聯(lián)容器
-
順序容器
順序容器有以下三種:可變長(zhǎng)動(dòng)態(tài)數(shù)組 vector、雙端隊(duì)列 deque局雄、雙向鏈表 list甥啄。之所以被稱為順序容器,是因?yàn)樵卦谌萜髦械奈恢猛氐闹禑o(wú)關(guān)哎榴,即容器不是排序的型豁。將元素插入容器時(shí)僵蛛,指定在什么位置(尾部尚蝌、頭部或中間某處)插入,元素就會(huì)位于什么位置充尉。
deuque:
deque是雙向開(kāi)口的連續(xù)線性空間,支持內(nèi)部元素的隨機(jī)訪問(wèn)倒源。
擅長(zhǎng)在序列尾部添加或刪除元素(時(shí)間復(fù)雜度為O(1))苛预,而不擅長(zhǎng)在序列中間添加或刪除元素。且支持頭部添加和刪除元素的成員笋熬。list:
雙向鏈表容器热某,即該容器的底層是以雙向鏈表的形式實(shí)現(xiàn)的。非連續(xù)空間胳螟、通過(guò)指針來(lái)連接每一個(gè)小空間昔馋、插入和刪除都是O(1)操作,元素訪問(wèn)效率較低等等糖耸,不支持隨機(jī)訪問(wèn)秘遏。 -
關(guān)聯(lián)容器
關(guān)聯(lián)容器有以下四種:set坤邪、multiset筒溃、map澄者、multimap朦蕴。關(guān)聯(lián)容器內(nèi)的元素是排序的夜牡。插入元素時(shí)遗增,容器會(huì)按一定的排序規(guī)則將元素放到適當(dāng)?shù)奈恢蒙辖狍虼瞬迦朐貢r(shí)不能指定位置招刹。multiset:
是排序好的集合(元素已經(jīng)進(jìn)行了排序)锅知,并且允許有相同的元素。map:
是有序鍵值對(duì)容器脓钾,它的元素的鍵是唯一的售睹。multimap:
multimap也是存儲(chǔ)兩個(gè)元素之間的映射關(guān)系的容器,不相同的是可训,multimap的key值可以重復(fù)出現(xiàn)昌妹。
STL中的vector的實(shí)現(xiàn),是怎么擴(kuò)容的
vector 為空的時(shí)候沒(méi)有預(yù)分配空間握截,每次添加一個(gè)元素時(shí)飞崖,會(huì)判斷當(dāng)前是否還有剩余可用空間,如果沒(méi)有則進(jìn)行試探性擴(kuò)容谨胞,并且把內(nèi)存拷貝到新申請(qǐng)的內(nèi)存空間上固歪,并且釋放原先的內(nèi)存。-
C++中vector和list的區(qū)別
vector是動(dòng)態(tài)數(shù)組胯努,內(nèi)部存儲(chǔ)是一片連續(xù)性的空間牢裳,支持通過(guò)下標(biāo)隨機(jī)訪問(wèn)。list是雙向鏈表叶沛,內(nèi)部存儲(chǔ)可能是不連續(xù)的空間蒲讯,通過(guò)指針鏈接這些不連續(xù)的空間,不支持隨機(jī)訪問(wèn)灰署。
怎么確定一個(gè)程序是C編譯的還是C++編譯的
如果編譯器在編譯cpp文件那么__cplusplus
就會(huì)被定義 如果是一個(gè)c文件在被編譯那么__STDC__
就會(huì)被定義判帮。說(shuō)一下什么是內(nèi)存泄漏,如何避免
是指程序在申請(qǐng)內(nèi)存后氓侧,無(wú)法釋放已申請(qǐng)的內(nèi)存空間脊另,稱之為內(nèi)存泄露。無(wú)法釋放的內(nèi)存會(huì)一直被無(wú)效占用约巷,且無(wú)法被再次使用偎痛,累計(jì)下來(lái)會(huì)導(dǎo)致進(jìn)程占用內(nèi)存越來(lái)越大,直至無(wú)內(nèi)存資源可用独郎,導(dǎo)致進(jìn)程崩潰踩麦。
在類(lèi)的構(gòu)造函數(shù)和析構(gòu)函數(shù)中沒(méi)有匹配的調(diào)用new和delete函數(shù)
沒(méi)有正確地清除嵌套的對(duì)象指針
在釋放對(duì)象數(shù)組時(shí)在delete中沒(méi)有使用方括號(hào)
指向?qū)ο蟮闹羔様?shù)組不等同于對(duì)象數(shù)組
缺少拷貝構(gòu)造函數(shù)
缺少重載賦值運(yùn)算符
沒(méi)有將基類(lèi)的析構(gòu)函數(shù)定義為虛函數(shù)
一個(gè)文件從源碼到可執(zhí)行文件所經(jīng)歷的過(guò)程
① 預(yù)處理,產(chǎn)生.ii文件
② 編譯氓癌,產(chǎn)生匯編文件 (.s文件)
③ 匯編谓谦,產(chǎn)生目標(biāo)文件 (.o或.obj文件)
④ 鏈接,產(chǎn)生可執(zhí)行文件C++構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用順序
構(gòu)造函數(shù)順序: 基類(lèi)構(gòu)造函數(shù)贪婉、對(duì)象成員構(gòu)造函數(shù)反粥、派生類(lèi)本身的構(gòu)造函數(shù)。
析構(gòu)函數(shù)順序: 派生類(lèi)本身的析構(gòu)函數(shù)、對(duì)象成員析構(gòu)函數(shù)才顿、基類(lèi)析構(gòu)函數(shù)(與構(gòu)造順序正好相反)莫湘。用 C++設(shè)計(jì)一個(gè)不能被繼承的類(lèi)
將自身構(gòu)造函數(shù)和析構(gòu)函數(shù)聲明為private。什么是純虛函數(shù)
基類(lèi)中聲明的虛函數(shù)郑气,僅有聲明無(wú)實(shí)現(xiàn)幅垮。要求派生的子類(lèi)必須定義自身的實(shí)現(xiàn)方法,達(dá)到多態(tài)效果尾组。構(gòu)造函數(shù)為什么一般不定義為虛函數(shù)忙芒?而析構(gòu)函數(shù)一般寫(xiě)成虛函數(shù)的原因
-
構(gòu)造函數(shù)不能聲明為虛函數(shù)
因?yàn)閯?chuàng)建一個(gè)對(duì)象時(shí)需要確定對(duì)象的類(lèi)型,而虛函數(shù)是在運(yùn)行時(shí)確定其類(lèi)型的讳侨。而在構(gòu)造一個(gè)對(duì)象時(shí)呵萨,由于對(duì)象還未創(chuàng)建成功,編譯器無(wú)法知道對(duì)象的實(shí)際類(lèi)型爷耀,是類(lèi)本身還是類(lèi)的派生類(lèi)等等虛函數(shù)的調(diào)用需要虛函數(shù)表指針甘桑,而該指針存放在對(duì)象的內(nèi)存空間中拍皮;若構(gòu)造函數(shù)聲明為虛函數(shù)歹叮,那么由于對(duì)象還未創(chuàng)建,還沒(méi)有內(nèi)存空間铆帽,更沒(méi)有虛函數(shù)表地址用來(lái)調(diào)用虛函數(shù)即構(gòu)造函數(shù)了
-
析構(gòu)函數(shù)最好聲明為虛函數(shù)
首先析構(gòu)函數(shù)可以為虛函數(shù)咆耿,當(dāng)析構(gòu)一個(gè)指向派生類(lèi)的基類(lèi)指針時(shí),最好將基類(lèi)的析構(gòu)函數(shù)聲明為虛函數(shù)爹橱,否則可以存在內(nèi)存泄露的問(wèn)題萨螺。
如果析構(gòu)函數(shù)不被聲明成虛函數(shù),則編譯器實(shí)施靜態(tài)綁定愧驱,在刪除指向派生類(lèi)的基類(lèi)指針時(shí)慰技,只會(huì)調(diào)用基類(lèi)的析構(gòu)函數(shù)而不調(diào)用派生類(lèi)析構(gòu)函數(shù),這樣就會(huì)造成派生類(lèi)對(duì)象析構(gòu)不完全组砚。
析構(gòu)函數(shù)的作用
對(duì)象消亡時(shí)吻商,自動(dòng)被調(diào)用,用來(lái)釋放對(duì)象占用的空間糟红。棧和堆的區(qū)別艾帐,什么時(shí)候必須使用堆
棧:為函數(shù)分配的一塊內(nèi)存,函數(shù)內(nèi)部聲明的所有局部變量都將占用棧內(nèi)存盆偿。函數(shù)執(zhí)行完畢后柒爸,占用的棧會(huì)被銷(xiāo)毀回收,內(nèi)部定義的變量均會(huì)銷(xiāo)毀事扭。效率很高捎稚,但是分配的內(nèi)存容量有限。
堆:程序中未使用的內(nèi)存,在程序運(yùn)行時(shí)可用于動(dòng)態(tài)分配內(nèi)存今野。由程序員自己維護(hù)申請(qǐng)和回收晰奖,若使用完畢未回收會(huì)導(dǎo)致內(nèi)存泄漏。
-
棧溢出原因
① 局部數(shù)組過(guò)大腥泥。當(dāng)函數(shù)內(nèi)部的數(shù)組過(guò)大時(shí)匾南,有可能導(dǎo)致堆棧溢出。② 遞歸調(diào)用層次太多蛔外。遞歸函數(shù)在運(yùn)行時(shí)會(huì)執(zhí)行壓棧操作蛆楞,當(dāng)壓棧次數(shù)太多時(shí),也會(huì)導(dǎo)致堆棧溢出夹厌。
③ 指針或數(shù)組越界豹爹。這種情況最常見(jiàn),例如進(jìn)行字符串拷貝矛纹,或處理用戶輸入等等臂聋。
解決方法
增大棧空間; 變量過(guò)大時(shí)或南,改用動(dòng)態(tài)分配孩等,使用堆(heap)而不是棧(stack)。
- 編碼實(shí)現(xiàn)某一變量某位清 0 或置 1
// 將第index為置1. index: 0~7
unsigned char set_bit(unsigned char value, int index)
{
return value | (1 << index);
}
//將第index位清0, index: 0~7
unsigned char clear_bit(unsigned char value, int index)
{
return value & (~(1 << index));
}
- 頭文件<>和""的區(qū)別
<>: 表示引用標(biāo)準(zhǔn)庫(kù)頭文件采够,編譯器會(huì)從系統(tǒng)默認(rèn)庫(kù)環(huán)境路徑查找肄方。
"": 一般表示用戶自己定義使用的頭文件,編譯器默認(rèn)會(huì)優(yōu)先從當(dāng)前路徑中尋找蹬癌;若未找到权她,再?gòu)南到y(tǒng)默認(rèn)庫(kù)環(huán)境路徑中去查找。
注:linux下C和C++默認(rèn)庫(kù)環(huán)境路徑:/usr/include
- 靜態(tài)綁定和動(dòng)態(tài)綁定的介紹
把一個(gè)方法與其所在的類(lèi)/對(duì)象關(guān)聯(lián)起來(lái)叫做方法的綁定逝薪。
靜態(tài)類(lèi)型:對(duì)象在聲明時(shí)采用的類(lèi)型隅要,在編譯期既已確定。
動(dòng)態(tài)類(lèi)型:通常是指一個(gè)指針或引用目前所指對(duì)象的類(lèi)型董济,是在運(yùn)行期決定的步清。
靜態(tài)綁定:綁定的是靜態(tài)類(lèi)型,所對(duì)應(yīng)的函數(shù)或?qū)傩砸蕾囉趯?duì)象的靜態(tài)類(lèi)型感局,發(fā)生在編譯期尼啡。
動(dòng)態(tài)綁定:綁定的是動(dòng)態(tài)類(lèi)型,所對(duì)應(yīng)的函數(shù)或?qū)傩砸蕾囉趯?duì)象的動(dòng)態(tài)類(lèi)型询微,發(fā)生在運(yùn)行期崖瞭。
非虛函數(shù)一般都是靜態(tài)綁定,而虛函數(shù)都是動(dòng)態(tài)綁定(如此才可實(shí)現(xiàn)多態(tài)性)
引用是否能實(shí)現(xiàn)動(dòng)態(tài)綁定撑毛,為什么引用可以實(shí)現(xiàn)
可以书聚。引用在創(chuàng)建的時(shí)候必須初始化唧领,在訪問(wèn)虛函數(shù)時(shí),編譯器會(huì)根據(jù)其所綁定的對(duì)象類(lèi)型決定要調(diào)用哪個(gè)函數(shù)雌续。注意只能調(diào)用虛函數(shù)斩个。什么情況下會(huì)調(diào)用拷貝構(gòu)造函數(shù)(三種情況)
拷貝構(gòu)造函數(shù)從來(lái)不顯示調(diào)用,而是由編譯器隱式地調(diào)用驯杜。
① 用類(lèi)的一個(gè)對(duì)象去初始化另一個(gè)對(duì)象時(shí)受啥;
② 當(dāng)函數(shù)的形參是類(lèi)的對(duì)象時(shí)(也就是值傳遞時(shí)),如果是引用傳遞則不會(huì)調(diào)用鸽心;
③ 當(dāng)函數(shù)的返回值是類(lèi)的對(duì)象或引用時(shí)滚局。extern "C"作用
extern "C"
的 主要 作用 就 是 為了能夠正確實(shí)現(xiàn)C++代碼調(diào)用其他C語(yǔ)言代碼。加上extern "C"
后顽频,編譯器會(huì)按照C語(yǔ)言語(yǔ)法進(jìn)行編譯藤肢。typedef和define的區(qū)別
typedef和define都是替一個(gè)對(duì)象取一個(gè)別名,以此增強(qiáng)程序的可讀性糯景。
①作用階段不同
typedef: 編譯階段有效, 有類(lèi)型檢查的功能嘁圈。
define: 預(yù)處理階段有效, 編譯前, 只進(jìn)行簡(jiǎn)單而機(jī)械的字符串替換, 不進(jìn)行任何檢查。
② 功能不同
typedef: 用來(lái)定義類(lèi)型(內(nèi)部或自定義類(lèi)型)的別名, 起到使類(lèi)型易于記憶的功能蟀淮。
define: 不止可以為類(lèi)型取別名, 還可以定義常量, 變量, 編譯開(kāi)關(guān)等最住。
③ 作用域不同
typedef: 與變量生命期類(lèi)似。放在函數(shù)外灭贷,作用域從定義開(kāi)始到文件尾温学;若放在函數(shù)內(nèi)略贮,定義域從定義處到該函數(shù)結(jié)尾甚疟。
define 沒(méi)有作用域的限制,從定義開(kāi)始到文件結(jié)尾逃延。
//源自https://www.cnblogs.com/retry/p/14045305.html
//a.c
typedef …//此處開(kāi)始到文件結(jié)尾
#define …//此處開(kāi)始到文件結(jié)尾
int negate(int num)
{
…
typedef …//此處開(kāi)始到該函數(shù)結(jié)束览妖。注意,該函數(shù)內(nèi)揽祥,此定義前讽膏,也不能用
#define …//此處開(kāi)始到文件結(jié)尾
…
}
typedef …//此處開(kāi)始到文件結(jié)尾
#define …//此處開(kāi)始到文件結(jié)尾
void show()
{
typedef …//此處開(kāi)始到該函數(shù)結(jié)束。
#define …//此處開(kāi)始到文件結(jié)尾
}
④ 對(duì)指針的操作:
二者修飾指針類(lèi)型時(shí), 作用不同拄丰。
Typedef int * pint府树;
#define PINT int *
const pint p;//p不可更改料按,p指向的內(nèi)容可以更改奄侠,相當(dāng)于 int * const p;
const PINT p;//p可以更改载矿,p指向的內(nèi)容不能更改垄潮,相當(dāng)于 const int *p;或 int const *p;
pint s1, s2; //s1和s2都是int型指針
PINT s3, s4; //相當(dāng)于int * s3弯洗,s4旅急;只有一個(gè)是指針。
友元函數(shù)
類(lèi)的友元函數(shù)是定義在類(lèi)外部牡整,但有權(quán)訪問(wèn)類(lèi)的所有私有(private)成員和保護(hù)(protected)成員藐吮。盡管友元函數(shù)的原型有在類(lèi)的定義中出現(xiàn)過(guò)逃贝,但是友元函數(shù)并不是成員函數(shù)。友元類(lèi)
在類(lèi)A中秋泳,用friend
修飾另一個(gè)已經(jīng)定義的類(lèi)B,類(lèi)B就屬于類(lèi)A的友元類(lèi)迫皱,類(lèi)B中的所有成員函數(shù)都是類(lèi)A的友元函數(shù)歉闰,類(lèi)B可以訪問(wèn)類(lèi)A的所有成員和敬,包括public
、protected
戏阅、private
屬性的昼弟。
- 空間足夠時(shí),可以將經(jīng)常需要讀取的資源芭逝,緩存在內(nèi)存中渊胸。
- 盡量減少大內(nèi)存對(duì)象的構(gòu)造與析構(gòu),考慮緩存暫時(shí)不用的對(duì)象胖翰,等待后續(xù)繼續(xù)使用切厘。
- 盡量使用C++11的右值語(yǔ)義,減少臨時(shí)對(duì)象的構(gòu)造某弦。
- 簡(jiǎn)單的功能函數(shù)可以使用內(nèi)聯(lián)。少用繼承靶壮,多用組合腾降,盡量減少繼承層級(jí)。
- 在循環(huán)遍歷時(shí)螃壤,優(yōu)化判斷條件奸晴,減少循環(huán)次數(shù)冤馏。
- 優(yōu)化線程或進(jìn)程的同步方式,能用原子操作的就不用鎖寄啼。能應(yīng)用層同步的就不用內(nèi)核對(duì)象同步。
- 優(yōu)化堆內(nèi)存的使用涕刚,如果有內(nèi)存頻繁的申請(qǐng)與釋放乙帮,可以考慮內(nèi)存池。
- 優(yōu)化線程的使用驾茴,節(jié)省系統(tǒng)資源與切換造成的性能損耗,線程使用頻繁的可以考慮線程池塞绿。
- 盡量使用事件通知沟涨,謹(jǐn)慎使用輪循或者sleep函數(shù)异吻。
- 界面開(kāi)發(fā)中诀浪,耗時(shí)的業(yè)務(wù)代碼不要放在UI線程中執(zhí)行延都,使用單獨(dú)的線程去異步處理耗時(shí)業(yè)務(wù)晰房,提高界面響應(yīng)速度射沟。
- 經(jīng)常重構(gòu)验夯、優(yōu)化代碼結(jié)構(gòu)摔刁。優(yōu)化算法或者架構(gòu)共屈,從設(shè)計(jì)層面進(jìn)行性能的優(yōu)化。
二借宵、計(jì)算機(jī)網(wǎng)絡(luò)編程
select、poll括改、epoll是多路復(fù)用主要用到的三種技術(shù)家坎,主要區(qū)別如下:
① 支持一個(gè)進(jìn)程所能打開(kāi)的最大連接數(shù)
select
? 單個(gè)進(jìn)程所能打開(kāi)的最大連接數(shù)有FD_SETSIZE宏定義虱疏,其大小是32個(gè)整數(shù)的大小(在32位的機(jī)器上对粪,大小就是3232著拭,同理64位機(jī)器上FD_SETSIZE為3264)牍帚,當(dāng)然我們可以對(duì)進(jìn)行修改暗赶,然后重新編譯內(nèi)核肃叶,但是性能可能會(huì)受到影響因惭,這需要進(jìn)一步的測(cè)試详幽。
poll
? poll本質(zhì)上和select沒(méi)有區(qū)別唇聘,但是它沒(méi)有最大連接數(shù)的限制,原因是它是基于鏈表來(lái)存儲(chǔ)的剥险。
epoll
? 雖然連接數(shù)有上限表制,但是很大控乾,1G內(nèi)存的機(jī)器上可以打開(kāi)10萬(wàn)左右的連接蜕衡,2G內(nèi)存的機(jī)器可以打開(kāi)20萬(wàn)左右的連接慨仿。
② FD劇增后帶來(lái)的IO效率問(wèn)題
select
? 因?yàn)槊看握{(diào)用時(shí)都會(huì)對(duì)連接進(jìn)行線性遍歷镰吆,所以隨著FD的增加會(huì)造成遍歷速度慢的“線性下降性能問(wèn)題”。
poll
? 同上摧找。
epoll
? 因?yàn)閑poll內(nèi)核中實(shí)現(xiàn)是根據(jù)每個(gè)fd上的callback函數(shù)來(lái)實(shí)現(xiàn)的慰于,只有活躍的socket才會(huì)主動(dòng)調(diào)用callback唤衫,所以在活躍socket較少的情況下佳励,使用epoll沒(méi)有前面兩者的線性下降的性能問(wèn)題,但是所有socket都很活躍的情況下妙黍,可能會(huì)有性能問(wèn)題拭嫁。
③ 消息傳遞方式
select
? 內(nèi)核需要將消息傳遞到用戶空間抓于,都需要內(nèi)核拷貝動(dòng)作捉撮。
poll
? 同上。
epoll
? epoll通過(guò)內(nèi)核和用戶空間共享一塊內(nèi)存來(lái)實(shí)現(xiàn)的肉康。
- TCP是面向連接的吼和,UDP是無(wú)連接的
- TCP是可靠的骑素,UDP是不可靠的
- TCP是面向字節(jié)流的砂豌,UDP是面向數(shù)據(jù)報(bào)文的
- TCP只支持點(diǎn)對(duì)點(diǎn)通信,UDP支持一對(duì)一塔粒,一對(duì)多卒茬,多對(duì)多
- TCP報(bào)文首部20個(gè)字節(jié)咖熟,UDP首部8個(gè)字節(jié)
- TCP有擁塞控制機(jī)制馍管,UDP沒(méi)有
- TCP協(xié)議下雙方發(fā)送接受緩沖區(qū)都有,UDP并無(wú)實(shí)際意義上的發(fā)送緩沖區(qū)捌锭,但是存在接受緩沖區(qū)
① 第一次握手
客戶端給服務(wù)器發(fā)送一個(gè)SYN段(在 TCP 標(biāo)頭中 SYN 位字段為 1 的 TCP/IP 數(shù)據(jù)包), 該段中也包含客戶端的初始序列號(hào)(Sequence number = J)观谦。
② 第二次握手
服務(wù)器返回客戶端 SYN +ACK 段(在 TCP 標(biāo)頭中SYN和ACK位字段都為 1 的 TCP/IP 數(shù)據(jù)包)豁状, 該段中包含服務(wù)器的初始序列號(hào)(Sequence number = K);同時(shí)使 Acknowledgment number = J + 1來(lái)表示確認(rèn)已收到客戶端的 SYN段(Sequence number = J)夭禽。
③ 第三次握手
客戶端給服務(wù)器響應(yīng)一個(gè)ACK段(在 TCP 標(biāo)頭中 ACK 位字段為 1 的 TCP/IP 數(shù)據(jù)包), 該段中使 Acknowledgment number = K + 1來(lái)表示確認(rèn)已收到服務(wù)器的 SYN段(Sequence number = K)驻粟。
? 為了實(shí)現(xiàn)可靠數(shù)據(jù)傳輸凶异,TCP 協(xié)議的通信雙方剩彬,都必須維護(hù)一個(gè)序列號(hào),以標(biāo)識(shí)發(fā)送出去的數(shù)據(jù)包中沃饶,哪些是已經(jīng)被對(duì)方收到的糊肤。三次握手的過(guò)程即是通信雙方相互告知序列號(hào)起始值氓鄙,并確認(rèn)對(duì)方已經(jīng)收到了序列號(hào)起始值的必經(jīng)步驟抖拦。
① 第一次揮手: Client端發(fā)起揮手請(qǐng)求态罪,向Server端發(fā)送標(biāo)志位是FIN報(bào)文段,設(shè)置序列號(hào)seq绩聘,此時(shí)君纫,Client端進(jìn)入FIN_WAIT_1狀態(tài)芹彬,這表示Client端沒(méi)有數(shù)據(jù)要發(fā)送給Server端了舒帮。
② 第二次揮手:Server端收到了Client端發(fā)送的FIN報(bào)文段,向Client端返回一個(gè)標(biāo)志位是ACK的報(bào)文段肢执,ack設(shè)為seq加1预茄,Client端進(jìn)入FIN_WAIT_2狀態(tài)侦厚,Server端告訴Client端刨沦,我確認(rèn)并同意你的關(guān)閉請(qǐng)求想诅。
③ 第三次揮手: Server端向Client端發(fā)送標(biāo)志位是FIN的報(bào)文段,請(qǐng)求關(guān)閉連接篮灼,同時(shí)Client端進(jìn)入LAST_ACK狀態(tài)诅诱。
④ 第四次揮手 : Client端收到Server端發(fā)送的FIN報(bào)文段晌坤,向Server端發(fā)送標(biāo)志位是ACK的報(bào)文段骤菠,然后Client端進(jìn)入TIME_WAIT狀態(tài)商乎。Server端收到Client端的ACK報(bào)文段后,關(guān)閉連接鲜戒。此時(shí)翔烁,Client端等待2MSL的時(shí)間后依然沒(méi)有收到回復(fù)疼鸟,則證明Server端已正常關(guān)閉,Client端也關(guān)閉連接粹庞。
其實(shí)是客戶端和服務(wù)端的兩次揮手庞溜,也就是客戶端和服務(wù)端分別釋放連接的過(guò)程流码。客戶端在發(fā)送完最后一次確認(rèn)之后赏胚,還要等待2MSL的時(shí)間觉阅。有兩個(gè)原因: 一是為了讓B能夠按照正常步驟進(jìn)入CLOSED狀態(tài)典勇,二是為了防止已經(jīng)失效的請(qǐng)求連接報(bào)文出現(xiàn)在下次連接中叮趴。
① 由于客戶端最后一個(gè)ACK可能會(huì)丟失眯亦,這樣B就無(wú)法正常進(jìn)入CLOSED狀態(tài)妻率。于是B會(huì)重傳請(qǐng)求釋放的報(bào)文,而此時(shí)A如果已經(jīng)關(guān)閉了走净,那就收不到B的重傳請(qǐng)求伏伯,就會(huì)導(dǎo)致B不能正常釋放。而如果A還在等待時(shí)間內(nèi)炸枣,就會(huì)收到B的重傳抛虏,然后進(jìn)行應(yīng)答,這樣B就可以進(jìn)入CLOSED狀態(tài)了背伴。
② 在這2MSL等待時(shí)間里面峰髓,本次連接的所有的報(bào)文都已經(jīng)從網(wǎng)絡(luò)中消失携兵,從而不會(huì)出現(xiàn)在下次連接中。
- 編寫(xiě)socket套接字的步驟
服務(wù)器端程序的編寫(xiě)步驟
① 調(diào)用socket()函數(shù)創(chuàng)建一個(gè)用于通信的套接字静檬。
② 第二步:給已經(jīng)創(chuàng)建的套接字綁定一個(gè)端口號(hào)拂檩,這一般通過(guò)設(shè)置網(wǎng)絡(luò)套接口地址和調(diào)用bind()函數(shù)來(lái)實(shí)現(xiàn)稻励。
③ 調(diào)用listen()函數(shù)使套接字成為一個(gè)監(jiān)聽(tīng)套接字愈涩。
④ 調(diào)用accept()函數(shù)來(lái)接受客戶端的連接履婉,這是就可以和客戶端通信了谐鼎。
⑤ 處理客戶端的連接請(qǐng)求。
⑥ 終止連接身害。客戶端程序編寫(xiě)步驟
① 調(diào)用socket()函數(shù)創(chuàng)建一個(gè)用于通信的套接字塌鸯。
② 通過(guò)設(shè)置套接字地址結(jié)構(gòu)丙猬,說(shuō)明客戶端與之通信的服務(wù)器的IP地址和端口號(hào)茧球。
③ 調(diào)用connect()函數(shù)來(lái)建立與服務(wù)器的連接。
④ 調(diào)用讀寫(xiě)函數(shù)發(fā)送或者接收數(shù)據(jù)弹灭。
⑤ 終止連接穷吮。
三捡鱼、操作系統(tǒng)
如何不用
sizeof()
判斷系統(tǒng)是16位還是32位?
可通過(guò)內(nèi)存地址地址長(zhǎng)度判斷驾诈,定義一個(gè)指針變量伟墙,通過(guò)打印其地址即可判斷戳葵。進(jìn)程和線程間的通信方式
匿名管道(pipe)拱烁、高級(jí)管道(popen)、有名管道(fifo)邦投、消息隊(duì)列志衣、信號(hào)量念脯、信號(hào)(sinal)、共享內(nèi)存吉懊、套接字(socket)借嗽。線程安全和線程不安全
線程安全指支持多線程訪問(wèn)恶导,多線程訪問(wèn)時(shí)不會(huì)導(dǎo)致共享數(shù)據(jù)污染甲锡。反之羽戒,為線程不安全易稠。
死鎖的定義
? 兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中驶社,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象亡电,若無(wú)外力作用份乒,它們都將無(wú)法推進(jìn)下去或辖。死鎖的產(chǎn)生原因
通常是源于多個(gè)進(jìn)程對(duì)資源的爭(zhēng)奪枣接,不僅對(duì)不可搶占資源進(jìn)行爭(zhēng)奪或引起死鎖但惶,而且對(duì)可消耗資源進(jìn)行爭(zhēng)奪也會(huì)引起死鎖⊙羯叮總結(jié)如下:
① 系統(tǒng)資源不足捌省;
② 進(jìn)程運(yùn)行推進(jìn)的順序不當(dāng)纲缓;
③ 資源分配不當(dāng)祝高;死鎖產(chǎn)生的必要條件
① 互斥條件:
進(jìn)程在運(yùn)行中對(duì)資源進(jìn)行排他性使用工闺,即一個(gè)資源僅能被一個(gè)進(jìn)程使用陆蟆,此時(shí)其他進(jìn)程請(qǐng)求資源時(shí)雷厂,只能等待其釋放。
② 請(qǐng)求與保持條件:
某進(jìn)程已經(jīng)保持了一個(gè)資源叠殷,但又請(qǐng)求另一個(gè)資源改鲫,若該資源被其他進(jìn)程占有,此時(shí)請(qǐng)求阻塞林束,且對(duì)已經(jīng)占有的資源不釋放像棘;
③ 不可搶占條件:
進(jìn)程獲得的資源在未使用完時(shí)不可被搶占壶冒,只能在進(jìn)程使用完時(shí)自己釋放缕题;
④ 循環(huán)等待條件
發(fā)生死鎖時(shí),必然存在這樣一個(gè)循環(huán)胖腾,一個(gè)進(jìn)程p1等待p2占有的資源進(jìn)程p2等待p3占有的資源...進(jìn)程pn等待p1占有的資源烟零。死鎖的處理方法
① 預(yù)防死鎖:事先預(yù)防策略,容易實(shí)現(xiàn)胸嘁,通過(guò)實(shí)現(xiàn)設(shè)置限制瓶摆,破壞產(chǎn)生死鎖的四個(gè)條件之一。(如對(duì)資源采用按序分配策略)
② 避免死鎖:事先預(yù)防策略性宏,在資源的動(dòng)態(tài)分配過(guò)程中群井,用某些方法防止系統(tǒng)禁圖不安全狀態(tài)。常見(jiàn)的方法有銀行家算法毫胜。
③ 檢測(cè)死鎖:通過(guò)檢測(cè)機(jī)構(gòu)等及時(shí)檢測(cè)出死鎖书斜,采取適當(dāng)措施诬辈,把進(jìn)程從死鎖中解脫。
④ 解除死鎖:檢測(cè)出死鎖后荐吉,采取措施解決焙糟。比如剝奪資源,撤銷(xiāo)進(jìn)程样屠。
這四種方法對(duì)死鎖的防范逐漸減弱穿撮,但對(duì)應(yīng)的是資源利用率的提高。
如何采用單線程處理高并發(fā)
采用非阻塞,異步編程的思想痪欲。
① IO多路復(fù)用技術(shù)
② 采用事件驅(qū)動(dòng)模型悦穿,基于異步回調(diào)來(lái)處理事件線程的狀態(tài)
運(yùn)行期、掛起业踢、死亡栗柒、正常退出、和線程阻塞知举。進(jìn)程的狀態(tài)
① 運(yùn)行(running)態(tài):進(jìn)程占有處理器正在運(yùn)行瞬沦。
② 就緒(ready)態(tài):進(jìn)程具備運(yùn)行條件,等待系統(tǒng)分配處理器以便運(yùn)行雇锡。
③ 等待(wait)態(tài):又稱為阻塞(blocked)態(tài)或睡眠(sleep)態(tài)逛钻,指進(jìn)程不具備運(yùn)行條件,正在等待某個(gè)事件的完成锰提。
從操作系統(tǒng)角度來(lái)看绣的,進(jìn)程分配內(nèi)存有兩種方式,分別由兩個(gè)系統(tǒng)調(diào)用完成:brk和mmap(不考慮共享內(nèi)存)。
- brk是將數(shù)據(jù)段(.data)的最高地址指針_edata往高地址推芭概;
- mmap是在進(jìn)程的虛擬地址空間中(堆和棧中間,稱為文件映射區(qū)域的地方)找一塊空閑的虛擬內(nèi)存踢故。
這兩種方式分配的都是虛擬內(nèi)存惹苗,沒(méi)有分配物理內(nèi)存。在第一次訪問(wèn)已分配的虛擬地址空間的時(shí)候淋纲,發(fā)生缺頁(yè)中斷院究,操作系統(tǒng)負(fù)責(zé)分配物理內(nèi)存本涕,然后建立虛擬內(nèi)存和物理內(nèi)存之間的映射關(guān)系伙窃。
進(jìn)程和線程的區(qū)別
① 地址空間
線程共享本進(jìn)程的地址空間菩颖,而進(jìn)程之間是獨(dú)立的地址空間。
② 資源
線程共享本進(jìn)程的資源如內(nèi)存为障、I/O晦闰、cpu等,不利于資源的管理和保護(hù)鳍怨,而進(jìn)程之間的資源是獨(dú)立的呻右,能很好的進(jìn)行資源管理和保護(hù)。
③ 健壯性
多進(jìn)程要比多線程健壯京景,一個(gè)進(jìn)程崩潰后窿冯,在保護(hù)模式下不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響,但是一個(gè)線程崩潰整個(gè)進(jìn)程都死掉确徙。
④ 執(zhí)行過(guò)程
每個(gè)獨(dú)立的進(jìn)程有一個(gè)程序運(yùn)行的入口醒串、順序執(zhí)行序列和程序入口,執(zhí)行開(kāi)銷(xiāo)大鄙皇。
但是線程不能獨(dú)立執(zhí)行芜赌,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制伴逸,執(zhí)行開(kāi)銷(xiāo)小缠沈。
⑤ 可并發(fā)性
兩者均可并發(fā)執(zhí)行。
⑥ 切換時(shí)
進(jìn)程切換時(shí)错蝴,消耗的資源大洲愤,效率高。所以涉及到頻繁的切換時(shí)顷锰,使用線程要好于進(jìn)程柬赐。同樣如果要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作肛宋,只能用線程不能用進(jìn)程。
⑦ 其他
線程是處理器調(diào)度的基本單位沉帮,但是進(jìn)程不是馅精。工作常用到的Linux命令
find、grep压彭、ps、top询一、ls(比較簡(jiǎn)單健蕊,不展開(kāi))gdb
參考網(wǎng)上gdb常用的調(diào)試手法。gcc/g++
C和C++的編譯工具嫡锌。什么是虛擬內(nèi)存
《操作系統(tǒng)》:虛擬存儲(chǔ)技術(shù)的基本思想時(shí)利用大容量外存來(lái)擴(kuò)充內(nèi)存,產(chǎn)生一個(gè)比有限的實(shí)際內(nèi)存空間大得多的歌懒、邏輯的虛擬空間,簡(jiǎn)稱虛存躲庄,以便能夠有效地支持多道程序系統(tǒng)的實(shí)現(xiàn)和大型程序運(yùn)行的需要,從而增強(qiáng)系統(tǒng)的處理能力倔监。
簡(jiǎn)單的分為連續(xù)分配管理方式和非連續(xù)分配管理方式這兩種浩习。連續(xù)分配管理方式是指為一個(gè)用戶程序分配一個(gè)連續(xù)的內(nèi)存空間洽蛀,比如塊式管理郊供。非連續(xù)分配管理方式允許一個(gè)程序內(nèi)存分散,比如頁(yè)式管理疯淫、段式管理和段頁(yè)式管理峡竣。
塊式管理
遠(yuǎn)古時(shí)代的計(jì)算機(jī)操作系統(tǒng)的內(nèi)存管理方式,將內(nèi)存分為幾個(gè)固定大小的塊类浪,每個(gè)塊只包含一個(gè)進(jìn)程,如果程序運(yùn)行需要內(nèi)存力细,操作系統(tǒng)就給它分配一塊眠蚂,如果程序運(yùn)行只需要很小的空間,則分配的這塊內(nèi)存很大一部分就浪費(fèi)了云稚,這些在每個(gè)塊中未被利用的空間静陈,我們稱為碎片。頁(yè)式管理
把主存分為大小相等且固定的一頁(yè)一頁(yè)的形式崩泡,頁(yè)比較小,相對(duì)于塊式管理的劃分力度更大谒所,提高了內(nèi)存利用率劣领,減少了碎片尖淘。頁(yè)式管理通過(guò)頁(yè)表對(duì)應(yīng)邏輯地址和物理地址。段式管理
頁(yè)式管理雖然提高了內(nèi)存利用率,但是其中的頁(yè)沒(méi)有任何實(shí)際意義肄鸽,段式管理把主存分為一段一段 ,每一段的空間又比一頁(yè)的空間小很多。但是段有實(shí)際意義汛骂,段式管理通過(guò)段表對(duì)應(yīng)邏輯地址和物理地址淑掌。段頁(yè)式管理
段頁(yè)式管理機(jī)制結(jié)合了段式管理和頁(yè)式管理的優(yōu)點(diǎn),就是把主存分為若干段担敌,每個(gè)段又分為若干頁(yè)桃犬,也就是說(shuō)段頁(yè)式管理機(jī)制中段和段之間以及段的內(nèi)部都是離散的土匀。
- 大端和小端就轧,用C++代碼怎么確定
- 指針?lè)?/li>
int JudgeSystem(void) {
int a = 1;
char *p = (char *)&a;
// 如果是小端則返回 1,如果是大端則返回 0
return *p;
}
- 聯(lián)合體法
int JudgeSystem(void) {
union {
char c;
int i;
} un; // 匿名聯(lián)合體 un
un.i = 1;
// 如果是小端則返回 1携丁,如果是大端則返回 0
return un.c;
}
四、數(shù)據(jù)結(jié)構(gòu)及算法
幾種常見(jiàn)的排序算法
① 冒泡排序
② 選擇排序
③ 插入排序
④ 希爾排序
⑤ 快速排序
⑥ 歸并排序
⑦ 堆排序鏈表的特點(diǎn)和操作
- 特點(diǎn)
① 采用動(dòng)態(tài)存儲(chǔ)分配,不會(huì)造成內(nèi)存浪費(fèi)和溢出宠互。
② 鏈表執(zhí)行插入和刪除操作十分方便椭坚,修改指針即可予跌,不需要移動(dòng)大量元素。 - 常見(jiàn)操作
① 創(chuàng)建
② 插入
③ 修改
④ 查找
⑤ 刪除
常見(jiàn)的查找算法
① 順序查找
② 二分查找
③ 插值查找
④ 斐波那契查找
⑤ 樹(shù)表查找
⑥ 分塊查找
⑦ 哈希查找
通過(guò)快慢指針善茎。慢指針每次走1步券册,快指針每次走2步。當(dāng)快慢指針相遇垂涯,說(shuō)明鏈表為循環(huán)鏈表烁焙。
bool IsRingList(SNode* pHead)
{
bool ret = false;
SNode *pSlow = pHead, *pFast = pHead;
while(pFast && pFast->next)
{
pSlow = pSlow->next;
pFast = pFast->next->next;
if (pSlow == pFast) {
return true;
}
}
return ret;
}
- 計(jì)算環(huán)形鏈表的長(zhǎng)度
通過(guò)快慢指針鞠苟。慢指針每次走1步鹦倚,快指針每次走2步,兩者速度差為1步夺颤。 當(dāng)兩指針相遇時(shí)嵌洼,快指針比慢指針多走1圈。
int GetRingListLength(SNode* pHead)
{
int length = 0;
SNode *pSlow = pHead, *pFast = pHead;
while(pFast && pFast->next)
{
pSlow = pSlow->next;
pFast = pFast->next->next;
length++;
if (pSlow == pFast) {
break;
}
}
if (pSlow != pFast)
{
length = 0;
printf("It is not ring list.\n");
}
return length;
}
- 查找單鏈表倒數(shù)第n個(gè)節(jié)點(diǎn)
通過(guò)快慢指針崭倘,快指針先走n步坞淮,隨后慢指針與快指針同步走,當(dāng)快指針到達(dá)鏈表尾部時(shí)阐滩,慢指針即為倒數(shù)第n個(gè)節(jié)點(diǎn)凡简。