前言
眾所周知,C程序員新手和老手的一大差別就在于是否對(duì)指針有深刻理解,能否高效利用指針。
可以說(shuō)學(xué)好c指針對(duì)于以后的開(kāi)發(fā)工作至關(guān)重要,所以在這里整理出了一系列關(guān)于指針的文章,
供大家一起學(xué)習(xí)進(jìn)步。
本期簡(jiǎn)要介紹指針、指針操作符以及指針如何與內(nèi)存相互作用。
1.1 指針和內(nèi)存
C程序在編譯后,會(huì)以以下三種形式使用內(nèi)存。
- 靜態(tài)/全局內(nèi)存
靜態(tài)聲明的變量分配在這里,全局變量也使用這部分內(nèi)存。這些變量在程序開(kāi)始運(yùn)行時(shí)分配,知道程序終止才消失。所有函數(shù)都能訪問(wèn)全局變量,靜態(tài)變量的作用域則局限在定義他們的函數(shù)內(nèi)部。 - 自動(dòng)內(nèi)存
這些變量在函數(shù)內(nèi)部聲明,并且在函數(shù)被調(diào)用時(shí)才創(chuàng)建。它們的作用域局限在函數(shù)內(nèi)部,而且生命周期局限在函數(shù)的執(zhí)行時(shí)間內(nèi)。 - 動(dòng)態(tài)內(nèi)存
內(nèi)存分配在堆上,可以根據(jù)需要釋放,而且直到釋放才消失。指針引用分配的內(nèi)存,作用域局限于引用內(nèi)存的指針。
理解這些內(nèi)存類型可以更好地理解指針。大部分指針用來(lái)操作內(nèi)存中的數(shù)據(jù),因此理解內(nèi)存的分布和組織方式有助于我們弄清楚指針如何操作內(nèi)存。
指針變量包含內(nèi)存中別的變量、對(duì)象或函數(shù)的地址。對(duì)象就是內(nèi)存分配函數(shù)(比如malloc)分配的內(nèi)存。指針通常根據(jù)所指的數(shù)據(jù)類型來(lái)聲明。對(duì)象可以是任何C數(shù)據(jù)類型,如整數(shù)、字符、字符串或結(jié)構(gòu)體。然而,指針本身并沒(méi)有包含所引用數(shù)據(jù)的類型信息,指針只包含地址。
1.2 指針幾大使用鐵律
鐵律1:指針是一種數(shù)據(jù)類型
1) 指針是一種數(shù)據(jù)類型也是一個(gè)變量,占有內(nèi)存空間,用來(lái)保存內(nèi)存地址。
a) 說(shuō)它是一種數(shù)據(jù)類型,那他究竟是什么類型呢
指針的數(shù)據(jù)類型是指它所指向內(nèi)存空間的數(shù)據(jù)類型
// 測(cè)試指針變量占有內(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)存
在指針聲明時(shí),*號(hào)表示所聲明的變量為指針
在指針使用時(shí),*號(hào)表示操作指針?biāo)赶虻膬?nèi)存空間中的值
*p相當(dāng)于通過(guò)地址(p變量的值)找到一塊內(nèi)存;然后操作內(nèi)存
*p放在等號(hào)的左邊賦值(給內(nèi)存賦值)
*p放在等號(hào)的右邊取值(從內(nèi)存獲取值)
3) 指針變量和它指向的內(nèi)存塊是兩個(gè)不同的概念
含義1 給p賦值p = 0x1111; 只會(huì)改變指針變量值,不會(huì)改變所指的內(nèi)容;p += 1;p++
含義2 給*p賦值*p = 'a'; 不會(huì)改變指針變量的值,只會(huì)改變所指的內(nèi)存塊的值
含義3 =左邊*p 表示 給內(nèi)存賦值, =右邊*p 表示取值 含義不同切結(jié)!
含義4 =左邊char *p
含義5 保證所指的內(nèi)存塊能修改
4) 指針是一種數(shù)據(jù)類型,是指它指向的內(nèi)存空間的數(shù)據(jù)類型
含義1:指針步長(zhǎng)(p++),根據(jù)所致內(nèi)存空間的數(shù)據(jù)類型來(lái)確定
p++=?(unsigned char )p+sizeof(a);
結(jié)論:指針的步長(zhǎng),根據(jù)所指內(nèi)存空間類型來(lái)定。
注意: 不斷的給指針變量賦值,就是不斷的改變指針變量(和所指向內(nèi)存空間沒(méi)有任何關(guān)系)。
鐵律2: 間接賦值(*p)是指針存在的最大意義
1) 兩碼事:指針變量和它指向的內(nèi)存塊變量
2) 條件反射:指針指向某個(gè)變量,就是把某個(gè)變量地址傳給指針
3) *p間接賦值成立條件:3個(gè)條件
a) 2個(gè)變量(通常一個(gè)實(shí)參,一個(gè)形參)
b) 建立關(guān)系,實(shí)參取地址賦給形參指針
c) *p形參去間接修改實(shí)參的值
4)引申:函數(shù)調(diào)用時(shí),用n指針(形參)改變n-1指針(實(shí)參)的值。
//改變0級(jí)指針(int iNum = 1)的值有2種方式
//改變1級(jí)指針(eg char *p = 0x1111 )的值,有2種方式
//改變2級(jí)指針的(eg char **pp1 = 0x1111 )的值,有2種方式
//函數(shù)調(diào)用時(shí),形參傳給實(shí)參,用實(shí)參取地址,傳給形參,在被調(diào)用函數(shù)里面用*p,來(lái)改變實(shí)參,把運(yùn)算結(jié)果傳出來(lái)。
//指針作為函數(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:一級(jí)指針典型用法(指針做函數(shù)參數(shù))
// 一級(jí)指針做輸入
int showbuf(char *p)
int showArray(int *array, int iNum)
// 一級(jí)指針做輸出
int geLen(char *pFileName, int *pfileLen);
理解
主調(diào)函數(shù)還是被調(diào)用函數(shù)分配內(nèi)存
被調(diào)用函數(shù)是在heap/stack上分配內(nèi)存
鐵律6:二級(jí)指針典型用法(指針做函數(shù)參數(shù))
// 二級(jí)指針做輸入
int main(int arc ,char *arg[]); 字符串?dāng)?shù)組
int shouMatrix(int [3][4], int iLine);
// 二級(jí)指針做輸出
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)系以及指針使用過(guò)程中需要注意事項(xiàng)和總結(jié),牢記這些指針的使用就沒(méi)有太大的問(wèn)題了。后期將逐一介紹案例,加強(qiáng)印象。