理解指標才能真正的算c語言入門。也許是我大學期間太關注前端ue,也許是當初開始學c語言的時候沒怎麼認真;直到畢業後的某一天我才「懂」指標,才算理解c語言的獨特。如果有初學c語言的同行對指標有困惑,希望我這淺薄的認識能幫助你。
指標在原英文中為pointer,個人覺得翻譯過來後針的含義不如指的含義好理解,pointer還可翻譯為指示器,如果是初學者的話,筆者建議在學習過程中多琢磨指的含義。
指標可以說是一種特殊的資料型別,前面的記憶體篇介紹過,程式執行時的資料基本上都儲存在記憶體中,記憶體中用數字標識不同資料,在各種計算機語言中,把這種數字標識成為位址。計算機系統並不認識c語言,程式編譯就是把c語言翻譯為作業系統可識別的語言。比如「我」翻譯英文為i,翻譯過後已經看不到「我」這個字了。我們在程式中定義了整型變數i,賦值為5,那麼經過編譯執行,作業系統同樣看不到i,對作業系統而言,i被翻譯為某個記憶體位址上的整型值。
要使用指標首先要認識兩個符號:乙個是'&',可以在程式中取得變數的記憶體位址;乙個是'*','*'在定義變數的時候標明該變數為指標,在已定義的變數前面使用的時候,表示獲取(設定)該指標變數所在記憶體位址中儲存的值。
1 #include 23int main(int arg, char *args)
4
1 srci:7665592,74f7b8
2 *srci:5
3 i:7
筆者認為理解指標重點就在理解'*'這個符號,這裡強調下,在定義變數時,'*'表示後面定義的變數是指標型別,在已定義的指標前'*'表示獲取(設定)後面變數儲存的記憶體位址中實際儲存的值,專業點說就是獲取(設定)後面變數所指向的值。下面列舉乙個未理解'*'含義時會犯的錯誤:
1 #include 23int main(int arg, char * args)
4
上述**編譯執行都沒有報錯,本意是想把src儲存的位址改為變數j的記憶體位址,而實際卻變成設定變數i的值,這就是對'*'錯誤的理解後果。這段**還說明了一件事情:第7行位址可以賦值給整型變數,這也證實了前面的話:記憶體中用數字標識不同資料,該資料標識就是記憶體位址。
下面再通過**說明const指標
1 #include 2 #include 34int main(int arg, char *args)
5
之前只使用了整型作為示例,而實際上'&'可以用來取得所有資料型別的位址,如char,float,double等等;用'*'定義指標的時候,同樣可以定義出 char *,float *,double *這些指標型別,不同的指標型別在讀取資料的時候的不同點就在於其解釋位址的方式不同。如int *型別,定義後使用*取值,會從int *所代表的位址開始,取sizeof(int)位位址的資料,然後以int的方式解析出資料,使用其他資料型別以此類推。
指標型別可以儲存所有資料型別的位址,那麼指標是否可以儲存指標的位址呢?確實可以,有關多級指標的問題,這裡舉個可能不是很恰當的例子:在班級課堂上你需要一支筆,於是你向你同桌要,同桌說ta後面的人有筆,然後你再向同桌後面的人要,同桌後面的人說ta旁邊的人有,於是你再向同桌後面旁邊的人要......如果需要的話,這個場景可以迴圈下去。多級指標大概就是這麼個意思,你讀取這個位址發現裡面還是個位址,於是再讀裡面的位址......當然現實中遇到這種借筆借半天的問題肯定很坑,但是對於計算機指標來說,只是多乙個符號的問題。下面做個簡單示例:
1 #include 23int main(int arg, char *args)
4
執行結果如下:
*src:6**srcsrc:6
***srcsrcsrc:6i:8
i:10
i:12
說了這麼多,指標在實際使用中有何作用?首先,你發現指標讀取的都是作業系統記憶體位址,所有程式的資料都存在系統記憶體中,如果能讀取設定他們所有的值,那麼也就可以通過記憶體位址修改系統其他程式的資料,這就是修改器、外掛程式的部分原理,實際想這麼做還要考慮如何找位址,如何通過系統的記憶體保護(注入)。
1 #include 23int changearr(int *arr)48
9int main(int arg, char *args)10;
13 printf("
*array:%d\n
", *array); //
可以直接通過*取得首元素值
1415
//正常方式遍歷陣列
16 printf("
array:");
17for (i = 0; i < sizeof(array) / sizeof(int); i++)
1821 printf("\n"
);22
//指標方式遍歷陣列
23 printf("
array:");
24for (i = 0; i < sizeof(array) / sizeof(int); i++)
2528 printf("\n"
);29
30//
通過帶指標引數的函式對陣列值進行修改
31changearr(array);
32//
指標方式遍歷陣列
33 printf("
after change\narray:");
34for (i = 0; i < sizeof(array) / sizeof(int); i++)
3538 printf("\n"
);39
getchar();
40return0;
41 }
執行結果如下:
1 *array:12 array: 123
4563 array: 123
4564
after change
5 array: 20403
456
上面所用示例基本都是棧上的記憶體空間,在直接定義變數的時候會申請棧上的記憶體空間,實際程式所能申請使用的棧空間很小,所以在處理大一些的資料的時候,應手動申請堆上的記憶體。在c語言中,手動申請需要了解幾個c語言函式,這裡先列舉它們的函式名:malloc,calloc,realloc,free,_alloca。
這裡先以malloc和free兩個函式做個示例(對資料型別記憶體空間有疑問的可以看看之前的記憶體的隨筆):
1 #include 2 #include 34int main(int arg, char *args)
515 *a = 5
;16 printf("
%d,%x\n
", *a, a); //
分別列印出指標a位址指向的值及a位址
1718
if (a !=null)
1925
26 getchar(); //
暫停作用
27return0;
28 }
執行結果為:
5,1099538
其他記憶體分配相關函式用的並不是很多,這裡只做簡介記錄
realloc:對已分配記憶體的指標進行重新分配,同樣需要free手動釋放記憶體,以應用舉例:原來分配的記憶體可能過小,這時可用realloc,申請一片新的記憶體空間,然後將之前的記憶體空間複製過去,如果新空間比原空間小會導致資料丟失。可用realloc做c語言中的動態陣列(可變容量)
原型:void *realloc(void *mem_address, unsigned int newsize);
calloc:申請兩個數乘積大小的空間,同樣需要free手動釋放記憶體。比如我想申請乙個含6個元素的整型陣列空間:calloc(6,sizeof(int));
原型:void *calloc(size_t n, size_t size);
_alloca:在棧上申請空間,用完自動釋放
原型:void * __cdecl _alloca(size_t);
一般來說,乙個人能運用函式指標說明其水平正從入門走向熟練,筆者自己用的基本都是在一些系統呼叫下才會用到,一般用於**,這裡就做個引子,簡單說說其定義及使用。請看下圖中**及注釋:
1 #include 23void
func()47
8float addfloat(float a, floatb)9
1213
14int main(int arg, char *args)
15
執行結果如下:
1hello func pointer
23.0+4.0=7.0
我對於指標的部分理解及執行暫時就先到這裡,如果有問題還請大家指出,謝謝!
深入理解C C 指標
c語言所有複雜的指標宣告,都是由各種宣告巢狀構成的。如何解讀複雜指標宣告呢?右左法則是乙個既著名又常用的方法。不過,右左法則其實並不是c標 準裡面的內容,它是從c標準的宣告規定中歸納出來的方法。c標準的宣告規則,是用來解決如何建立宣告的,而右左法則是用來解決如何辯識乙個宣告的,兩者可 以說是相反的。...
指標學習心得與理解
在c語言的學習過程中,指標是相當重要的一部分,學好指針對c的學習有很重要的意義。指標和記憶體 如果說記憶體相當於街道,那麼位址就相當於位於街道中房子的房號。乙個位元組 8bit 包含乙個位址。記憶體中每乙個位置都包含乙個獨一無二的位址標識,而每乙個位置都包含乙個值。p分別作為左值和右值時具有不同的意...
指標學習心得與理解
在c語言的學習過程中,指標是相當重要的一部分,學好指針對c的學習有很重要的意義。指標和記憶體 如果說記憶體相當於街道,那麼位址就相當於位於街道中房子的房號。乙個位元組 8bit 包含乙個位址。記憶體中每乙個位置都包含乙個獨一無二的位址標識,而每乙個位置都包含乙個值。p分別作為左值和右值時具有不同的意...