什麼是指針
指針是一種數據類型(整數),這種類型定義出的變量叫指針變量(簡稱指針)。
內存的每個字節都有一個編號,指針變量中存儲的就是這種整數。
1bit 最小的可用單位,能存儲1或0
1byte = 8bit
1kb = 1024byte
1mb = 1024kb
1gb = 1024mb
1tb = 1024gb
1pb = 1024tb
爲什麼使用指針
-
堆內存不能與標識符(變量名)建立聯繫,必須與指針配合才能使用堆內存
-
優化參數的傳遞效率,函數的傳參是值內存(內存拷貝),如果值傳遞變量的地址(4byte),可以達到傳參的目的
-
函數之間空間命名相互獨立,當需要共享變量時只能通過全局變量(不宜過多使用),不傳遞變量地址也能達到共享變量的目的。
注意:指針具有一定的危險性,不該用的時候不要亂用。
如何使用指針
定義指針變量:
類型* 變量名_p;
-
指針變量與普通變量一樣默認值不確定,一般初始化NULL(空指針)
-
指針變量的用法和普通變量不同,通過名字把指針變與普通變量區分開,以免誤用。
-
不能練習定義指針變量。
-
不能連接定義指針變量
int* p1,p2;// p1指針,p2普通的int類型變量
int *p1,p2;//一個*只能定義出一個指針變量
爲指針變量賦值:
指針變量 = 內存編號
int num;
p = #//把棧內存的地址賦值給指針變量
p = malloc(4);//把堆內存的地址賦值給指針變量
注意:如果指針變量存儲的地址是非法的,則訪問內存是就會出現段錯誤。
通過指針變量訪問內存(解引用):
*指針變量
* 間接訪問運算符,是一個單目運算符,間接訪問指針所指向的對象。*運算符的操作對象必須是指針(地址)。
注意:*有兩種含義,定義指針變量時*表示的是變量的身份,其它情況下表示對指針進行解引用。
int num = 10;
int* p = #
// *p <-> num 是等價的
pinrtf %p 可以顯示指針的值
使用指針要注意的問題
空指針:
指針變量的值爲NULL,我們把這種指針稱爲空指針。空指針也是一種錯誤標誌,當一個函數的返回值爲NULL時表示函數執行錯誤
#include <stdio.h>
#include <stdlib.h>
int main(){
int* p = malloc(~0); //取到32個1,地址過大;
print("%p\n",p);
}
//輸出爲nil;
注意:對空指針解引用會引發段錯誤,在大多數情況下NULL就是0地址,而0地址存儲的是系統復位時的一些數據因此對空指針引用會引發段錯誤。
-
如何杜絕空指針導致的段錯誤?
對來歷不明的指針(函數參數)進行解引用時要先判斷是否爲NULL。
野指針:
指針變量中存儲的值是不確定的。
使用野指針的後果:一切正常、段錯誤、髒數據。
注意:使用野指針不一定會出錯,但野指針危害比空指針更嚴重,因爲野指針無法通過條件判斷出(只能對代碼進行分析)。
-
如何避免野指針所造成的錯誤?
所有的野指針都是人爲製造出來的,不製造野指針也就不會有野指針。
-
定義指針一定要初始化,如果不知道什麼值就給個NULL。
-
函數不返回局部、塊變量的地址。
例:
#include <stdio.h>
int* func(void){
int num = 100;
int*p = #
return p; //不應該返回局部變量的值
}
int test(void){
int arr[10] = {1,2,3,4,5,6,7,8,9,};
}
int main(){
int* p = func();
printf("%d\n",*p);
test();
printf("%d\n",*p);
}
- 當一塊堆內存被釋放後,只想它的指針應該立即置空。
指針的運算:
注意:指針變量中存儲的就是代表內存編號的整數
整數能使用的運算符指針變量理論上來說都應該可以使用,但不是所有的運算都有意義。
有意義的運算:
-
指針+整數 = 指針+類型寬度×整數
指針-整數 = 指針-類型寬度×整數
(指針加減一個整數相當於前後移動) -
指針-指針 = (指針-指針)/類型寬度
(指針減指針可以計算出利用指針之間相隔多少個元素) -
指針 == 、 != 、>、<、>=、<=指針
(判斷出指針的前後位置關係)
指針與數組
數組名就是一種特殊的常指針它與數組元素的首地址是對應關係(指針是指向關係)
因爲數組名就是指針所有可以使用指針的語法,而指針野可以使用數組的語法。
*(p+1) <=> p[i];
arr 與 &arr的區別:
arr的類型:int*
&arr類型:int (*arr)[5]
數組指針:專門用來指向數組的指針
指針數組:由指針變量組成的數組,如int* arr[5];
指針與const
-
const int* p;保護的是指針變量所指向的內存,不能通過解引用來修改內存中的數據,解決提高效率帶來的安全隱患。
-
int const * p; 同上
-
int* const p;保護的是指針變量不被顯示修改,可以防止變成野指針
-
const int* const p;既保護指針變量又保護指針變量所指向的內存。
-
int const * const p;同上
#include <stdio.h>
//解決提高傳遞效率帶的安全隱患
void func(const double* p)
{
*p = 3.14; //error
}
int main()
{
const int num = 10;
const int* p = NULL;
*p = num; //error
int* const p1 = NULL;
p1 = # //error
double f = 0;
func(&f);
}