前言
眾所周知冕香,C程序員新手和老手的一大差別就在于是否對指針有深刻理解祠肥,能否高效利用指針纸镊。
可以說學(xué)好c指針對于以后的開發(fā)工作至關(guān)重要鸵闪,所以在這里整理出了一系列關(guān)于指針的文章檐晕,
供大家一起學(xué)習(xí)進步。
本期簡要介紹指針蚌讼、指針操作符以及指針如何與內(nèi)存相互作用辟灰。
1.1 指針和內(nèi)存
C程序在編譯后,會以以下三種形式使用內(nèi)存啦逆。
- 靜態(tài)/全局內(nèi)存
靜態(tài)聲明的變量分配在這里伞矩,全局變量也使用這部分內(nèi)存。這些變量在程序開始運行時分配夏志,知道程序終止才消失乃坤。所有函數(shù)都能訪問全局變量,靜態(tài)變量的作用域則局限在定義他們的函數(shù)內(nèi)部沟蔑。 - 自動內(nèi)存
這些變量在函數(shù)內(nèi)部聲明湿诊,并且在函數(shù)被調(diào)用時才創(chuàng)建。它們的作用域局限在函數(shù)內(nèi)部瘦材,而且生命周期局限在函數(shù)的執(zhí)行時間內(nèi)厅须。 - 動態(tài)內(nèi)存
內(nèi)存分配在堆上,可以根據(jù)需要釋放食棕,而且直到釋放才消失朗和。指針引用分配的內(nèi)存,作用域局限于引用內(nèi)存的指針簿晓。
理解這些內(nèi)存類型可以更好地理解指針眶拉。大部分指針用來操作內(nèi)存中的數(shù)據(jù),因此理解內(nèi)存的分布和組織方式有助于我們弄清楚指針如何操作內(nèi)存憔儿。
指針變量包含內(nèi)存中別的變量忆植、對象或函數(shù)的地址。對象就是內(nèi)存分配函數(shù)(比如malloc)分配的內(nèi)存谒臼。指針通常根據(jù)所指的數(shù)據(jù)類型來聲明朝刊。對象可以是任何C數(shù)據(jù)類型,如整數(shù)蜈缤、字符拾氓、字符串或結(jié)構(gòu)體。然而劫樟,指針本身并沒有包含所引用數(shù)據(jù)的類型信息痪枫,指針只包含地址织堂。
1.2 指針幾大使用鐵律
鐵律1:指針是一種數(shù)據(jù)類型
1) 指針是一種數(shù)據(jù)類型也是一個變量,占有內(nèi)存空間,用來保存內(nèi)存地址。
a) 說它是一種數(shù)據(jù)類型奶陈,那他究竟是什么類型呢
指針的數(shù)據(jù)類型是指它所指向內(nèi)存空間的數(shù)據(jù)類型
// 測試指針變量占有內(nèi)存空間大小:注意32/64位之分
int a = 10;
int *p = &a;
size_t size = sizeof(p);
printf("%zu\n", size);// 8
printf("%p\n", p);// 0x7fff5fbff7c4
2) *p操作內(nèi)存
在指針聲明時易阳,*號表示所聲明的變量為指針
在指針使用時,*號表示操作指針?biāo)赶虻膬?nèi)存空間中的值
*p相當(dāng)于通過地址(p變量的值)找到一塊內(nèi)存吃粒;然后操作內(nèi)存
*p放在等號的左邊賦值(給內(nèi)存賦值)
*p放在等號的右邊取值(從內(nèi)存獲取值)
3) 指針變量和它指向的內(nèi)存塊是兩個不同的概念
含義1 給p賦值p = 0x1111; 只會改變指針變量值潦俺,不會改變所指的內(nèi)容;p += 1;p++
含義2 給*p賦值*p = 'a'; 不會改變指針變量的值徐勃,只會改變所指的內(nèi)存塊的值
含義3 =左邊*p 表示 給內(nèi)存賦值事示, =右邊*p 表示取值 含義不同切結(jié)!
含義4 =左邊char *p
含義5 保證所指的內(nèi)存塊能修改
4) 指針是一種數(shù)據(jù)類型僻肖,是指它指向的內(nèi)存空間的數(shù)據(jù)類型
含義1:指針步長(p++)肖爵,根據(jù)所致內(nèi)存空間的數(shù)據(jù)類型來確定
p++=?(unsigned char )p+sizeof(a);
結(jié)論:指針的步長,根據(jù)所指內(nèi)存空間類型來定臀脏。
注意: 不斷的給指針變量賦值劝堪,就是不斷的改變指針變量(和所指向內(nèi)存空間沒有任何關(guān)系)。
鐵律2: 間接賦值(*p)是指針存在的最大意義
1) 兩碼事:指針變量和它指向的內(nèi)存塊變量
2) 條件反射:指針指向某個變量揉稚,就是把某個變量地址傳給指針
3) *p間接賦值成立條件:3個條件
a) 2個變量(通常一個實參秒啦,一個形參)
b) 建立關(guān)系,實參取地址賦給形參指針
c) *p形參去間接修改實參的值
4)引申:函數(shù)調(diào)用時,用n指針(形參)改變n-1指針(實參)的值搀玖。
//改變0級指針(int iNum = 1)的值有2種方式
//改變1級指針(eg char *p = 0x1111 )的值余境,有2種方式
//改變2級指針的(eg char **pp1 = 0x1111 )的值,有2種方式
//函數(shù)調(diào)用時灌诅,形參傳給實參芳来,用實參取地址,傳給形參猜拾,在被調(diào)用函數(shù)里面用*p绣张,來改變實參,把運算結(jié)果傳出來关带。
//指針作為函數(shù)參數(shù)的精髓。
鐵律3: 間接賦值(*p)是指針存在的最大意義
1) 主調(diào)函數(shù) 被調(diào)函數(shù)
a) 主調(diào)函數(shù)可把堆區(qū)沼撕、棧區(qū)宋雏、全局?jǐn)?shù)據(jù)內(nèi)存地址傳給被調(diào)用函數(shù)
b) 被調(diào)用函數(shù)只能返回堆區(qū)、全局?jǐn)?shù)據(jù)
2) 內(nèi)存分配方式
a) 指針做函數(shù)參數(shù)务豺,是有輸入和輸出特性的磨总。
鐵律4:應(yīng)用指針必須和函數(shù)調(diào)用相結(jié)合(指針做函數(shù)參數(shù))
鐵律5:一級指針典型用法(指針做函數(shù)參數(shù))
// 一級指針做輸入
int showbuf(char *p)
int showArray(int *array, int iNum)
// 一級指針做輸出
int geLen(char *pFileName, int *pfileLen);
理解
主調(diào)函數(shù)還是被調(diào)用函數(shù)分配內(nèi)存
被調(diào)用函數(shù)是在heap/stack上分配內(nèi)存
鐵律6:二級指針典型用法(指針做函數(shù)參數(shù))
// 二級指針做輸入
int main(int arc ,char *arg[]); 字符串?dāng)?shù)組
int shouMatrix(int [3][4], int iLine);
// 二級指針做輸出
int Demo64_GetTeacher(Teacher **ppTeacher);
int Demo65_GetTeacher_Free(Teacher **ppTeacher);
int getData(char **data, int *dataLen);
Int getData_Free(void *data);
Int getData_Free2(void **data); //避免野指針
理解
主調(diào)函數(shù)還是被調(diào)用函數(shù)分配內(nèi)存
被調(diào)用函數(shù)是在heap/stack上分配內(nèi)存
1.3 summary
以上就是現(xiàn)階段指針與內(nèi)存之間的聯(lián)系以及指針使用過程中需要注意事項和總結(jié),牢記這些指針的使用就沒有太大的問題了笼沥。后期將逐一介紹案例蚪燕,加強印象娶牌。