指針基本概念
-
什么是地址
-
生活中的地址:
-
內(nèi)存地址:
-
-
地址與內(nèi)存單元中的數(shù)據(jù)是兩個(gè)完全不同的概念
- 地址如同房間編號, 根據(jù)這個(gè)編號我們可以找到對應(yīng)的房間
- 內(nèi)存單元如同房間, 房間是專門用于存儲數(shù)據(jù)的
-
變量地址:
- 系統(tǒng)分配給"變量"的"內(nèi)存單元"的起始地址
int num = 6; // 占用4個(gè)字節(jié)
//那么變量num的地址為: 0ff06
char c = 'a'; // 占用1個(gè)字節(jié)
//那么變量c的地址為:0ff05
什么是指針
在計(jì)算機(jī)中所有數(shù)據(jù)都存儲在內(nèi)存單元中,而每個(gè)內(nèi)存單元都有一個(gè)對應(yīng)的地址, 只要通過這個(gè)地址就能找到對應(yīng)單元中存儲的數(shù)據(jù).
由于通過地址能找到所需的變量單元汪诉,所以我們說該地址指向了該變量單元窗看。將地址形象化的稱為“指針”
-
內(nèi)存單元的指針(地址)和內(nèi)存單元的內(nèi)容是兩個(gè)不同的概念。
什么是指針變量
-
在C語言中,允許用一個(gè)變量來存放其它變量的地址, 這種專門用于存儲其它變量地址的變量, 我們稱之為指針變量
示例:
int age;// 定義一個(gè)普通變量
num = 10;
int *pnAge; // 定義一個(gè)指針變量
pnAge = &age;
定義指針變量的格式
- 指針變量的定義包括兩個(gè)內(nèi)容:
- 指針類型說明,即定義變量為一個(gè)指針變量;
-
指針變量名;
- 示例:
char ch = 'a';
char *p; // 一個(gè)用于指向字符型變量的指針
p = &ch;
int num = 666;
int *q; // 一個(gè)用于指向整型變量的指針
q = #
- 其中,*表示這是一個(gè)指針變量
- 變量名即為定義的指針變量名
- 類型說明符表示本指針變量所指向的變量的數(shù)據(jù)類型
指針變量的初始化方法
- 指針變量初始化的方法有兩種:定義的同時(shí)進(jìn)行初始化和先定義后初始化
- 定義的同時(shí)進(jìn)行初始化
int a = 5;
int *p = &a;
- 先定義后初始化
int a = 5;
int *p;
p=&a;
- 把指針初始化為NULL
int *p=NULL;
int *q=0;
- 不合法的初始化:
- 指針變量只能存儲地址, 不能存儲其它類型
int *p;
p = 250; // 錯(cuò)誤寫法
- 給指針變量賦值時(shí),指針變量前不能再加“*”
int *p;
*p=&a; //錯(cuò)誤寫法
-
注意點(diǎn):
-
多個(gè)指針變量可以指向同一個(gè)地址
-
指針的指向是可以改變的
int a = 5;
int *p = &a;
int b = 10;
p = &b; // 修改指針指向
- 指針沒有初始化里面是一個(gè)垃圾值,這時(shí)候我們這是一個(gè)野指針
- 野指針可能會導(dǎo)致程序崩潰
- 野指針訪問你不該訪問數(shù)據(jù)
-
所以指針必須初始化才可以訪問其所指向存儲區(qū)域
訪問指針?biāo)赶虻拇鎯臻g
- C語言中提供了地址運(yùn)算符&來表示變量的地址腰耙。其一般形式為:
- &變量名;
- C語言中提供了*來定義指針變量和訪問指針變量指向的內(nèi)存存儲空間
- 在定義變量的時(shí)候 * 是一個(gè)類型說明符,說明定義的這個(gè)變量是一個(gè)指針變量
int *p=NULL; // 定義指針變量
- 在不是定義變量的時(shí)候 *是一個(gè)操作符,代表訪問指針?biāo)赶虼鎯臻g
int a = 5;
int *p = &a;
printf("a = %d", *p); // 訪問指針變量
指針類型
-
在同一種編譯器環(huán)境下,一個(gè)指針變量所占用的內(nèi)存空間是固定的。
-
雖然在同一種編譯器下, 所有指針占用的內(nèi)存空間是一樣的,但不同類型的變量卻占不同的字節(jié)數(shù)
- 一個(gè)int占用4個(gè)字節(jié)彤恶,一個(gè)char占用1個(gè)字節(jié),而一個(gè)double占用8字節(jié)越驻;
- 現(xiàn)在只有一個(gè)地址叽掘,我怎么才能知道要從這個(gè)地址開始向后訪問多少個(gè)字節(jié)的存儲空間呢楣铁,是4個(gè),是1個(gè)更扁,還是8個(gè)民褂。
-
所以指針變量需要它所指向的數(shù)據(jù)類型告訴它要訪問多少個(gè)字節(jié)存儲空間
二級指針
- 如果一個(gè)指針變量存放的又是另一個(gè)指針變量的地址,則稱這個(gè)指針變量為指向指針的指針變量。也稱為“二級指針”
char c = 'a';
char *cp;
cp = &c;
char **cp2;
cp2 = &cp;
printf("c = %c", **cp2);
- 多級指針的取值規(guī)則
int ***m1; //取值***m1
int *****m2; //取值*****m2
練習(xí)
- 定義一個(gè)函數(shù)交換兩個(gè)變量的值
- 寫一個(gè)函數(shù)疯潭,同時(shí)返回兩個(gè)數(shù)的和與差
數(shù)組指針的概念及定義
- 數(shù)組元素指針
- 一個(gè)變量有地址,一個(gè)數(shù)組包含若干元素,每個(gè)數(shù)組元素也有相應(yīng)的地址, 指針變量也可以保存數(shù)組元素的地址
-
只要一個(gè)指針變量保存了數(shù)組元素的地址, 我們就稱之為數(shù)組元素指針
printf(“%p %p”, &(a[0]), a); //輸出結(jié)果:0x1100, 0x1100
- 注意: 數(shù)組名a不代表整個(gè)數(shù)組,只代表數(shù)組首元素的地址赊堪。
- “p=a;”的作用是“把a(bǔ)數(shù)組的首元素的地址賦給指針變量p”,而不是“把數(shù)組a各元素的值賦給 p”
指針訪問數(shù)組元素
int main (void)
{
int a[5] = {2, 4, 6, 8, 22};
int *p;
// p = &(a[0]);
p = a;
printf(“%d %d\n”,a[0],*p); // 輸出結(jié)果: 2, 2
}
- 在指針指向數(shù)組元素時(shí),允許以下運(yùn)算:
- 加一個(gè)整數(shù)(用+或+=),如p+1
- 減一個(gè)整數(shù)(用-或-=),如p-1
- 自加運(yùn)算,如p++,++p
- 自減運(yùn)算,如p--,--p
- 如果指針變量p已指向數(shù)組中的一個(gè)元素,則p+1
指向
同一數(shù)組中的下一個(gè)元素,p-1指向
同 一數(shù)組中的上一個(gè)元素衅鹿。
- 結(jié)論: 訪問數(shù)組元素,可用下面兩種方法:
- 下標(biāo)法, 如a[i]形式
- 指針法, *(p+i)形式
- 注意:
- 數(shù)組名雖然是數(shù)組的首地址截粗,但是數(shù)組名所所保存的數(shù)組的首地址是不可以更改的
int x[10];
x++; //錯(cuò)誤
int* p = x;
p++; //正確
指針與字符串
- 定義字符串的兩種方式
- 字符數(shù)組
char string[]=”I love lnj!”;
printf("%s\n",string);
- 字符串指針指向字符串
// 數(shù)組名保存的是數(shù)組第0個(gè)元素的地址, 指針也可以保存第0個(gè)元素的地址
char *str = "abc"
- 字符串指針使用注意事項(xiàng)
- 可以查看字符串的每一個(gè)字符
har *str = "lnj";
for(int i = 0; i < strlen(str);i++)
{
printf("%c-", *(str+i)); // 輸出結(jié)果:l-n-j
}
- 不可以修改字符串內(nèi)容
// + 使用字符數(shù)組來保存的字符串是保存棧里的,保存棧里面東西是可讀可寫,所有可以修改字符串中的的字符
// + 使用字符指針來保存字符串,它保存的是字符串常量地址,常量區(qū)是只讀的,所以我們不可以修改字符串中的字符
char *str = "lnj";
*(str+2) = 'y'; // 錯(cuò)誤
- 不能夠直接接收鍵盤輸入
// 錯(cuò)誤的原因是:str是一個(gè)野指針,他并沒有指向某一塊內(nèi)存空間
// 所以不允許這樣寫如果給str分配內(nèi)存空間是可以這樣用 的
char *str;
scanf("%s", str);
指向函數(shù)指針
- 為什么指針可以指向一個(gè)函數(shù)固灵?
- 函數(shù)作為一段程序胧辽,在內(nèi)存中也要占據(jù)部分存儲空間喻粹,它也有一個(gè)起始地址
- 函數(shù)有自己的地址凑保,那就好辦了烦感,我們的指針變量就是用來存儲地址的忠蝗。
- 因此可以利用一個(gè)指針指向一個(gè)函數(shù)增淹。其中椿访,函數(shù)名就代表著函數(shù)的地址。
- 指針函數(shù)的定義
- 格式:
返回值類型 (*指針變量名)(形參1, 形參2, ...);
- 格式:
int sum(int a,int b)
{
return a + b;
}
int (*p)(int,int);
p = sum;
-
指針函數(shù)定義技巧
- 1虑润、把要指向函數(shù)頭拷貝過來
- 2成玫、把函數(shù)名稱使用小括號括起來
- 3、在函數(shù)名稱前面加上一個(gè)*
- 4拳喻、修改函數(shù)名稱
-
應(yīng)用場景
- 調(diào)用函數(shù)
- 將函數(shù)作為參數(shù)在函數(shù)間傳遞
-
注意點(diǎn):
- 由于這類指針變量存儲的是一個(gè)函數(shù)的入口地址哭当,所以對它們作加減運(yùn)算(比如p++)是無意義的
- 函數(shù)調(diào)用中"(指針變量名)"的兩邊的括號不可少,其中的不應(yīng)該理解為求值運(yùn)算,在此處它 只是一種表示符號