嵌入式軟體開發工程師面指南
- 一、C語言
- 1.1、區域變數能否和全域變數重名
- 1.2、如何用C撰寫死回圈
- 1.2、new和malloc
- 1.3、static的用法(定義和用途)(必考)
- 1.4、const的用法(定義與用途)(必考)
- 1.5、const常量和#define的區別(編譯階段、安全性、記憶體占用等)
- 1.6、volatile作用和用法
- 1.7、變數的作用域(全域變數和區域變數)
- 1.8、sizeof與strlen(字串,陣列)
- 1.9、與或非,異或,運算子優先級
- 1.10、遞回函式與回呼函式的區別是什么?
- 1.11、問什么要用回呼函式呢?
- 1.12、const關鍵字的作用
- 1.13、系統呼叫和函式呼叫的區別
- 1.14、段錯誤發生的原因
- 1.15、段錯誤發生的原因
- 1.16、什么時候會造成記憶體泄露
- 1.17、什么是大小端模式
- 1.18、全域變數可以宣告定義在頭檔案中?
- 1.19、C語言中各種資料型別與"0"的比較詳解
- 1.19.1、int型別資料和0比較
- 1.19.1、int型別資料和0比較
- 1.19.2、float型別與0比較
- 1.19.3、bool型別與0比較
- 1.19.4、指標型別與0比較
- 1.20、c語言中什么是位段
- 1.21、簡述什么是地址傳遞和值傳遞,并簡述兩者的區別
- 1.21、c語言中呼叫函式如何回傳多個值?
- 1.22、函式中能否回傳一個區域變數地址
- 1.23、堆疊的特點是什么
- 1.24、c語言中用了#define,作用范圍是從哪到哪
- 1.25、c語言中定義常量有幾種方式
- 1.26、程式的區域變數存在于哪里,全域變數存在于哪里,動態申請資料存在于哪里,
- 1.27、do……while和while有什么區別?
- 二、Linux
- 2.1、 Linux內核的組成部分
- 2.2、Linux系統的組成部分
- 2.3、系統呼叫與普通函式呼叫的區別
- 2.4、內核態,用戶態的區別
- 2.5、bootloader、內核、根檔案的關系
- 2.6 、Bootloader啟動的兩個階段:
- 2.7、linux下檢查記憶體狀態的命令
- 2.8、一個程式從開始運行到結束的完整程序(四個程序)
- 2.9、什么是堆,堆疊,記憶體泄漏和記憶體溢位?
- 2.10、死鎖的原因、條件
- 2.11、硬鏈接與軟鏈接
- 2.12、中斷和例外的區別
- 2.13、中斷怎么發生,中斷處理流程
- 2.14、linux下編譯優化選項
- 2.15、linux命令
- 2.16、硬實時系統和軟實時系統
- 三、資料結構
- 3.1、十大排序
- 3.2、演算法
- 3.3、佇列和堆疊的區別有什么?
- 3.4、順序表和鏈表他們的特點?
- 3.5、什么是完全二叉樹
- 3.6、什么是二叉樹
- 3.7、七大查找演算法
- 3.8、十大排序排序演算法
- 3.8、怎樣判斷一個演算法的優劣?
- 3.9、"演算法"的基本特征有哪些?
- 3.10、什么是哈希表
- 3.11、如何判斷單鏈表是否存在環
- 3.12、洗掉鏈表中倒數第n個節點
- 3.13、回圈佇列有什么用
- 四、行程與執行緒
- 4.1、什么是行程、執行緒、有什么區別
- 4.2、多行程與多執行緒的優缺點
- 4.3、什么時候用行程、什么時候用執行緒
- 4.4、父行程、子行程
- 4.5、Fork的作用是什么?
- 4.6、fork和vfork的區別
- 4.7、行程的開銷比執行緒大在了哪里?
- 4.8、什么是阻塞,什么是非阻塞
- 4.9、同步和互斥
- 4.10、申請互斥鎖的程序
- 4.11、創建守護行程的步驟
- 4.12、指出靜態庫和共享庫的區別
- 4.13、什么是 I/O 多路復用?
- 1.14、進執行緒的區別
- 1.15、一個程式中最多創建多少個執行緒
- 1.16、檔案io中的檔案描述符
- 1.17、執行緒中的同步應該怎么實作
- 1.18、行程間通信訊息佇列的機制
- 1.19、什么是行程池
- 1.20、行程之間通信的途徑有哪些?
- 1.21、產生死鎖的原因是什么?
- 1.22、行程和執行緒有什么區別?
- 五、網路編程
- 5.1、TCP、UDP的區別
- 4.5、TCP、UDP的優缺點
- 4.5、TCP、UDP適用場景
- 4.5、TCP為什么是可靠連接
- 5.6、OSI典型網路模型 ★★★
- 5.7、三次握手、四次揮手
- 5.8、常見網路協議
- 5.9、處理粘包問題
- 5.10、ip地址分了多少類
- 六、C++
- 6.1、構造和析構的作用
- 6.2、繼承是做什么的?
- 6.3、多型是做什么?
- 6.4、面向物件中的物件指的是什么?
- 6.5、類和物件的關系是什么?
- 6.6、類的關鍵詞用什么
- 6.7、如果想要在類的外部訪問類
- 6.8、友元有哪些呢?
- 6.9、繼承的作用是什么?
- 6.10、組合和繼承的區別是什么?
- 6.11、多型指的是什么?
- 6.12、什么是抽象類,抽象類怎么使用?
- 6.13、malloc 和 new的區別?
- 6.14、深拷貝和淺拷貝的區別是什么?
- 七、Qt
- 八、ARM體系結構
- 8.1、講一講馮諾依曼和哈佛體系的區別
- 8.2、什么是ARM體系架構
- 8.3、什么的例外
- 九、系統移植
- 9.1、什么是設備樹
- 十、驅動
- 10.1、什么是驅動?
- 十一、Python
- 十二、單片機
- 12.1、 IO口作業方式(學過STM32的人應該很熟悉)
- 12.2、請說明總線介面USRT、I2C、USB的異同點
- 12.3、IIC協議時序圖
- 12.4、單片機的SP指標始終指向
- 12.5、IIC總線在傳送資料程序中共有三種型別信號
- 12.6、FIQ中斷向量入口地址
- 12.7、SPI四種模式,簡述四種模式,并畫出時序圖
- 十三、雜項
- 13.1、高耦合低內聚
- 13.2、什么是溢位,什么是越界
- 跳轉:嵌入式軟體開發工程師面指南_總結
個人網站入口:http://www.baiziqing.cn/
一、C語言
1.1、區域變數能否和全域變數重名
能,區域會屏蔽全域,
1.2、如何用C撰寫死回圈
while(1){}或者for( ; ; )
1.2、new和malloc
1)、new和delete是c++的關鍵字,不需要頭檔案,需要編譯器支持;malloc和free是c/c++的庫函式、需要帶頭檔案stdlin.h
2)、使用new運算子申請記憶體分配時,無需指定記憶體塊的大小,編譯器會根據型別資訊自行計算;而malloc則需要支持本地所分配的大小,
3)、new運算子記憶體分配成功時,回傳的是物件型別的指標;而malloc記憶體分配成功則回傳void,
1.3、static的用法(定義和用途)(必考)
static 限制作用域
在C語言中,關鍵字static有三個明顯的作用:
1)、用static修飾區域變數:使其變為靜態儲存方式,那么這個區域變數執行完成時不會被釋放,繼續保留在記憶體中,
2)、用static修飾全域變數:使其在本檔案內部有效,而其他檔案不可以被參考或鏈接該變數,
3)、用static修飾函式:使函式只在本檔案內部有效,對其他檔案不可見,這樣的函式又叫靜態函式;使用靜態函式的好處,不用擔心與其他檔案的同名函式產生干擾,也是對函式本身保護的一種機制,
1.4、const的用法(定義與用途)(必考)
const主要用來修飾變數、函式形參和類成員函式:
1)、用const修飾常量:定義時就初始化,以后不能修改,
2)、用const修飾形參:func(const int a){ };該函式在函式內不能改變,
3)、用const修飾成員函式:該函式對成員變數只能進行只讀操作,就是不能修改成員變數的數值,
下面的宣告都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
第一和第二作業是一樣的,a是常整型數,
第三個意味著a是一個指向常整型數的指標,(整型數不可修改,但指標可以)
第四個意思是a是一個指向整型數的常數的指標,(指標指向的整型數是可以修改的,但指標是不可修改的)
第五個意味著a是一個指向整型數的常指標,(指標指向的整型數是不可修改的,同時指標也是不可修改的)
[scode type=“blue”]
結論和記憶方法: ***
(1)const 在 *前面,就表示const作用于p所指向的量,所以這時候p所指向的是個常量,
(2)const 在 *后面,表示p本身是常量,但是p指向的不一定是常量,
(3)*在const中間,表示p本身是常量,p指向的也是個常量,
[/scode]
1.5、const常量和#define的區別(編譯階段、安全性、記憶體占用等)
用#define max 100;定義的常量沒有型別(不就行型別安全檢查,可能會引數意想不到的錯誤)所給出的是一個立即數,編譯器只是把所定義的常量值與所在的常量名字聯系起來,define所定義的宏變數在預處理階段的時候進行替換,在程式中使用到該常量的地方都要進行拷貝替換,
用const int max = 255;定義的常量有型別(編譯時會進行型別檢查)名字,存盤在靜態區域中,在編譯時確定其值,在程式運行程序中const變數只有一個拷貝,而#define所定義的宏變數卻有多個拷貝,所以宏定義在程式運行程序中所消耗的記憶體比const變數的大很多,
1.6、volatile作用和用法
一個定義為volatile的變數是說這變數可能被意想不到的地改變,這樣不會假設這個變數的值了,
以下幾種情況都會用到volatile:
1)、并行設備的硬體存盤器,
2)、一個中斷服務子程式會訪問到的非自動變數,
3)、多執行緒應用中被幾個任務共享的變數,
1.7、變數的作用域(全域變數和區域變數)
全域變數:
在所以函式體外部定義,程式所在的部分(甚至其他檔案中的代碼)都可以使用,
全域變數不受作用域的影響(也就是全域變數的生命周期一直到程式的結束),
區域變數:
出現在一個作用域內,它們是局限于一個函式的,
區域變數經常被稱為自動變數,它們進入作用域時自動生成,離開作用域時自動消失,
關鍵字auto可以顯式說明這個問題,但是區域變數默認為auto,所以沒有必要宣告auto,
區域變數可以和全域變數重名,在區域變數作用域范圍內,全域變數失效,采用的是區域變數的值,
1.8、sizeof與strlen(字串,陣列)
1)、如果是陣列:
#include<stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
printf(“sizeof 陣列名=%d\n”,sizeof(a));
printf(“sizeof *陣列名=%d\n”,sizeof(*a));
}
運行結果:
sizeof 陣列名=20
sizeof *陣列名=4
2)、如果是指標,sizeof只會檢測到指標的型別,指標都是占用4位元組的空間(32位機),
sizeof是什么?是一個運算子,也是關鍵字,就不是一個函式,這和strlen()不同,strlen()是一個函式,
1.9、與或非,異或,運算子優先級

