您好,登錄后才能下訂單哦!
1、計算機為什么需要編程?編程已經編了這么多年,已經寫了很多程序,為什么還需要編程?
因為我們需要(希望)通過程序,達到一定的目的或者得到一定的結果。
編寫新的程序是為了得到不同的結果。
計算機程序 = 代碼 + 數據 (經過運行后得到一個結果,就是計算機程序運行的結果)
從宏觀上理解:代碼就是動作,就是加工數據指令。
數據就是數字,就是我們希望被代碼加工的數字。
結論:計算機編程不外乎兩種目的,結果或者過程;即加工數據得到結果。
可以用函數來類比:比如函數的形參就是待加工的數據(有可能函數內還需要一些臨時數據,就是局部變量),函數體就是代碼,函數體的執行就是加工過程,函數的返回值就是結果
2、程序就是有很多個函數組成的,函數是程序的重要組成部分。
程序需要運行才會得到我們需要的結果或者過程。
程序的本質就是函數,函數的本質是加工數據的動作。
3、馮諾依曼結構和哈佛結構
馮諾依曼結構是:數據和代碼放在一起。
哈佛結構是:數據和代碼分開存在。
什么是代碼:函數
什么是數據:全局變量、局部變量
譬如在S5PV210中運行的linux系統上,運行應用程序時:這時候所有的應用程序的代碼和數據都在DRAM,所以這種結構就是馮諾依曼結構;
在單片機中,我們把程序代碼燒寫到Flash(內置NorFlash,flash是只讀的)中,然后程序在Flash中原地運行,程序中所涉及到的數據(全局變量、局部變量)不能放在Flash中,必須放在RAM(SRAM)中。這種就叫哈佛結構。
4、動態內存DRAM和靜態內存SRAM
靜態內存是系統分給一定的內存后不再變化了,也就是在程序一開始運行就分配內存(不需要初始化就可以直接使用的),直到程序結束了,內存才被釋放;
動態內存是系統開始不分配內存,運行時根據需要分配(需要先進行初始化才能進行使用),也就是在程序調用在程序中定義的函數時才被分配,函數調用結束了,內存就釋放
5、為什么需要內存?
總結:內存是用來存儲可變數據的,數據在程序中表現為全局變量或局部變量等(在gcc中,常量也是存儲在內存中;但在大部分單片機中,常量存儲在flash中的,也就是代碼段中)
很多編程的關鍵都是為了內存,譬如數據結構和算法
數據結構是研究數據如何組織的,而數據是放在內存中的。
算法是研究如何更優秀的更有效的加工數據,也離不開內存。衡量一個算法優秀與否,絕大部分與這個算法所占的內存大小有關
。
6、如何管理內存?
內存是程序的一種資源,不能過于或隨便的浪費。所以管理內存對程序來說是一種很重要的技術。
在沒有操作系統(也就是裸機程序)中,程序需要直接操作內存,編程者需要自己計算內存的使用和安排,如果不小心把內存用錯了,后果需要自己承擔。
從語言角度來講:不同的語言提供了不同的內存操作接口;
譬如匯編:根本沒有任何內存管理,內存管理全靠程序員自己,匯編中操作內存時直接使用內存地址(如0xd0020010),非常麻煩。
譬如C語言:C語言中編譯器幫我們管理直接內存地址,我們都是通過編譯器提供的變量名等來訪問內存的。在操作系統中,如果需要大塊內存,可以通過API(malloc分配內存free釋放內存)來訪問系統內存;在裸機系統中,如果需要大塊的內存,就需要自己來定義數組等解決
總結:語言沒有好壞,只有適應不適應;譬如當我們程序對性能(如操作系統內核)非常需要時就會使用C/C++,當我們對開發程序速度非常需要時,就會使用java/C#
7、什么是內存?
內存(RAM)從硬件上講就是一個電腦配件(內存條)。
從邏輯上講內存是一種這樣的東西,可以隨機訪問,隨時進行讀寫(也可以限制只讀或者只寫)。
內存在 編程中天生就是為存放變量的(也可以說就是有了內存,才有了C語言的變量,原來受限于硬件)
內存實際是有無數個內存單元格組成的,每一個單元格都有一個唯一的內存地址
用大樓來類比內存很合適,內存就像是一棟無限高的大樓,一個個內存單元格就像是大樓內的一個個小房子,內存地址就像是門牌號,存進去的內容就像是住進去的人
8、位,字節,半字,字的概念和內存位寬
內存單元的大小單位:位(1bit) 字節(8bit) 半字(一般是16bit) 字(一般是32bit)
在所有計算機,所有操作系統中,位永遠是 1bit,字節永遠是 8bit
歷史上曾經出現過16位,32位,64位系統三種,而且系統還有windows,linux,ios等。半字和字等很多概念被混亂定義過
所以在工作中不要詳細區分字,半字,雙子的概念,只要知道這些單位具體占多少位是依賴于平臺的,實際工作中先去搞清楚所在平臺的定義,需要注意的是半字一定是字的一半,雙字一定是字的2倍
編程一般用不到字的概念,區分主要是我們會在文檔中用到字,如果不加區分,容易造成理解錯誤
在linux+ARM的平臺上 字是32位的
內存芯片之間可以并聯,即使是8位的內存芯片,通過并聯可以也可以做出來16位,32位的內存芯片
9、內存編址和尋址、內存對齊
內存在邏輯上就是一個一個的格子(內存單元格),里面可以存儲數據,每一個單元格都有一個內存地址,單元格與內存地址一一對應且永久綁定,這就是內存編址的方法
一個內存單元有兩個概念:地址和空間(內存單元的兩面性)
關鍵:內存編址是以字節為單位的
一個內存地址,對應的空間(內存單元)大小是一定的,就是一個字節(8bit)
內存對齊;對齊訪問和硬件匹配,所以效率高,非對齊訪問和硬件不搭配,所以效率低(因為系統兼容性的問題,非對齊訪問也可以實現)
10、數據類型和內存的關系
數據類型是用來定義變量的,變量要存儲、運算在內存中,所以內存就必須語相應的數據類型相匹配,否則就會造成效率低下或者不工作
int ×××(整數類型,整的意思就是說和cpu本身的數據位寬(32位或64位)是一樣的)
C語言的數據類型決定一個內存單元的長度和解析方法
類型只是對后面符號或者數字(代表的內存地址)所表征的內存長度規定和解析方法規定而已
指針全名是指針變量,實質上和普通變量沒有任何區別(包括內存分配)
11、內存管理之結構體
數據結構就是研究數據如何組織(在內存中分布)和加工的學問
最簡單的數據結構就是數組(可以一次定義多個數據類型相同,意義相關的變量); //int a[10];
數組的優點:數組比較簡單,可以隨機訪問,訪問時用下標
數組的缺點:數組內所有元素的類型必須相同,且在定義時數組大小就確定,而且不能改變(沒有伸縮性,靈活性差)
而在結構體中可以定義數據類型不同的變量
struct number { int age; char name[20]; double high; };
結構體可以說是數組的升級版;如果結構體中的數據類型全都相同就可以用數組來代替;
結構體內嵌指針可以實現面向對象;
總的來說C語言是面向程序的,但是C語言寫出的linux系統是面向對象的
struct s { int age; //普通變量 void (*pFunc)(void); //函數指針,指向 void func(void) 這類的函數 };
使用這樣的結構體就可以實現面向對象
12、內存管理之棧
什么是棧:棧是一種數據結構,C語言中用棧來存儲局部變量;棧是用來管理內存的
棧:先進后出;入口即出口,有一個口是堵死的,所以先進去的必須后出來
隊列:先進先出;入口和出口是分開的,必須從入口進,從出口出,所以先進去的先出來
棧內存是反復使用的,上次用完的值沒有清零,所以定義局部變量時需要顯式初始化,如果沒有顯式初始化,那么值就是隨機的。
13、復雜數據結構
鏈表:最常用也是最重要的(在嵌入式開發領域)
14、位操作運算
運算種類和運算符:
位與:符號 a&b 全一為一,有零為零 用于對關心位清零(和零作位與)
位或:符號 a|b 全零為零,有一為一 用于對關心位置位(置一,和一作位或)
位異或:符號a^b 相同為零,不同為一 用于對關心位取反(和一作異或)
位取反:符號 ~a 一變零,零變一
位左移:符號a<<
位右移:符號a>> 對于有符號數,右移時左側補符號位(如果正數就補0,負數就補1,叫算術移位)
15、邏輯操作運算
在C語言中,只有0為假,其他的全都是真
邏輯與:符號 a&&b 有假為假,全真為真
邏輯或:符號 a||b 有真為真,全假為假
邏輯取反:符號 !a 真變假,假變真
16、指針是C語言的精髓
指針變量和普通變量沒有任何本質區別
標準用法: int a = 10, b = 0; int *p; p = &a; b = *p; //結果b = 10
16、野指針問題
野指針就是指定義后沒有初始化或者賦值的指針
野指針指向的位置是隨機的,是不可預知的,在運行時容易觸發段錯誤(Sgmentation fault)
總結:指針變量和普通局部變量一樣,都是存儲在棧上,都需要在定義時,進行初始化,否則值就是隨機的
17、如何避免野指針問題
一般注意以下四點就可以避免野指針問題
第一點:在定義指針變量時就初始化為NULL
第二點:在解引用前判斷指針是否指向NULL(指向則不執行解引用,不指向則可以放心解引用)
即 if(NULL != p);
第三點:在解引用完成后,重新把指針賦值為NULL
第四點:在解引用前確保指針指向一個確定的內存地址(需要程序員自己把握)
NULL的實質就是數字0,0地址是不可訪問的
18、const關鍵字和指針結合
const和指針常見的有四種方式:
第一種:int const *p; //p是一個指針,指向一個int型數據,p所指向的是個常量
第二種:const int *p; //p是一個指針,指向一個int型數據,p所指向的是個常量
第三種:int *const p; //p是一個指針,指向一個int型數據,p本身是常量,指向的是變量
第四種:const int *const p; //p是一個指針,指向一個int型數據,p本身是常量,指向的也是常量
關于指針變量,一共涉及到兩個變量,一個是指針變量本身(p),一個是指針所指向的那個變量(*p),而一個const關鍵字只能修飾一個變量。
19、深入學習數組
從內存角度看,數組就是一次定義多個變量,而且在內存中的存儲單元的內存地址是依次連續的
從編譯器角度看,數組數組變量本質上和普通變量,指針變量沒有區別;變量的本質就是一個地址,編譯器把地址(在編譯器中表現為具體的數值)和變量名綁定,變量類型決定了這個地址的延續長度
搞清楚:變量、變量名、變量類型的三個概念的含義和區別
//左值和右值:賦值運算符左邊的就是左值,右邊的就是右值,賦值就是把右值里面的東西給左值;所以右值里面必須有東西(如常量,變量),左值必須能接收東西(如變量)
20、指針和數組的天生關系
數組就是內存地址連續的、類型相同(也就是大小相同)的一連串元素(變量)。這就決定了數組天生就適合使用指針進行訪問,數組訪問有兩種,一種是通過數組下標進行訪問(也就是 a[0];);
一種是通過指針進行訪問(也就是 *(a+2);)。
編譯器實質都是通過指針訪問數組,數組下標訪問是C語言提供給編程者的一種方便方法。
定義一個數組 int a[6];
a 表示數組首元素首地址,類型是int *類型,意義和數值等同于&a[0],兩者可以相互替換。
&a 表示整個數組的首地址,類型是數組指針。
指針變量 +1,表示指向數組的下一個元素,而不是真的數值+1;也就是加1*sizeof(數據類型);
在32位系統中,所有的指針變量所占的內存空間都是4字節
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。