陣列 字串 結構體 共用體 列舉

2022-09-07 00:54:14 字數 4351 閱讀 3399

(1)void * 是乙個指標型別,malloc返回的是乙個void *型別的指標,實質上malloc返回的是堆管理器分配給我本次申請的記憶體空間的首位址(malloc 返回的值其實是乙個數字,這個數字表示乙個記憶體位址)。為什麼要使用void *作為型別?主要原因是malloc幫我們分配記憶體是只分配了記憶體空間,至於這段空間將來被用來儲存什麼型別的元素malloc是不關心的,由程式自己來決定。

(2)什麼是void型別。早起被翻譯成空型。這個翻譯非常不好,會誤導人。void型別不表示沒有型別,而表示萬能型別。void的意思是這個資料型別當前是不確定的,在需要的時候可以再去指定它的具體型別。void *型別是乙個指標型別,這個指標本身佔4個位元組,但是指標指向的型別是不確定的。換句話說,指標在需要的時候可以被強制轉化為任何一種確定型別的指標,也就是說這個指標可以指向任何型別的指標。

(4)malloc申請的記憶體使用完後,要注意記憶體釋放free。free(p);會告訴堆管理器這段記憶體已經使用完,堆管理器可以**了。堆管理器**了這段記憶體後,這段記憶體當前程序就不應該再使用了。因為釋放後,堆管理器就可能吧這段記憶體分配給別的程序,所以你就不能再使用了。

(5)再呼叫free歸還這段記憶體之前,指向這段記憶體的指標p一定不能丟(也就是p不能另外賦值)。因為p一旦丟失這段malloc來的記憶體就永遠的丟失了(記憶體洩露)直到當前程式結束時,作業系統才會**這段記憶體。

編譯器在編譯程式的時候,將程式中的所有的元素分成了一些組成部分,各部分構成了乙個段。所以說段是可執行程式的組成部分。

注意區分:資料段(.data)和bss段的區別和聯絡:二者本來沒有本質區別,都是用來存放c語言中的全域性變數的。區別在於我們把顯示的初始化為非0 的全域性變數存在.data段,而把顯式初始化為0 或者並未顯式初始化的全域性變數存在.bss段

注意:指向字串的指標和字串本身是分開的兩個東西。

(1)char *p = "linux";

(2)strlen剛好用來計算字串長度

總結對比:字元陣列和字串有本質區別。字元陣列本身是陣列,陣列自身自帶記憶體空間,可以用來存東西(所以陣列類似於容器),而字串本身是指標,本身永遠佔4位元組還不能用來存有效資料,所以只能把有效資料存到別的地方,然後把位址存在p。也就是字元陣列自己存那些字元,而字串需要額外的記憶體來存那些字元,字串本身只存真正的那些字元所在的記憶體空間的首位址。

(1)c語言中的2中型別:原生型別和自定義型別

(1)結構體定義時需要先先定義結構體型別再用型別來定義變數

(2)也可以在定義結構體型別的同時定義變數

(1)結構體可以認為是從陣列發展而來的。其實陣列和結構體都算作資料結構的範疇,陣列就是最簡單的資料結構、結構體比陣列更複雜一些,鍊錶、雜湊表之類的比結構體又複雜一些,二叉樹、圖等又更複雜一些。

(2)陣列由2個明顯的缺陷:第乙個是定義時必須明確給出大小,且這個大小在以後不能更改。第二個是陣列要求所有的元素型別必須一致更複雜的資料結構中就致力於解決這兩個缺陷

(3)結構體用於解決陣列的第二個缺陷,可以將結構體理解成乙個其中元素型別可以不同的陣列。結構體完全可以取代陣列,只是在陣列可用的範圍內,陣列更簡單

陣列中元素的訪問方式:表面上有兩種方式(陣列下標方式和指標方式),實質上都是指標方式訪問

結構體變數中的元素訪問方式:只有一種,用.或者->方式訪問(.和->訪問結構體元素的實質是一樣的,只是c語言規定了用結構體變數來訪問就用.而結構體指標的方式訪問就用->,實際上高階語言已經不分了,都用.)

結構體的訪問訪問方式有點類似於陣列下標方式

思考:結構體變數的點號或者->訪問元素的實質是什麼?其實本質上是指標來訪問的。

(1)編譯器本身可以設定記憶體對齊規則,有以下的規則需要記住,

第乙個:32位編譯器,一般編譯器預設對齊方式是4位元組對齊

(1)#pragma是用來指揮編譯器,或者說設定編譯器的對齊方式的。編譯器預設的對齊方式是4,但是有時候我們不希望對齊方式是4位元組,而是希望設定為別的(譬如設定為1,也可能希望是8,甚至可能是128位元組)