1.10、遞回函式與回呼函式的區別是什么?
答:回呼是一個函式把非當前函式當做引數傳遞到自身內部來呼叫;而遞回是自己呼叫自己,
1.11、問什么要用回呼函式呢?
答:我們對回呼函式的使用無非是對函式指標的應用,函式指標的概念本身很簡單,但是把函式指標應用于回呼函式就體現了一種解決問題的策略,一種設計系統的思想,
1.12、const關鍵字的作用
const是一個修飾符,被修飾的物件或者變數是不可修改的,也就是說const可讀不可改
1.13、系統呼叫和函式呼叫的區別
系統呼叫是最底層的應用,是面向硬體的,而庫函式的呼叫是面向開發的,相當于應用程式的API(即預先定義好的函式)介面;
1.14、段錯誤發生的原因
段錯誤 是指訪問的記憶體超過了系統給程式分配的記憶體空間,
原因:
- 訪問不存在的記憶體空間
- 訪問只讀的記憶體空間
- 訪問系統保護的記憶體空間
- 堆疊溢位
1.15、段錯誤發生的原因
1.16、什么時候會造成記憶體泄露
常見的記憶體泄露
(1)記憶體分配未成功,卻使用了它
(2)記憶體分配成功,但尚未初始化就參考它
(3)記憶體分配成功且初始化,但操作越過了記憶體的邊界
(4)忘記釋放記憶體,造成記憶體泄漏
(5)釋放了記憶體卻繼續使用它
1.17、什么是大小端模式
高位元組對應高地址(大端模式)、高位元組對應低地址(小端模式)
1.18、全域變數可以宣告定義在頭檔案中?
注意頭檔案中不可以放變數的定義!!!一般情況下頭檔案中只放變數的宣告,因為頭檔案要被其他檔案包含(即#include),如果把定義放到頭檔案的話,就不能避免多次定義變數,C++不允許多次定義變數,一個程式中對指定變數的定義只有一次,宣告可以無數次,
1.19、C語言中各種資料型別與"0"的比較詳解
1.19.1、int型別資料和0比較
1.19.1、int型別資料和0比較
if(a == 0)或者 if(a != 0)
1.19.2、float型別與0比較
const float N=0.0001;
if( (a>=N) && (a<=N)
不建議寫成:
if(a == 0)或者 if(a != 0)
1.19.3、bool型別與0比較
建議寫成:if(a)或者 if(!a)
1.19.4、指標型別與0比較
if(p == NULL) 或者 if(p != NULL)
1.20、c語言中什么是位段
位段(bit-field)是以位為單位來定義結構體(或聯合體)中的成員變數所占的空間,含有位段的結構體(聯合體)稱為位段結構,采用位段結構既能夠節省空間,又方便于操作,
1.21、簡述什么是地址傳遞和值傳遞,并簡述兩者的區別
值傳遞只是將變數的內容復制一份而已,函式進行操作的其實是另一個變數,只是另一個變數的值和傳遞的變數值是相同的,
而地址傳遞是直接把變數的地址傳遞給函式,這時函式是直接對原來的變數進行操作的,所以值會變化,
1.21、c語言中呼叫函式如何回傳多個值?
通過使用指標,在函式呼叫時,傳遞帶有地址的引數,并使用指標更改其值;這樣,修改后的值就會變成原始引數,
1.22、函式中能否回傳一個區域變數地址
一般的來說,函式是可以回傳區域變數的, 區域變數的作用域只在函式內部,在函式回傳后,區域變數的記憶體已經釋放了,
1.23、堆疊的特點是什么
堆疊的特點是先進后出表,堆疊是一種只能在一端進行插入和洗掉操作的特殊線性表,它按照先進后出的原則存盤資料,先進入的資料被壓入堆疊底,最后的資料在堆疊頂,需要讀資料的時候從堆疊頂開始彈出資料,
1.24、c語言中用了#define,作用范圍是從哪到哪
define只在當前檔案有效,如果是在頭檔案中定義的,則參考改頭檔案的檔案都有效
1.25、c語言中定義常量有幾種方式
定義常量PI的兩種方式:
#define Pi 3.1415926f;
const float pi 3.1415926f;
1.26、程式的區域變數存在于哪里,全域變數存在于哪里,動態申請資料存在于哪里,
程式的區域變數存在于堆疊區;全域變數存在于靜態區;動態申請資料存在于堆區,
1.27、do……while和while有什么區別?
do…while是先回圈再判斷,while是先判斷再回圈,
二、Linux
2.1、 Linux內核的組成部分
Linux內核主要由五個子系統組成:行程調度,記憶體管理,虛擬檔案系統,網路介面,行程間通信,
2.2、Linux系統的組成部分
Linux系統一般有4個主要部分:內核、shell、檔案系統和應用程式,
2.3、系統呼叫與普通函式呼叫的區別
1)、系統呼叫:
- 使用INT和IRET指令,內核和應用程核態,從而可以使用特權指令操控設備
- 依賴于內核,不保證移植性
- 在用戶空間和內核背景關系環境間切換
- 是作業系統的一個入口點
2)、普通函式呼叫:
- 使用CALL和RET指令,呼叫時沒有堆
- 平臺移植性好
- 屬于程序呼叫,呼叫開銷較小
- 一個普通功能函式的呼叫
2.4、內核態,用戶態的區別
內核態,作業系統在內核態運行——運行作業系統程式
用戶態,應用程式只能在用戶態運行——運行用戶程式
2.5、bootloader、內核、根檔案的關系
啟動順序:bootloader->linux kernel->rootfile->app
2.6 、Bootloader啟動的兩個階段:
Stage1:匯編語言
Stage2:c語言
2.7、linux下檢查記憶體狀態的命令
查看行程:top
查看記憶體:free
cat /proc/meminfo
vmstat
2.8、一個程式從開始運行到結束的完整程序(四個程序)
預處理(Pre-Processing)、編譯(Compiling)、匯編(Assembling)、鏈接(Linking)
2.9、什么是堆,堆疊,記憶體泄漏和記憶體溢位?
堆疊由系統操作,程式員不可以操作,
所以記憶體泄漏是指堆記憶體的泄漏,
堆記憶體是指程式從堆中分配的,大小任意的,使用完后必須顯式釋放的記憶體,應用程式一般使用malloc,new等函式從堆中分配到一塊記憶體,使用完后,程式必須負責相應的呼叫free或delete釋放該記憶體塊,否則,這塊記憶體就不能被再次使用,
記憶體溢位:你要求分配的記憶體超出了系統能給你的,系統不能滿足需求,于是產生溢位,
記憶體越界:向系統申請了一塊記憶體,而在使用記憶體時,超出了申請的范圍(常見的有使用定大小陣列時發生記憶體越界)
記憶體溢位問題是 C 語言或者 C++ 語言所固有的缺陷,它們既不檢查陣列邊界,又不檢查型別可靠性(type-safety),
2.10、死鎖的原因、條件
產生死鎖的原因主要是:
1)、因為系統資源不足,
2)、行程運行推進的順序不合適,
3)、資源分配不當等,
2.11、硬鏈接與軟鏈接
1)、硬鏈接
硬鏈接只能參考同一檔案系統中的檔案,它參考的是檔案在檔案系統中的物理索引(也稱為inode),當您移動或洗掉原始檔案時,硬鏈接不會被破壞,因為它所參考的是檔案的物理資料而不是檔案在檔案結構中的位置,
硬鏈接的檔案不需要用戶有訪問原始檔案的權限,也不會顯示原始檔案的位置,這樣有助于檔案的安全,如果您洗掉的檔案有相應的硬鏈接,那么這個檔案依然會保留,直到所有對它的參考都被洗掉,
2)、軟鏈接
軟連接,其實就是新建立一個檔案,這個檔案就是專門用來指向別的檔案的(那就和windows 下的快捷方式的那個檔案有很接近的意味),
軟連接產生的是一個新的檔案,但這個檔案的作用就是專門指向某個檔案的,刪了這個軟連接檔案,那就等于不需要這個連接,和原來的存在的物體原檔案沒有任何關系,但洗掉原來的檔案,則相應的軟連接不可用,
2.12、中斷和例外的區別
內中斷:同步中斷(例外)是由cpu內部的電信號產生的中斷,其特點為當前執行的指令結束后才轉而產生中斷,由于有cpu主動產生,其執行點必然是可控的,
外中斷:異步中斷是由cpu的外設產生的電信號引起的中斷,其發生的時間點不可預期,
2.13、中斷怎么發生,中斷處理流程
請求中斷→回應中斷→關閉中斷→保留斷點→中斷源識別→保護現場→中斷服務子程式→恢復現場→中斷回傳,
2.14、linux下編譯優化選項
加:-o
2.15、linux命令
1)、改變檔案屬性的命令:chmod (chmod 777 /etc/squid 運行命令后,sq
就被修改為777(可讀可寫可執行))
2)、查找檔案中匹配字串的命令:grep
3)、查找當前目錄:pwd
4)、洗掉目錄:rm -rf 目錄名
5)、洗掉檔案:rm 檔案名
6)、創建目錄(檔案夾):mkdir
7)、創建檔案:touch
8)、vi和vim 檔案名也可以創建
9)、解壓:tar -xzvf 壓縮包
打包:tar -cvzf 目錄(檔案夾)
10)、查看行程對應的埠號
1、先查看行程pid
ps -ef | grep 行程名
2、通過pid查看占用埠
netstat -nap | grep 行程pid
2.16、硬實時系統和軟實時系統
軟實時系統:
Windows、Linux系統通常為軟實時,當然有補丁可以將內核做成硬實時的系統的,
硬實時系統:
對時間要求很高,限定時間內不管做沒做完必須回傳,
VxWorks,uCOS,FreeRTOS,WinCE,RT-thread等實時系統;
三、資料結構
3.1、十大排序
我想對于每一個經歷過秋招的小伙伴們來說,十大排序基本都被問過(快速排序、歸并排序、堆排序、冒泡排序、插入排序、選擇排序、希爾排序、桶排序、基數排序),
對這十大排序的考察主要有兩點:
1、考察時間復雜度、空間復雜度、穩定與否,
2、手寫某種排序,
第一點:對于時間復雜度的考察,可能會考察插入排序的平均復雜度是多少?最壞和最好復雜度又是多少?有時候也會從別的角度來對你進行考察,直接會問你了解到的的排序中哪些排序是穩定的?哪些不是穩定的?
第二點:快速排序手寫次數絕對占據第一名,因為現在企業招聘基本都是有代碼要求的,有時候面試官可能也拿不準讓你寫什么演算法題,“算了,寫個快排吧”,快排的頻率就是就是這樣被拉高的;第二高頻率的應該就是歸并排序了,在筆者秋招程序中,手寫過5次歸并,3次快排,因為歸并是剛好比快排難度大一點,但也不是那種特別難的排序方法,對于女生來說,讓手寫的排序一般是冒泡排序、快速排序、歸并排序,對于男生同學而言,要求手寫的排序一般有快速排序、歸并排序以及堆排序,
十大排序中考察最多的就是冒泡排序、快速排序、歸并排序、堆排序以及可能會出現的桶排序和基數排序了,其余排序出現的概率稍小一點,
3.2、演算法
嵌入式考察演算法大多都是雙向鏈表、二叉樹、字串翻轉和復制這些普通題目,刷題可以在LeetCode、牛客網、杭電OJ等,
十種常見排序演算法可以分為兩大類:
非線性時間比較類排序:通過比較來決定元素間的相對次序,由于其時間復雜度不能突破O(nlogn),因此稱為非線性時間比較類排序,
線性時間非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基于比較排序的時間下界,以線性時間運行,因此稱為線性時間非比較類排序,
3.3、佇列和堆疊的區別有什么?
堆疊:
堆疊(stack)又名堆疊,線性表,僅允許在表的一端進行插入和洗掉運算,這一端為堆疊頂,另一端為堆疊底,先進后出,
佇列:
佇列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進行洗掉操作,而在表的后端(rear)進行插入操作,和堆疊一樣,佇列是一種操作受限制的線性表,進行插入操作的端稱為隊尾,進行洗掉操作的端稱為隊頭,
3.4、順序表和鏈表他們的特點?
線性表存盤資料,需要預先申請一塊存盤空間,然后將資料按照次序逐一存盤,資料之間緊密貼合,不留一絲空隙,
鏈表的存盤方式與順序表截然相反,什么時候存盤資料,什么時候才申請存盤空間,資料之間的邏輯關系依靠每個資料元素攜帶的指標維持
3.5、什么是完全二叉樹
如果二叉樹中除去最后一層節點為滿二叉樹,且最后一層的結點依次從左到右分布,則此二叉樹被稱為完全二叉樹,
3.6、什么是二叉樹
樹有很多種, 每個節點最多只能有兩個子節點的叫二叉樹
二叉樹的子節點分為左節點和右節點
3.7、七大查找演算法
順序查找
二分查找
插值查找
斐波那契查找
樹表查找
分塊查找
哈希查找
3.8、十大排序排序演算法
(1)冒泡排序;
(2)選擇排序;
(3)插入排序;
(4)希爾排序;
(5)歸并排序;
(6)快速排序;
(7)基數排序;
(8)堆排序;
(9)計數排序;
(10)桶排序;
3.8、怎樣判斷一個演算法的優劣?
時間復雜度
空間復雜度
3.9、"演算法"的基本特征有哪些?
一個演算法應該具有以下五個重要的特征:
1,有窮性(Finiteness)
2,確切性(Definiteness)
3,輸入項(Input)
4,輸入項(Input)
5,可行性(Effectiveness)
3.10、什么是哈希表
根據關鍵碼值而直接進行訪問的資料結構
3.11、如何判斷單鏈表是否存在環
方法一、窮舉遍歷
方法二、哈希表快取
方法三、快慢指標
方法四、Set集合大小變化
3.12、洗掉鏈表中倒數第n個節點
要洗掉倒數第n個節點,我們就要找到其前面一個節點,也就是倒數第n+1個節點,找到這個節點就可以進行洗掉;
定義兩個指標,p和cur,cur指標向前走,走了n+1步之后,p指標開始走,當cur指標走到鏈表結尾的時候,p指標剛好走到倒數第n+1個節點處,
3.13、回圈佇列有什么用
為充分利用向量空間,克服"假溢位"現象的方法是:將向量空間想象為一個首尾相接的圓環,并稱這種向量為回圈向量,
四、行程與執行緒
4.1、什么是行程、執行緒、有什么區別
行程是資源(CPU、記憶體等)分配的基本單位,執行緒是CPU調度和分配的基本單位(程式執行的最小單位),
同一時間,如果CPU是單核,只有一個行程在執行,所謂的并發執行,也是順序執行,只不過由于切換太快,誤以為這些行程同步執行,多核CPU可以同一時間點多個行程在執行,
4.2、多行程與多執行緒的優缺點
1)、一個行程死了不影響其他行程,一個執行緒奔潰很可能影響1到它本身所處在的執行緒,
2)、創建多行程的系統花銷大于創建多執行緒,
3)、多行程通訊因為需要跨域行程邊界,不適合大量的資料傳送,適合小資料或者密集的資料傳送,多執行緒無需跨域行程邊界,適合各執行緒間的大量傳送,并且多執行緒跨域共享同一行程的共享記憶體和變數,
4.3、什么時候用行程、什么時候用執行緒
行程間通訊:
(1)、有名管道、無名管道;(2)、信號;(3)、共享記憶體;(4)、訊息佇列;(5)、信號量;(6)、socket
執行緒通訊(鎖):
(1)、信號量;(2)、讀寫鎖;(3)、條件變數;(4)、互斥鎖;(5)、自旋鎖
4.4、父行程、子行程
父行程呼叫fork()以后,克隆出一個子行程,子行程和父行程擁有相同內容的代碼段、資料段和用戶堆疊,
父行程和子行程誰先執行不一定,看CPU,所以我們一般會設定父行程等待子行程執行完畢,
4.5、Fork的作用是什么?
在Linux下產生新的行程的系統呼叫就是fork函式
4.6、fork和vfork的區別
- fork ():子行程拷貝父行程的資料段,代碼段
vfork( ):子行程與父行程共享資料段 - fork ()父子行程的執行次序不確定
vfork 保證子行程先運行,在呼叫exec 或exit 之前與父行程資料是共享的,在它呼叫exec
或exit 之后父行程才可能被調度運行,
4.7、行程的開銷比執行緒大在了哪里?
- 創建行程需要為行程劃分出一塊完整的記憶體空間,有大量的初始化操作,比如要把記憶體分段(堆疊、正文區等),
- 創建執行緒則簡單得多,只需要確定 PC 指標 和暫存器 的值,并且給執行緒分配一個堆疊 用于執行程式,同一個行程的多個執行緒間可以復用堆疊 ,
- 因此,創建行程比創建執行緒慢,而且行程的記憶體開銷更大,
4.8、什么是阻塞,什么是非阻塞
阻塞呼叫是指呼叫結果回傳之前,當前執行緒會被掛起,呼叫執行緒只有在得到結果之后才會回傳,
非阻塞呼叫指在不能立刻得到結果之前,該呼叫不會阻塞當前執行緒,
4.9、同步和互斥
互斥 :是指散步在不同任務之間的若干程式片斷,當某個任務運行其中一個程式片段時,其它任務就不能運行它們之中的任一程式片段,只能等到該任務運行完這個程式片段后才可以運行,
同步 :是指散布在不同任務之間的若干程式片斷,它們的運行必須嚴格按照規定的某種先后次序來運行,這種先后次序依賴于要完成的特定的任務,
4.10、申請互斥鎖的程序
/*頭檔案*/
#include <pthread.h>
1)初始化互斥鎖
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
2)上鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);
3)解鎖
int pthread_mutex_unlock(pthread_mutex_t * mutex);
4)銷毀互斥鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);
4.11、創建守護行程的步驟
- 創建子行程,父行程退出
- 子行程下創建新的會話
- 設定當前目錄為根目錄
- 設定檔案權限掩碼
- 退出檔案描述符
4.12、指出靜態庫和共享庫的區別
靜態庫編譯時程式較大,可以獨立運行,
動態庫編譯時程式交小,不可獨立運行,
4.13、什么是 I/O 多路復用?
I/O 通常指網路 I/O,多路指多個 Socket 鏈接,復用指作業系統進行運算調度的最小單位執行緒 ,整體意思也就是多個網路 I/O 復用一個或少量的執行緒來處理 Socket,
I/O 多路服用有多種實作模式:select、 poll、 epoll、 kqueue
1.14、進執行緒的區別
執行緒依賴于行程,同一行程的多個執行緒共享這一行程的資源, 所以行程間的切換會比執行緒更加的耗時,
1.15、一個程式中最多創建多少個執行緒
一個執行緒的堆疊要預留1M的記憶體空間,而一個行程中可用的記憶體空間只有2G,所以理論上一個行程中最多可以開2048個執行緒,但是記憶體當然不可能完全拿來作執行緒的堆疊,所以實際數目要比這個值要小,
1.16、檔案io中的檔案描述符
對于Linux而言,所有對設備或檔案的操作都是通過檔案描述符進行的,
1.17、執行緒中的同步應該怎么實作
當使用多個執行緒來訪問同一個資料時,非常容易出現執行緒安全問題(比如多個執行緒都在操作同一資料導致資料不一致),所以我們用同步機制來解決這些問題,
1.18、行程間通信訊息佇列的機制
訊息佇列與命名管道有許多類似之處,但少了在打開和關閉管道時的復雜性,但使用訊息佇列并未解決我們在使用命名管道時遇到的問題,比如管道滿時的阻塞問題,
與命名管道相比,訊息佇列的優勢在于,它獨立于發送和接收行程而存在,這消除了在同步命名管道的打開和關閉時可能產生的一些困難,
1.19、什么是行程池
行程池的作用是在多個客戶端并發請求時提高服務器的處理效率,
1.20、行程之間通信的途徑有哪些?
行程間通訊方式有:管道,信號,信號量,訊息佇列,共享記憶體,套接字共六種,
1.21、產生死鎖的原因是什么?
系統資源有限,
行程推進順序不合理,
1.22、行程和執行緒有什么區別?
行程是資源分配的最小單位,
執行緒是程式執行的最小單位,
五、網路編程
5.1、TCP、UDP的區別
TCP --> 傳輸控制協議,提供面向物件連接、可靠的位元組流服務,當客戶端和服務器交換資料前,必須先在雙方之間建立一個TCP連接、之后才能傳輸資料,
UDP --> 用戶資料報協議,是一個簡單的面向資料報的運算層協議,UDP不提供可靠性,它是把應用程式傳給IP層的資料報發送出去,但是并不能保證它們能到達目的地,
| TCP | <–> | UDP |
|---|---|---|
| TCP是面向連接 | UDP面向無連接 | |
| UDP程式結構簡單 | ||
| TCP是面向位元組流 | UDP是基于資料報 | |
| TCP保證資料正確性 | UDP可能丟包 | |
| TCP保證資料順序到達 | UDP不保證資料到達 |
4.5、TCP、UDP的優缺點
TCP優點:可靠穩定
TCP的可靠體現在TCP在傳輸資料之前,會有三次握手來建立連接,而且在資料傳遞時,有確認、視窗、重傳、阻塞控制機制,在資料傳完之后,還會斷開來連接用來節約系統資源,
TCP缺點:慢、效率低、占用系統資源高、容易被攻擊
在傳遞資料之前要建立連接,這會消耗時間,而且在資料傳遞時,確認機制、重傳機制、阻塞機制等會消耗大量時間,而且每臺設備上維護所有的傳遞連接,
UDP優點:快,比TCP稍安全
UDP沒有TCP擁有各種機制,是一種無狀態的傳輸協議,所以傳輸資料非常快,沒有TCP整型機制,被攻擊的機會就少一些,但也是無法避免被攻擊,
UDP缺點:不可靠、不穩定
因為沒有TCP的這些機制,UDP在傳輸資料時,如果網路質量不好,就會容易丟包,造成資料的缺失,
4.5、TCP、UDP適用場景
TCP:傳輸一些對信號完整性,信號質量有要求的資訊,
UDP:對網路通信質量要求不高時,要求網路通信速度要快的場景,
4.5、TCP為什么是可靠連接
因為TCP傳輸的資料滿足3大條件,不丟失,不重復,按順序到達,
5.6、OSI典型網路模型 ★★★


