一、c語言中的記憶體管理
c語言程式在編譯後需要載入記憶體中才能開始執行。記憶體中對於資料的劃分不是隨機的,而是根據這個資料的性質分段進行劃分的。某段記憶體區域只會儲存相應的資料。
具體來說,c語言對於記憶體空間的劃分可以分為以下幾個區域:
1)**區:這段區域主要用來儲存編譯後的函式體的二進位制**,以及會用到的字串常量。該區域是唯讀的。示例:程式中列舉了常見的資料及資料所在的儲存區域。2)資料區:這個區域主要儲存已初始化的全域性變數、靜態變數、一般常量。
3)bss區:這個區域主要儲存未初始化的全域性變數、靜態變數。
4)堆區:由程式設計師手動申請、手動釋放**。若程式設計師不手動釋放,則在程式結束後由作業系統**。所對應的函式是malloc()、calloc()、free()等。
5)棧區:由系統自動分配、自動釋放**,存放函式的引數值、區域性變數等。
6)命令列引數區:存放環境變數等,例如main()函式的傳遞的引數值。
其中,堆區與棧區的記憶體是在程式執行時由系統分配的。當該程式需要分配記憶體時才會分配,不需要時不會分配(或者分配後直接**)。而bss區、資料區、**區是在程式執行開始階段就由編譯器分配記憶體,這三個區域的內存在程式執行時會一直存在,不會被臨時**。
char *p1;//全域性變數未初始化區
#include#include#includeint a=0;//全域性變數初始化區
int main()
二、野指標與空指標
1、野指標
指標變數在定義的時候,若未初始化或指向某物件,則該指標所存的位址值並不是空(null),而是乙個隨機值。這時這個指標指向一段未知記憶體,這樣的指標就稱為「野指標」。
野指標產生的原因主要有兩個:
1.定義指標變數時未初始化或之後未指向正確的物件
2.指標釋放後指標未及時置空
示例:
#includeint main()
雖然程式編譯沒有問題,但執行時會報錯:segmentation fault (core dumped)segmentation fault (core dumped):中文翻譯為「段錯誤」。發生段錯誤的原因是程式對記憶體進行了非法操作,系統為了保護記憶體而強制終止了程式的執行。
發生段錯誤的原因很多,主要有:陣列越界、修改唯讀記憶體、操作未知記憶體(操作野指標)等。
野指標無法通過語法檢查而查出錯誤,只能通過程式設計人員的自身素養規避。初學者要十分小心使用指標變數,尤其不要出現野指標。
2、空指標
在c語言中,有巨集定義「null」代表「空」。若指標的值為null,則表示該指標未指向任何記憶體。
int *p = null;//指標置空
初學者要養成良好習慣:若定義指標後暫時不指向任何物件,應該在定義時就把該指標置空防止出現野指標。
我們可以通過判斷語句來判斷乙個指標是否是空指標:
if(p == null)
三、返回指標值的函式(指標函式)
乙個函式既可以返回int型別、char型別等,也可以返回乙個指標型別資料,即返回乙個位址。返回指標值的函式,稱為「指標函式」。
指標函式的定義形式為:
型別名 *函式名(引數列表)
例如:int *a(int x,int y)
char *strcpy(char *s1,const char *s2)
示例:有3個學生,每個學生有4門課成績,存放在乙個二維陣列中。要求使用者輸入學生的序號(1或2或3)之後,能夠輸出這個學生的4門成績。使用指標函式實現。
#includeint *search(int(*p)[4],int n)
int main()
,,};
int n,i;
printf("查詢第幾個學生的成績(1~3)?\n");
scanf("%d",&n);
if(n!=1 && n!=2 && n!=3)
n--;
int *a = search(score,n);
for(i=0;i<4;i++)
printf("\n");
return 0;
}
注意:當指標作為函式的返回值的時候,主調函式需要考慮指標指向的資料是否已經被**。由於被調函式的區域性變數儲存在棧區,因此當被調函式執行完畢後系統會**該段記憶體空間,這樣被調函式內資料就會丟失。例如:
char *mem()
int main()
執行程式會發現我們不會得到"hello world"而是會輸出亂碼。
思考:怎樣修改被調函式,使得主調函式可以輸出"hello world"?
修改一:
char *mem()
int mai
修改二:
char *mem()
int mai
四、指向函式的指標(函式指標)
在程式中定義的函式在編譯時系統也會對函式**分配一段儲存空間,這段儲存空間的起始位址(又稱「入口位址」)稱為這個函式的指標。
那麼我們就可以定義乙個指向這個函式入口位址的指標變數用於儲存這個函式的入口位址,就意味著該指標指向該函式。
1、定義函式指標
函式指標的定義形式為:
《型別名》 (*《指標變數名》)(引數列表)//引數列表只寫形參型別即可,不必寫形參名
注意:函式指標與指標函式的定義主要區別就在於是否用()把函式名括起來,請注意區分。
例如:int (*p)(int,int);
這個指標變數p的型別是int (*)(int,int),表示這是乙個指向有兩個int型引數、返回值為int型的函式的指標。
2、使用函式指標呼叫函式
示例:寫乙個函式,求出2個數中較大值。呼叫函式用函式指標實現。
#includeint max(int x,int y)
int main()
注意:
1.定義了乙個函式指標,但不代表該函式指標可以指向任何型別的函式。示例程式中的指標p只能指向引數是2個int型、返回值是int型的函式。不能指向非這種型別的函式。
2.使用函式指標呼叫函式前,一定要先將該指標變數指向該函式。
3.在給函式指標賦值時,只需函式名即可,千萬不要寫成函式呼叫。
p = max;//正確
p = max(a,b);//錯誤
4.使用函式指標時,只需用*《指標變數名》來代替普通函式呼叫即可。
5.函式指標不能進行算數運算。如p+1、p-1、p++、p--等都是非法的。
練習:寫兩個函式,乙個求2個數中較大值,另乙個求2個數中較小值。使用者選擇1或2,輸入1代表呼叫較大值函式,輸入2代表呼叫較小值函式。呼叫函式用函式指標實現。
答案:
#includeint max(int x,int y)
int min(int x,int y)
return p;
}int main()
{int *a = get_memory(max*sizeof(int));
if(!a)
{printf("申請空間失敗!\n");
return 0;
c語言010 指標
include int main 注意 p前面的型別決定了取位址的能力。如果是int型別的,就說明在32平台下可以取址能力是4個位元組。2 指標的本質就是儲存乙個位址,在32位的系統上,所有程式的記憶體位址都用4個位元組表示,所以不管是什麼型別的指標。指標大小都佔4個位元組。稱之為間接引用,表示根據...
2018 5 1指標c語言
是人類的,人類 肯定是給我隨便用,不然 抽他。include include pragma pack push,1 struct s1 a char ch pragma pack pop static void alloc void static void fill void p static vo...
C語言(九) 指標(3)指標與const
表示一旦得到了某個變數的位址,不能再指向其他變數 int i 0 int const q i q是 const q 20 ok q error表示不能通過指標去修改這個變數 int i 0 int j const int p i const int p 等同於 int const p p 20 er...