(2)常用的設定編譯器編譯器對齊命令有2種:第一種是#pragma pack( ),這種就是設定編譯器1位元組對齊(有些人喜歡講:編譯器 不對齊訪問,還有些講取消編譯器對齊訪問);第二種是#pragma pack (4),這個括號中的數字就表示我們希望有多少位元組對齊。

(3)我們需要#pragma pack(n)開頭,以#pragma pack()結尾,定義乙個區間,這個區間內的對去引數就是n

#include#pragma pack(1)

struct

student

;#pragma pack()

int main(void

)

結果:sizeof(s1) = 7.

(1)_attribute_((packed))使用時直接放在要進行記憶體對齊的型別定義的後面,然後它起作用的範圍只有加了這個東西的這乙個型別。packed的作用就是取消對齊訪問。

(2)_attribute_((aligned(n)))使用時直接放在要進行記憶體對齊的型別定義的後面,然後它起作用的範圍只有加了這個東西的這乙個型別。他的作用是讓整個結構體變數整體進行n位元組對齊(注意是結構體變數整體n位元組對齊,而不是結構體內各元素也要n位元組對齊)

#includestruct

mystruct1

__attribute__((packed));

int main(void

)結果:

sizeof(s1) = 7.

由結構體指標而訪問各元素的原理

學習思路:第第一步先學會用offsetof巨集,第二步再去理解這個巨集

(type  *)0 這是乙個強制型別轉換,把0位址強制型別轉換為乙個指標,且這個指標指向乙個type 型別的結構體變數,實際上這個結構體變數可能不存在,但是只要不去解引用就不會出錯。

((type  *)0)->member  (type *)0是乙個type 型別的結構體變數指標,通過指標來訪問結構體變數的member元素。

&((type  *)0)->member   等效於&(((type  *)0)->member),意義就是得到member元素的位址,但是因為我們整個結構體變數的首位址是0 ,所以該位址減去0值不變,但是含義卻就是偏移量

#includestruct

mystruct;//

type是結構體型別,而member是結構體中乙個元素名

//這個巨集返回的是member元素相對於整個結構體的偏移量

#define offsetof(type,member) ((int)&((type *)0)->member)

int main(void

)結果:offsetofa = 0

.offsetofb = 4

.offsetofc = 8.

#includestruct

mystruct

;#define container_of(ptr, type, member) ()

int main(void

)

逆推:知道結構體變數中某個元素的指標,如何逆推得到結構體的指標。

#include//

//union myunion;//

如果是小端模式則返回1,如果是大端模式則返回0

//union方式

int is_little_endlian(void)//

指標方式

int is_little_endlian2(void

)int main(void

)

else

printf(

"大端模式.\n");

return0;

}

看似可行實測不行的測試大小端方式:

(1)位與運算。

結論:位與無法測試機器的大小端模式。(表現就是大端機器和小端機器的&運算後的值相同)

理論分析:位與運算是編譯器提供運算,這個運算是高於記憶體層次的(或者說位與運算在二進位制層次具有可移植性,也就是說&的時候一定是高位元組&高位元組,低位元組&低位元組)

#includeint main(void

)這種方式是不對的。

(2)移位

結論:移位的方式也無法測試機器的大小端

理論分析:原因和位與運算子不能測試一樣,因為c語言對運算子的級別是高於二進位制層次的。右移運算永遠是將低位元組移除,而和二進位制儲存時這個低位元組是高位還是低位無關

(3)強制型別轉換

結論:這種也是不可以的。

理論分析:同上

總結:巨集定義先出現用來解決符號常量的問題,後來發現有時候彼此之間的符號常量之間有關聯(多選一的關係),用巨集定義雖然可以做,但是不太好,於是發明了列舉。

看文件

5 陣列 字串 結構體 共用體 列舉

堆的使用 malloc的一些細節 有些特殊資料段會被放到 段 總結 c語言沒有原生字串型別 c語言使用指標來管理字串 c語言中字串的本質 注意 儲存多個字元的2種方式 字串和字元陣列 字元陣列初始化與sizeof strlen 字串初始化與sizeof strlen 字元陣列與字串的本質差異 記憶體...

第五章 陣列 字串 結構體 共用體 列舉

0x12345678 在記憶體byte0,byte1,byte2,byte3中的存放方法大端模式 0x12 0x34 byte0 byte1 0x560x78 byte2 byte3 2 通過程式確定大小端 通過共用體 定義共用體 union strs1 判斷 int func void int m...

結構體 共用體 列舉

結構體 共用體 列舉 分析 首先宣告的結構體元素year的位址是最低的 0012ff74 而最後宣告的day的位址是最高的 0012ff7c 而我們又知道在棧中宣告變數的時候,位址是從高到低的分配的.因此,切記在結構體中宣告的變數與直接在外面宣告是不一樣的.在結構體中,最先宣告的變數放在最低位的.另...