5.7、三次握手、四次揮手
1)、三次握手程序

- 第一次握手:建立連接時,客戶端發送syn包(syn=x)到服務器,并進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers),
- 第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=x+1),同時自己也發送一個SYN包(syn=y),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
- 第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手,
TCP/IP建立連接是三次握手程序:
第一次:建立連接時,客戶端向服務器發送連接請求,進入SYN_END狀態,并等待服務器確認,
第二次:服務器收到客戶端連接請求,并向客戶端發送允許連接應答,進入SYN_RECV狀態,
第三次:客戶端收到服務器允許連接應答,并向服務器發送確認連接,此時客戶端和服務器進入通信狀態,三次握手完成,
2)、四次揮手程序

- 1.客戶端行程發出連接釋放報文,并且停止發送資料,釋放資料報文首部,FIN=1,其序列號為seq=u(等于前面已經傳送過來的資料的最后一個位元組的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態, TCP規定,FIN報文段即使不攜帶資料,也要消耗一個序號,
- 2.服務器收到連接釋放報文,發出確認報文,ACK=1,ack=u+1,并且帶上自己的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態,TCP服務器通知高層的應用行程,客戶端向服務器的方向就釋放了,這時候處于半關閉狀態,即客戶端已經沒有資料要發送了,但是服務器若發送資料,客戶端依然要接受,這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間,
- 3.客戶端收到服務器的確認請求后,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送連接釋放報文(在這之前還需要接受服務器發送的最后的資料),
- 4.服務器將最后的資料發送完畢后,就向客戶端發送連接釋放報文,FIN=1,ack=u+1,由于在半關閉狀態,服務器很可能又發送了一些資料,假定此時的序列號為seq=w,此時,服務器就進入了LAST-ACK(最后確認)狀態,等待客戶端的確認,
[collapse status=“false” title=“常見面試題:”]
【問題1】為什么連接的時候是三次握手,關閉的時候卻是四次握手? ★★★
答:三次握手時,服務器同時把ACK和SYN放在一起發送到了客戶端那里,
四次揮手時,當收到對方的 FIN 報文時,僅僅表示對方不再發送資料了但是還能接收資料,己方是否現在關閉發送資料通道,需要上層應用來決定,因此,己方 ACK 和 FIN 一般都會分開發送,
【問題2】為什么客戶端最后還要等待2MSL?
答:客戶端需要保證最后一次發送的ACK報文到服務器,如果服務器未收到,可以請求客戶端重發,這樣客戶端還有時間再發,重啟2MSL計時,
【問題3】為什么不能用兩次握手進行連接?
答:3次握手完成兩個重要的功能,既要雙方做好發送資料的準備作業(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手程序中被發送和確認,
【問題4】如果已經建立了連接,但是客戶端突然出現故障了怎么辦?
TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源,服務器每收到一次客戶端的請求后都會重新復位這個計時器,時間通常是設定為2小時,若兩小時還沒有收到客戶端的任何資料,服務器就會發送一個探測報文段,以后每隔75秒鐘發送一次,若一連發送10個探測報文仍然沒反應,服務器就認為客戶端出了故障,接著就關閉連接,
[/collapse]
5.8、常見網路協議
TCP/IP協議
NetBEUI
IPX/SPX協議
5.9、處理粘包問題
解決粘包問題: 就是轉換成發送資料和接收資料的格式,
發送資料: 發送資料,先發送資料的長度,然后在發送真實資料的位元組數;
接收資料: 接收真實資料的長度,然后在安置位元組長度接收資料;
5.10、ip地址分了多少類
A類:0 ~ 127.255.255.255
B類:128 ~ 191.255.255.255
C類:192 ~ 223.255.255.255
D類:224 ~ 239.255.255.255
E類:240 ~ 255.255.255.255
六、C++
最喜歡問的莫過于strlen與sizeof的區別、explicit關鍵字、mutable關鍵字、指標和參考、public、protected、private三者在繼承情況下的一些訪問權限、菱形繼承、友元函式等,這些隨便一本基礎的C++書籍都會講到,
6.1、構造和析構的作用
建構式只是起初始化值的作用,但實體化一個物件的時候,可以通過實體去傳遞引數,從主函式傳遞到其他的函式里面,這樣就使其他的函式里面有值了,
解構式與建構式的作用相反,用于撤銷物件的一些特殊任務處理,可以是釋放物件分配的記憶體空間
特點:解構式與建構式同名,但該函式前面加~, 解構式沒有引數,也沒有回傳值,而且不能多載
6.2、繼承是做什么的?
繼承是指一個物件直接使用另一物件的屬性和方法
6.3、多型是做什么?
多型首先是建立在繼承的基礎上的,先有繼承才能有多型,多型是指不同的子類在繼承父類后分別都重寫覆寫了父類的方法,即父類同一個方法,在繼承的子類中表現出不同的形式,
6.4、面向物件中的物件指的是什么?
就是實體化了的類,類是屬性和方法的封裝,物件是 這個類的具體實作,
6.5、類和物件的關系是什么?
物件是類實體化出來的,物件中含有類的屬性,類是物件的抽象,
6.6、類的關鍵詞用什么
class
6.7、如果想要在類的外部訪問類
C public的類成員
可以作為虛函式的是普通函式,解構式,
6.8、友元有哪些呢?
友元函式就是以friend開頭的一種破壞類的封裝性的一種用法
友元類的私有和保護成員在類外不可以使用
6.9、繼承的作用是什么?
繼承是指在已存在的類的基礎上擴展產生新的類,
意義:繼承是面向物件程式設計的三大特征(封裝、繼承和多型)之一
6.10、組合和繼承的區別是什么?
組合和繼承是面向物件中兩種代碼復用的方式,組合是指在新類中創建原有類的物件,重復利用已有類的功能,繼承是面向物件的主要特性之一,它允許設計人員根據其他類的實作來定義一個類的實作,
6.11、多型指的是什么?
多型首先是建立在繼承的基礎上的,先有繼承才能有多型,多型是指不同的子類在繼承父類后分別都重寫覆寫了父類的方法,即父類同一個方法,在繼承的子類中表現出不同的形式,多型成立的另一個條件是在創建子類時候必須使用父類new子類的方式,
6.12、什么是抽象類,抽象類怎么使用?
抽象類是特殊的類,只是不能被實體化;除此以外,具有類的其他特性;重要的是抽象類可以包括抽象方法,這是普通類所不能的,
如果預計要創建組件的多個版本,則創建抽象類,抽象類提供簡單的方法來控制組件版本,
如果創建的功能將在大范圍的全異物件間使用,則使用介面,如果要設計小而簡練的功能塊,則使用介面,
如果要設計大的功能單元,則使用抽象類.如果要在組件的所有實作間提供通用的已實作功能,則使用抽象類,
抽象類主要用于關系密切的物件;而介面適合為不相關的類提供通用功能,
6.13、malloc 和 new的區別?
malloc/free是標準庫函式,new/delete是C++運算子
malloc失敗回傳空,new失敗拋例外
new/delete會呼叫構造、解構式,malloc/free不會,所以他們無法滿足動態物件的要求,
new回傳有型別的指標,malloc回傳無型別的指標
6.14、深拷貝和淺拷貝的區別是什么?
淺拷貝(shallowCopy)只是增加了一個指標指向已存在的記憶體地址,
深拷貝(deepCopy)是增加了一個指標并且申請了一個新的記憶體,使這個增加的指標指向這個新的記憶體,使用深拷貝的情況下,釋放記憶體的時候不會因為出現淺拷貝時釋放同一個記憶體的錯誤,
七、Qt
八、ARM體系結構
8.1、講一講馮諾依曼和哈佛體系的區別
哈佛結構:
程式和資料分開獨立放在不同的記憶體塊中, 彼此完全分離的結構稱為哈佛結構,譬如 大部分的單(MCS51、 ARM9等)均采用哈佛結構,
馮·諾伊曼結構:
程式和資料都放在記憶體中,且不彼此分離 的結構稱為馮諾依曼結構,譬如Intel的 CPU均采用馮諾依曼結構,
8.2、什么是ARM體系架構
ARM體系結構包含有:
(1)結構
- 不同ARM體系采用不同指令集
- 哈佛結構是將資料與指令分開存盤并行
- 馮諾依曼結構是混合存盤的
(2)ARM作業模式
User 、FIQ、IRQ、System、Supervisor、Abort、Undef
(3)暫存器
ARM有37個暫存器
(4)ARM指令機器碼
8.3、什么的例外
正常作業之外的流程都叫例外
九、系統移植
9.1、什么是設備樹
設備樹:用樹型結構描述設備節點
十、驅動
10.1、什么是驅動?
控制硬體的軟體
驅動是專門為系統撰寫的組態檔,沒有驅動電腦便無法正常運行,簡單來說,驅動是連接電腦和其他硬體的必備程式,
十一、Python
十二、單片機
12.1、 IO口作業方式(學過STM32的人應該很熟悉)
上拉輸入、下拉輸入、推挽輸出、開漏輸出,
12.2、請說明總線介面USRT、I2C、USB的異同點
串/并、速度、全/半雙工、總線拓撲等,
12.3、IIC協議時序圖

12.4、單片機的SP指標始終指向
堆疊頂
12.5、IIC總線在傳送資料程序中共有三種型別信號
它們分別是:開始信號、結束信號和應答信號,
12.6、FIQ中斷向量入口地址
FIQ和IRQ是兩種不同型別的中斷,ARM為了支持這兩種不同的中斷,提供了對應的叫做FIQ和IRQ處理器模式(ARM有7種處理模式),
FIQ的中斷向量地址在0x0000001C,而IRQ的在0x00000018,
12.7、SPI四種模式,簡述四種模式,并畫出時序圖
spi四種模式SPI的相位(CPHA)和極性(CPOL)分別可以為0或1,對應的4種組合構成了SPI的4種模式(mode)
Mode 0 CPOL=0, CPHA=0
Mode 1 CPOL=0, CPHA=1
Mode 2 CPOL=1, CPHA=0
Mode 3 CPOL=1, CPHA=1
簡述四種模式,并畫出時序圖參考鏈接:https://www.cnblogs.com/gmpy/p/12461461.html
十三、雜項
13.1、高耦合低內聚
高內聚低耦合,是軟體工程中的概念,是判斷軟體設計好壞的標準,主要用于程式的面向物件的設計,主要看類的內聚性是否高,耦合度是否低,目的是使程式模塊的可重用性、移植性大大增強,通常程式結構中各模塊的內聚程度越高,模塊間的耦合程度就越低,
13.2、什么是溢位,什么是越界
溢位本義是算術溢位(arithmetic overflow),指算術計算結果無法在一定范圍內表示,細分上溢(overflow)和下溢(underflow),
越界即訪問越界(access out of range),指對存盤的訪問不在預先指定的界限內,
邏輯上來說可能造成訪問越界的計算結果也可以看成一種溢位,這是引申義,只不過兩種情況經常一起出現,所以混用了,
跳轉:嵌入式軟體開發工程師面指南_總結
跳轉:嵌入式軟體開發工程師面指南_總結
跳轉:開頭
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/404143.html
標籤:其他
上一篇:2.C++-選擇排序、冒泡排序、插入排序、希爾排序、歸并排序、快速排序
下一篇:python猜數字小游戲制作
