詳解C說話中的內存四區模子及構造體對內存的應用。本站提示廣大學習愛好者:(詳解C說話中的內存四區模子及構造體對內存的應用)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解C說話中的內存四區模子及構造體對內存的應用正文
內存四區
1、代碼區
代碼區code,法式被操作體系加載到內存的時刻,一切的可履行代碼都加載到代碼區,也叫代碼段,這塊內存是弗成以在運轉時代修正的。
2、靜態區
一切的全局變量和法式中的靜態變量都存儲到靜態區。
3、棧區
棧stack是一種先輩後出的內存構造,一切的主動變量,函數的形參都是由編譯器主動放出棧中,當一個主動變量超越其感化域時,主動從棧中彈出。關於主動變量,甚麼時刻入棧,甚麼時刻出棧,是不須要法式掌握的,由C說話編譯器。完成棧不會很年夜,普通都是以K為單元的。
當棧空間以滿,但還往棧內存壓變量,這個就叫棧。溢出關於一個32位操作體系,最年夜治理治理4G內存,個中1G是給操作體系本身用的,剩下的3G都是給用戶法式,一個用戶法式實際上可使用3G的內存空間。
留意:C說話中函數參數入棧的次序是從右往左。
4、堆區
堆heap和棧一樣,也是一種在法式運轉進程中可以隨時修正的內存區域,但沒有棧那樣先輩後出的次序。堆是一個年夜容器,它的容量要遠弘遠於棧,然則在C說話中,堆內存空間的請求和釋放須要手動經由過程代碼來完成。
代碼示例:
#include <stdio.h> int c = 0; // 靜態區 void test(int a, int b) // 形參a,b都在棧區 { printf("%d, %d\n", &a, &b); } int *geta() // 函數的前往值是一個指針 { int a = 100; // 棧區 return &a; } // int a的感化域就是這個{} int main() { int *p = geta(); // 這裡獲得一個暫時棧變量的地址,這個地址在函數geta挪用完成以後曾經有效了 *p = 100; printf("%d\n", *p); static int d = 0; // 靜態區 int a = 0; // 棧區 int b = 0; printf("%d, %d, %d, %d, %d\n", &a, &b, &c, &d, main); test(a, b); return 0; } /* 輸入成果 100 2619740, 2619728, 9404720, 9404724, 9376059 2619512, 2619516 */
堆應用留意事項:
#include <stdio.h> #include <stdlib.h> int *geta() // 毛病,不克不及將一個棧變量的地址經由過程函數的前往值前往 { int a = 0; return &a; } int *geta1() // 可以經由過程函數的前往值前往一個堆地址,但記得,必定要free { int *p = (int *)malloc(sizeof(int)); // 請求了一個堆空間 return p; } int *geta2() // 正當的,然則記住這裡不克不及用free { static int a = 0; // 變量在靜態區,法式運轉進程中一向存在 return &a; } void getHeap(int *p) { printf("p = %p\n", &p); p = (int *)malloc(sizeof(int) * 10); } // getHeap履行完以後,p就消逝了,招致他指向的詳細堆空間的地址編號也隨之消逝了 // 這裡產生了內存洩露 void getHeap1(int **p) { *p = (int *)malloc(sizeof(int) * 10); } // 這裡的操作就是准確的 int main() { int *p = NULL; printf("p = %p\n", &p); getHeap(p); // 實參沒有任何轉變 getHeap1(&p); // 獲得了堆內存的地址 printf("p = %d\n", p); p[0] = 1; p[1] = 2; printf("p[0] = %d, p[1] = %d\n", p[0], p[1]); free(p); return 0; }
構造體內存對齊形式
構造體內存對齊形式各類情形詳解
#include <stdio.h> struct A { int a; // 此時構造體占用4個字節 char b; // 此時構造體占用8個字節 char c; // 照樣8個字節 char d; // 照樣8個字節 char e; // 照樣8個字節 char f; // 如今是12個字節 }; struct B { char a; // 1個字節 char b; // 2個字節 char c; // 3個字節 }; struct c { char name[10]; // 10個字節 char a; // 11個字節 // 關於char型數組來講,會把數組每一個元素看成一個char類型 }; struct d { int name[10]; // 40個字節 char a; // 44個字節 char b; // 44個字節 }; struct e { char a; // 1個字節 int b; // 8個字節 char c; // 12個字節 // 這類寫法內存的消費比擬A就會變年夜 }; struct f { char a; // 1 short b; // 4留意這裡short占用的是剩下三個字節中的後兩個 // 內存對齊老是以2的倍數對齊 char c; // 所以此時是6 int d; // 12 short e; // 16 char f; // 16 };
構造體變相完成數組賦值
struct name { char array[10]; }; int main() { char name1[10] = "name1"; char name2[20] = "name2"; name1 = name2; // 這裡是失足的,不克不及在數組之間停止賦值 struct name a1 = { "hello" }; struct name a2 = { 0 }; a2 = a1; // 這裡經由過程構造體可以賦值的特征變相完成了數組的賦值 return 0; }
構造體內存洩露
#include <stdio.h> #include <stdlib.h> union A { char a; char *b; // 結合體的指針成員要特殊留意 }; int main() { A a; a.b = (char *)malloc(10); // b指向了一個堆的地址 // 假如結合體中有指針成員,那末必定要應用完這個指針,而且free指針以後能力應用其他成員 a.a = 10; // b的值同樣成了10了 free(b); // 此時釋放b是毛病的,由於在下面一行對a停止賦值時,曾經將b的值更改了,這裡形成了內存洩露 return 0; }