詳解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;
}