### 一個由C/C++編譯的程序占用的內(nèi)存分為以下幾個部分1. 棧區(qū)(stack):由編譯器自動分配釋放,,存放函數(shù)的參數(shù)值,局部變量的值等,。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧,。2. 堆區(qū)(heap):一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時可能由OS回收,。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,,鏈表的數(shù)據(jù)空間必須采用堆存儲分配策。3. 全局區(qū)(靜態(tài)區(qū))(static):全局變量和靜態(tài)變量的存儲是放在這一塊的,。初始化的全局變量和靜態(tài)變量在一塊區(qū)域,,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域,程序結(jié)束后由系統(tǒng)釋放,。4. 文字常量區(qū):常量字符串就是放在這里的,,程序結(jié)束后由系統(tǒng)釋放。5. 程序代碼區(qū):存放函數(shù)體的二進(jìn)制代碼1. 選擇合適的數(shù)據(jù)結(jié)構(gòu)與算法,;5. 求余運算用&(如a=a%8改為a=a&7);6. 平方運算用*(如a=pow(a,2.0)改為a=a*a),;8. switch語句中根據(jù)發(fā)生頻率來進(jìn)行case排序;### `#include <>` 和 `#include ' '`的區(qū)別1. `#include <>` :到保存系統(tǒng)標(biāo)準(zhǔn)頭文件的位置查找頭文件,。2. `#include' '`:查找當(dāng)前目錄是否有指定名稱的頭文件,然后再從標(biāo)準(zhǔn)頭文件目錄中查找,。1. 數(shù)據(jù)類型(常用char, short, int, long, unsigned, float, double)2. 運算和表達(dá)式(=, +, -, *, while, do-while, if, goto, switch-case)3. 數(shù)據(jù)存儲(auto,,static ,extern,,const,,register,volatile,,restricted)4. 結(jié)構(gòu)(struct, enum, union,typedef),5. 位操作和邏輯運算(<<, >>, &, |, ~,,^, &&),6. 預(yù)處理(#define, #include, #error,,#if…#elif…#else…#endif等),,7. 平臺擴展關(guān)鍵字(__asm, __inline,__syscall)1. static修飾局部變量(靜態(tài)局部變量)與普通局部變量相比:- 靜態(tài)局部變量作用域與連接屬性,,和普通局部變量一樣- 存儲類:靜態(tài)局部變量分配在data/bss段,,普通局部變量在棧上- 生命周期:因為存儲類的不同,靜態(tài)局部變量生命周期變長了,,直到程序結(jié)束所以當(dāng)靜態(tài)局部變量離開作用域后,,并沒有銷毀,,而是仍然駐留在內(nèi)存當(dāng)中,只不過我們不能夠再對它進(jìn)行訪問,,直到該函數(shù)被再次調(diào)用,,并且值不變。2. static修飾的全局變量(函數(shù))與普通的相比:static修飾的全局變量的連接屬性是內(nèi)連接,普通的是外連接即:static修飾的全局變量不能給文件調(diào)用——這也是靜態(tài)變量和全局變量的區(qū)別,。內(nèi)部函數(shù):只能被本文件中的其他函數(shù)調(diào)用,。定義內(nèi)部函數(shù)時,在函數(shù)名,、函數(shù)類型前加static,。外部函數(shù):可供其他文件調(diào)用。定義外部函數(shù)時,,在函數(shù)首部左端加上extern,。若定義函數(shù)時省略extern,則默認(rèn)為外部函數(shù),。const 是定義只讀變量的關(guān)鍵字,,或者說 const 是定義常變量的關(guān)鍵字。說 const 定義的是變量,,但又相當(dāng)于常量,;說它定義的是常量,但又有變量的屬性,,所以叫常變量,。用 const 定義常變量的方法很簡單,就在通常定義變量時前面加 const 即可,,如:const 和變量類型 int 可以互換位置,,二者是等價的,即上條語句等價于:那么用 const 修飾后和未修飾前有什么區(qū)別呢,?它們不都等于 10 嗎,?、用 const 定義的變量的值是不允許改變的,,即不允許給它重新賦值,即使是賦相同的值也不可以,。所以說它定義的是只讀變量,。這也就意味著必須在定義的時候就給它賦出值。如果定義的時候未初始化,,我們知道,,對于未初始化的局部變量,,程序在執(zhí)行的時候會自動把一個很小的負(fù)數(shù)存放進(jìn)去。這樣后面再給它賦出值的話就是“改變它的值”了,,即發(fā)生語法錯誤,。(1)可以定義 const 常量,具有不可變性,。(2)便于進(jìn)行類型檢查,,使編譯器對處理內(nèi)容有更多了解,消除一些隱患,。(3)可以避免意義模糊的數(shù)字出現(xiàn),,同樣可以很方便進(jìn)行參數(shù)的調(diào)整和修改。同宏定義一樣,,可以做到不變則已,,一變都變。(4)可以保護被修改的東西,,防止意外的修改,,增強程序的健壯性。(5)可以節(jié)省空間,,避免不必要的內(nèi)存分配,。1. 數(shù)據(jù)類型:const修飾的變量有明確的類型,而宏沒有明確的數(shù)據(jù)類型2. 安全方面:const修飾的變量會被編譯器檢查,,而宏沒有安全檢查3. 內(nèi)存分配:const修飾的變量只會在第一次賦值時分配內(nèi)存,,而宏是直接替換,每次替換后的變量都會分配內(nèi)存4. 作用場所:const修飾的變量作用在編譯,、運行的過程中,,而宏作用在預(yù)編譯中5. 代碼調(diào)試:const方便調(diào)試,而宏在預(yù)編譯中進(jìn)行所以沒有辦法進(jìn)行調(diào)試,。嵌入式開發(fā)中,,常用到volatile關(guān)鍵字,它是一個類型修飾符,,含義為“易變的”,。使用方式如下:這里使用volatile關(guān)鍵字定義了一個字符型的變量i,指出i是隨時可能發(fā)生變化的,每次使用該變量時都必須從i的地址中讀取,。由于內(nèi)存的讀/寫速度遠(yuǎn)不及CPU中寄存器的讀/寫速度,為了提高數(shù)據(jù)信息的存取速度,。另一方面在軟件上使用編譯器對程序進(jìn)行優(yōu)化,將變量的值提前從內(nèi)存讀取到CPU的寄存器中,,以后用到該變量時,直接從速度較快的寄存器中讀取,,這樣有利于提高運算速度。但同時也可能存在風(fēng)險,如該變量在內(nèi)存中的值有可能被程序的其他部分(如其他線程)修改或覆蓋,,而寄存器中存放的仍是之前的值,,這就導(dǎo)致應(yīng)用程序讀取的值和實際變量值不一致;也有可能是寄存器中的值發(fā)生了改變,,而內(nèi)存中該變量的值沒有被修改,同樣也會導(dǎo)致不一致的情況發(fā)生,。因此,,為防止由于編譯器對程序進(jìn)行優(yōu)化導(dǎo)致讀取錯誤數(shù)據(jù),使用 volatile關(guān)鍵詞進(jìn)行定義,。簡單地說,,使用volatile關(guān)鍵字就是不讓編譯器進(jìn)行優(yōu)化,即每次讀取或者修改值時,都必須重新從內(nèi)存中讀取或者修改,,而不是使用保存在寄存器的備份,。舉個簡單的例子:大學(xué)里的獎/助學(xué)金的發(fā)放一般都是直接轉(zhuǎn)給學(xué)校,學(xué)校再發(fā)給每名學(xué)生,學(xué)校財務(wù)處都登記了每名學(xué)生的銀行卡號,,但不可避免地會有一些學(xué)生因各種原因丟失銀行卡或不再使用這張銀行卡,,而沒來得及去財務(wù)處重新登記,從而影響?yīng)?助學(xué)金的發(fā)放,這里,,學(xué)生就是變量的原始地址,,而財務(wù)處的銀行卡號就是變量在寄存器中的備份,使用 volatile關(guān)鍵字來定義學(xué)生這個變量,這樣每次發(fā)放獎/助學(xué)金時都去找學(xué)生這個變量的原始地址,,而不是直接轉(zhuǎn)到財務(wù)處保存的銀行卡上,,進(jìn)而避免錯誤的發(fā)生。const關(guān)鍵字的含義為“只讀”,volatile關(guān)鍵字的含義為“易變的”,,但volatile關(guān)鍵字解釋為“直接存取原始內(nèi)存地址”更為合適,,使用 volatile關(guān)鍵字定義變量后,該變量就不會因外因而發(fā)生變化了。一般來說,,volatile 關(guān)鍵字常用在以下場合,。- 中斷服務(wù)程序中修改的、供其他程序檢測的變量需要使用volatile關(guān)鍵字,。- 多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)添加 volatile關(guān)鍵字,。- 外設(shè)寄存器地址映射的硬件寄存器通常要用volatile關(guān)鍵字進(jìn)行聲明。### 談?wù)刢語?中有符號和?符號的區(qū)別,?有符號:數(shù)據(jù)的最?位為符號位,,0表示正數(shù),1表示負(fù)數(shù)?符號:數(shù)據(jù)的最?位不是符號位,,?是數(shù)據(jù)的?部分### 數(shù)據(jù)的類型轉(zhuǎn)換:數(shù)據(jù)類型自動轉(zhuǎn)換規(guī)則:char→int→long→float→double### 整型常量的存儲-8在內(nèi)存中的存儲形式是(A)整型數(shù)據(jù)在內(nèi)存中是以二進(jìn)制的形式存放的,數(shù)值是以補碼表示的,。一個正數(shù)的補碼和其原碼的形式相同,,一個負(fù)數(shù)的補碼是將該數(shù)絕對值的二進(jìn)制形式按位取反再加1。這里-8絕對值在內(nèi)存中的存儲形式為00000000 00000000 00000000 00001000,。將其取反操作得11111111 11111111 11111111 11110111,。取反后加1得:11111111 11111111 11111111 11111000聲明變量**不需要**建?存儲空間,, 變量的定義**需要**建?存儲空間`[存儲類型] [特征修飾] 數(shù)據(jù)類型 變量名`數(shù)據(jù)類型: 決定變量的存儲空間及數(shù)據(jù)范圍auto 只能修飾局部變量,存在棧(使用時臨時申請空間,,不用時,,會釋放空間,隨著函數(shù)結(jié)束而釋放)register 存在寄存器(cpu里,,不在內(nèi)存 )只能修飾整型的局部變量,,不能是浮點型,也不能進(jìn)行取地址操作(寄存器沒有地址)extern 告訴編譯器 ,,不用給這個變量申請空間,,因為它在其它.c文件申請過了(定義過了)(extern引用不了static變量,只能引用全局變量,,static變量只在本文件內(nèi)有效,,加了static就用不了extern了)static 既可以修飾全局變量,也可以修飾局部變量,,存在靜態(tài)區(qū)(data段),,這個變量本文件用全局變量:定義在函數(shù)外部的變量,作用范圍是整個程序,。局部變量:定義在函數(shù)內(nèi)部的變量,,作用范圍僅限于定義它的函數(shù)內(nèi)部靜態(tài)變量:static,static int a;定義一次就不再消失,,會把上一次的值保存起來,,下一次直接拿來用。靜態(tài)局部變量:在函數(shù)內(nèi)定義的靜態(tài)變量,,不可以被外部函數(shù)調(diào)用### 描述?下普通局部變量,、普通全局變量、靜態(tài)局部變量,、靜態(tài)全局變量的區(qū)別普通局部變量: 存在棧區(qū),、不初始化內(nèi)容隨機、只在定義所在的復(fù)合語句中有效,、符合語句結(jié)束變量空間釋放普通全局變量 :存在全局區(qū),、不初始化內(nèi)容為0、進(jìn)程結(jié)束空間才被釋放,,能被當(dāng)前源?件或其他源?件使?,,只是其他源?件使?的時候,記得使?extern修飾靜態(tài)局部變量: 存在全局區(qū),、不初始化內(nèi)容為0,、整個進(jìn)程結(jié)束空間才被釋放,,只能在定義所在的復(fù)合語句中有效靜態(tài)全局變量 :存在全局區(qū)、不初始化內(nèi)容為0,、整個進(jìn)程結(jié)束空間才被釋放,,只能被當(dāng)前源?件使?編譯時分配,包括:全局,、靜態(tài)全局,、靜態(tài)局部包括:棧(局部變量),堆,動態(tài)存儲區(qū),,需要程序員去申請釋放(C語言常用到的變量被動態(tài)地分配到內(nèi)存當(dāng)中:malloc,,calloc,realloc,,free函數(shù))const修飾的全局變量也儲存在常量區(qū),;const修飾的局部變量依然在棧上。int main(int argc, char **argv) //棧 char *p3 = '123456'; //123456\0在常量區(qū),,p3在棧上,。 static int c =0; //全局(靜態(tài))初始化區(qū) p2 = (char *)malloc(20); //分配得來得10和20字節(jié)的區(qū)域就在堆區(qū),。 strcpy(p1, '123456'); //123456\0放在常量區(qū),,編譯器可能會將它與p3所指向的'123456'優(yōu)化成一個地方。同?個數(shù)組所有的成員都是相同的數(shù)據(jù)類型,,同時所有的成員在內(nèi)存中的地址是連續(xù)的數(shù)組的分類主要是:靜態(tài)數(shù)組,、動態(tài)數(shù)組兩類。靜態(tài)數(shù)組:類似int arr[5];在程序運?就確定了數(shù)組的??,,運?過程不能更改數(shù)組的??,。動態(tài)數(shù)組:主要是在堆區(qū)申請的空間,數(shù)組的??是在程序運?過程中確定,,可以更改數(shù)組的??,。### 描述?下?維數(shù)組的不初始化、部分初始化,、完全初 始化的不同點不初始化:如果是局部數(shù)組 數(shù)組元素的內(nèi)容隨機 如果是全局?jǐn)?shù)組,,數(shù)組的元素內(nèi)容為0完全初始化:如果?個數(shù)組全部初始化 可以省略元素的個數(shù) 數(shù)組的??由初始化的個數(shù)確定### 談?wù)勀銓?維數(shù)組在物理上以及邏輯上的數(shù)組維度理解?維數(shù)組在邏輯上是?維的,在物理上是?維的### 談?wù)剶?shù)組名作為類型,、作為地址,、對數(shù)組名取地址的 區(qū)別?數(shù)組名作為類型:代表的是整個數(shù)組的??數(shù)組名作為地址:代表的是數(shù)組?元素的地址對數(shù)組名取地址:代表的是數(shù)組的?地址### 如何理解結(jié)構(gòu)體的淺拷?與深拷?當(dāng)結(jié)構(gòu)體中有指針成員的時候容易出現(xiàn)淺拷?與深拷?的問題,。淺拷?就是,,兩個結(jié)構(gòu)體變量的指針成員指向同?塊堆區(qū)空間,在各個結(jié)構(gòu)體變量釋放的時候會出現(xiàn)多次釋放同?段堆區(qū)空間深拷?就是,讓兩個結(jié)構(gòu)體變量的指針成員分別指向不同的堆區(qū)空間,,只是空間內(nèi)容拷??份,,這樣在各個結(jié)構(gòu)體變量釋放的時候就不會出現(xiàn)多次釋放同?段堆區(qū)空間的問題### 描述?下結(jié)構(gòu)體對?規(guī)則1. 數(shù)組成員對?規(guī)則。第?個數(shù)組成員應(yīng)該放在offffset為0的地?,,以后每個數(shù)組成員應(yīng)該放在offffset 為min(當(dāng)前成員的??,,#pargama pack(n))整數(shù)倍的地?開始(?如int在32位機器為4字節(jié),#pargama pack(2),,那么從2的倍數(shù)地?開始存儲)。2. 結(jié)構(gòu)體總的??,,也就是sizeof的結(jié)果,,必須是min(結(jié)構(gòu)體內(nèi)部最?成員,#pargama pack(n))的整數(shù)倍,,不?要補?,。3. 結(jié)構(gòu)體做為成員的對?規(guī)則。如果?個結(jié)構(gòu)體B?嵌套另?個結(jié)構(gòu)體A,還是以最?成員類型的??對?,,但是結(jié)構(gòu)體A的起點為A內(nèi)部最?成員的整數(shù)倍的地?,。(struct B?存有struct A,A?有 char,,int,,double等成員,那A應(yīng)該從8的整數(shù)倍開始存儲,。),,結(jié)構(gòu)體A中的成員的對?規(guī)則仍 滿?原則1、原則2,。### 結(jié)構(gòu)體與共?體的區(qū)別是啥結(jié)構(gòu)體中的成員擁有獨?的空間,,共?體的成員共享同?塊空間,但是每個共?體成員能訪問共?區(qū)的空間??是由成員?身的類型決定在項?中,,經(jīng)常把?些短???頻繁使?的函數(shù)寫成宏函數(shù),,這是由于宏函數(shù)沒有普通函數(shù)參數(shù)壓棧、跳轉(zhuǎn),、返回等的開銷,,可以調(diào)?程序的效率。宏通過使?參數(shù),,可以創(chuàng)建外形和作?都與函數(shù)類似地類 函數(shù)宏(function-like macro). 宏的參數(shù)也?圓括號括起來,,來保證宏函數(shù)的完整性。### 函數(shù)參數(shù)的傳遞方式有幾種,?(2)嚴(yán)格來看,只有一種傳遞,,值傳遞,,指針傳遞也是按值傳遞的,復(fù)制的是地址,。C語言的參數(shù)傳遞有傳值和傳地址兩種方式,。傳值的過程:(2)形參的存儲空間是函數(shù)被調(diào)用時才分配的,。調(diào)用開始,,系統(tǒng)為行參開辟一個臨時存儲區(qū),然后將各實參之值傳遞給行參,,這時形參就得到了實參的值,。(3)函數(shù)返回時,臨時存儲區(qū)也被撤銷,。傳值的特點:單向傳遞,,即函數(shù)中對形參變量的操作不會影響到調(diào)用函數(shù)中的實參變量。### 描述?下函數(shù)的定義與函數(shù)的聲明的區(qū)別函數(shù)定義:是指對函數(shù)功能的確?,,包括指定函數(shù)名,、函數(shù)類型、形參及其類型,、函數(shù)體等,,它是?個完整的、獨?的函數(shù)單位,。函數(shù)的聲明:是把函數(shù)的名字,、函數(shù)類型以及形參的個數(shù)、類型和順序(注意,,不包括函數(shù)體)通知編譯系統(tǒng),,以便在對包含函數(shù)調(diào)?的語句進(jìn)?編譯時,據(jù)此對其進(jìn)?對照檢查(例如函數(shù)名是否正確,,實參與形參的類型和個數(shù)是否?致)### 內(nèi)部函數(shù)與外部函數(shù)用static聲明,不能被外部函數(shù)調(diào)用,。用extern聲明,可以被外部函數(shù)(其他c文件)調(diào)用,。Note: 函數(shù)默認(rèn)為extern,。調(diào)用外部函數(shù)時,需要進(jìn)行聲明,,一般用頭文件聲明,。### 內(nèi)聯(lián)函數(shù)的優(yōu)缺點和適用場景是什么,?(1)優(yōu)點:內(nèi)聯(lián)函數(shù)與宏定義一樣會在原地展開,省去了函數(shù)調(diào)用開銷,,同時又能做類型檢查,。(2)缺點:它會使程序的代碼量增大,消耗更多內(nèi)存空間,。(3)適用場景:函數(shù)體內(nèi)沒有循環(huán)(執(zhí)行時間短)且代碼簡短(占用內(nèi)存空間?。?/section>### 變量的指針:指的是變量的地址,指針就是地址ip = &i; // ip加上運算符*后表示訪問指針ip內(nèi)存地址所存儲的內(nèi)容,,等價于直接訪問i,。*表示訪問內(nèi)存地址存儲的內(nèi)容y = *pt + 5; // 等價于y = x + 5`(*p)[n]`根據(jù)優(yōu)先級,先看括號內(nèi),,則p是一個指針,,這個指針指向一個一維數(shù)組,即數(shù)組的指針,,數(shù)組指針。`*p[n]`根據(jù)優(yōu)先級,,先看[],,這是一個數(shù)組,再結(jié)合*,,表示數(shù)組的元素是指針類型的,,指針的數(shù)組,即指針數(shù)組,,只能存放地址指針:沒存中每?個字節(jié)都會分配?個32位或64位的編號,,這個編號就是地址, ?指針就是內(nèi)存單元的編號。指針變量:本質(zhì)是變量 只是該變量存放的是空間的地址編號### 如何理解指針作為函數(shù)參數(shù)的輸?和輸出特性輸?特性:主調(diào)函數(shù)分配空間 背調(diào)函數(shù)使?該空間輸出特性:被調(diào)?分配空間 主調(diào)函數(shù)使?該空間指針變量未初始化,、指針釋放后未為置空,、指針操作超越變量作?域指針數(shù)組本質(zhì)是數(shù)組,只是數(shù)組的每個元素是?個指針(地址)庫是已經(jīng)寫好的,、成熟的,、可復(fù)?的代碼。每個程序都需要依賴很多底層庫,,不可能每個?的代碼從零開始編寫代碼,,因此庫的存在具有?常重要的意義。在我們的開發(fā)的應(yīng)?中經(jīng)常有?些公共代碼是需要反復(fù)使?的,,就把這些代碼編譯為庫?件,。 庫可以簡單看成?組?標(biāo)?件的集合,將這些?標(biāo)?件經(jīng)過壓縮打包之后形成的?個?件,。像在Windows這樣的平臺上,,最常?的c語?庫是由集成按開發(fā)環(huán)境所附帶的運?庫,這些庫?般由編譯?商提供(1)復(fù)制的內(nèi)容不同,。strcpy只能復(fù)制字符串,,而memcpy可以復(fù)制任意內(nèi)容,例如字符數(shù)組,、整型,、結(jié)構(gòu)體、類等,。(2)復(fù)制的方法不同,。strcpy不需要指定長度,它遇到被復(fù)制字符的串結(jié)束符'\0'才結(jié)束,,所以容易溢出,。memcpy則是根據(jù)其第3個參數(shù)決定復(fù)制的長度。(3)用途不同,。通常在復(fù)制字符串時用strcpy,,而需要復(fù)制其他類型數(shù)據(jù)時則一般用memcpy。### 在使?realloc給已分配的堆區(qū)空間追加空間時需要注意啥,??刷新,、滿刷新、強制刷新,、關(guān)閉刷新?進(jìn)制?件基于值編碼,,需要根據(jù)具體的應(yīng)?才能知道某個值具體的含義?本?件基于字符編碼,?個字節(jié)?個意思,,可以通過記事本打開基礎(chǔ)數(shù)據(jù)類型:以默認(rèn)的的長度對齊,,如char以1字節(jié)對齊,,short以2字節(jié)對齊等數(shù)組 :按照基本數(shù)據(jù)類型對齊,第一個對齊了后面的自然也就對齊了,。聯(lián)合體 :按其包含的長度最大的數(shù)據(jù)類型對齊,。結(jié)構(gòu)體:結(jié)構(gòu)體中每個數(shù)據(jù)類型都要對齊,結(jié)構(gòu)體本身以內(nèi)部最大數(shù)據(jù)類型長度對嵌入式c語言搭載微處理器,,用于嵌入式系統(tǒng)的啟動程序要能夠?qū)δ繕?biāo)系統(tǒng)的硬件和數(shù)據(jù)進(jìn)行初始化,,因此,用戶必須做特定的啟動程序,。一般情況下,,在支持微處理器的編譯器中會捆綁相應(yīng)的啟動程序,如下圖:
|