C語(yǔ)言簡(jiǎn)析指針用途
在C語(yǔ)言中,任何一個(gè)變量,都有兩層含義:
(1) 代表該變量的存儲(chǔ)單元的地址;變量的地址 左值 lvalue
(2) 代表該變量的值;右值 rvalue
對(duì)于一個(gè)變量的訪問(wèn),只有兩種情況:
一是把一個(gè)值寫到變量的地址中去 (lvalue)
二是從變量的地址中取變量的值 (rvalue)
對(duì)象的訪問(wèn)方式
直接訪問(wèn) : 通過(guò)對(duì)象名去訪問(wèn)
如:
int a; a = 1024; b = a;
注:直接訪問(wèn) 受到作用域的限制
間接訪問(wèn) :
通過(guò)對(duì)象的地址去訪問(wèn),指針訪問(wèn)。
只要你知道了對(duì)象的地址,就可以在任何地方去訪問(wèn)它。
不受作用域的限制。
什么是指針
存儲(chǔ)單元(如: memory 內(nèi)存)的地址:
分配給每個(gè)對(duì)象的內(nèi)存單元都有一個(gè)編號(hào),這個(gè)編號(hào)就是我們所說(shuō)
存儲(chǔ)單元的地址。并且存儲(chǔ)單元按照字節(jié)來(lái)編號(hào)。
在C語(yǔ)言中,指針的概念與地址差不多的,你可以直接認(rèn)為指針就是一個(gè)地址。
一個(gè)變量的地址,我們也稱為變量的“指針”
& 取地執(zhí)符
單目運(yùn)算符, “取xxx對(duì)象的地址”
通過(guò)一個(gè)對(duì)象的指針去訪問(wèn)它,首先要解決對(duì)象的指針(地址) 的保存問(wèn)題。
需要定義另外的一個(gè)變量去保存它的地址,這種變量我們稱為指針變量。
指針變量
指針變量也是一個(gè)變量,也是用來(lái)保存數(shù)據(jù),只不過(guò)指針變量保存的數(shù)據(jù)是其他對(duì)象的地址。
指針變量的定義:
指向的對(duì)象的類型 * 指針變量名;
“指向的對(duì)象的類型” :
指針變量指向的對(duì)象的類型,而不是指針的類型。
如:
int *p; int a=10; p=&a;//p保存了對(duì)象a的地址 // p 指向 a
與指針相關(guān)的運(yùn)算符
& : 取地址符
int a;
&a : 表示取對(duì)象a的地址
對(duì)象a的地址,其實(shí)就是對(duì)象a的指針。
* : 指向運(yùn)算符 ,單目運(yùn)算符
*地址(*指針): 地址對(duì)應(yīng)的那個(gè)變量(對(duì)象)。
如
int a=10; int *p=&a; int b=*&a;//b=10,int b=a
所以*(&a) <=> a
*& 可以直接約掉 (編譯原理狀態(tài)機(jī)的詞法分析)
指針變量作為函數(shù)參數(shù)
傳遞的還是值!! 只不過(guò)這個(gè)“實(shí)參的值”可能是某個(gè)對(duì)象的地址!
C語(yǔ)言中,函數(shù)參數(shù)的傳遞只能是"值傳遞"
形參 = 實(shí)參的值
野指針:
void XXX2(int * m, int * n) { int * t;//定義了一個(gè)指針變量t, 但是t沒(méi)有被賦值 //t沒(méi)有賦值,但是不代表它沒(méi)有值,相反它會(huì)有一個(gè)相對(duì)應(yīng)的 //不知道這個(gè)值是多少 undefine *t = *m; //操作野指針,可能導(dǎo)致 段錯(cuò)誤(對(duì)一個(gè)未知的空間進(jìn)行寫操作) *m = *n; *n = *t; //操作野指針,可能導(dǎo)致 段錯(cuò)誤(對(duì)一個(gè)未知的空間進(jìn)行讀操作)
*t 放置到 ‘=’ 符號(hào)的左邊,代表t指向?qū)ο蟮淖笾?/p>
對(duì)t的指向的對(duì)象進(jìn)行寫的操作
*t 放置到 ‘=’ 符號(hào)的右邊,代表t指向?qū)ο蟮挠抑?/p>
對(duì)t的指向的對(duì)象進(jìn)行read的操作
所以t是一個(gè)“野指針”,我們也不知道 t指向的內(nèi)存空間是否可讀可寫,
如果不可讀或者不可寫,那么后續(xù)對(duì)*t操作,就會(huì)導(dǎo)致內(nèi)存的非法訪問(wèn) => 段錯(cuò)誤!!
空指針:
NULL 0
在計(jì)算機(jī)中地址為0的存儲(chǔ)空間是不存在的
如果一個(gè)指針的值,指向空(NULL)的指針,稱之為空指針。
int *p=NULL; *p=1024;//操作空指針 int b=*p;//操作空指針
我們?nèi)ナ褂每罩羔?,一定?huì) 造成內(nèi)存的非法訪問(wèn) => 段錯(cuò)誤
數(shù)組與指針
數(shù)組元素與普通變量是一樣的,數(shù)組元素也有自己的地址。
數(shù)組元素也有左值和右值,并且數(shù)組元素間的地址是相鄰的。
數(shù)組名可以代表首元素的地址。
a => &a[0], 數(shù)組名a當(dāng)做指針來(lái)看
如
int a[]={1,2,3}; int *p=a;//a是數(shù)組名當(dāng)指針來(lái)看,==&a[0]
指針作加減的問(wèn)題:
能不能通過(guò)指針p去訪問(wèn)a[1]?
p=p+1;//&a[0]+1==&a[1]
p + i (p是一個(gè)指針,i是一個(gè)整數(shù)值)
注:不是簡(jiǎn)單地加減數(shù)值,而是加減i個(gè)指針指向單元的長(zhǎng)度。
p + 1 => 往后面挪了一個(gè)int單元的長(zhǎng)度 ,&a[1]
int a[10]; int * p = a; // p = &a[0] a[1] <=> *&a[1] <=> *(&a[0] + 1) <=> *(a + 1) <=> a[1] a[1] <=> *&a[1] <=> *(&a[0] + 1) <=> *(p + 1) <=> p[1]
數(shù)組名a,在代碼中有兩層含義:
int a[10];
(1) 數(shù)組名代表整個(gè)數(shù)組
&a : 取整個(gè)數(shù)組a的地址。
&a + 1 : 往后面挪了1個(gè)(int[10])單元長(zhǎng)度。
(2) 在合適情況下面,數(shù)組名可以當(dāng)作指針來(lái)看
a <=> &a[0]
a + 1 : 當(dāng)作指針來(lái)看
=> &a[0] + 1
=> &a[1]
多維數(shù)組與指針
在C語(yǔ)言中,所有的數(shù)組其實(shí)都是一維數(shù)組!
int a[3][4]; //int[4] a[3];
表達(dá)式 表達(dá)式的含義 表達(dá)式的值
a 數(shù)組名:
(1) 當(dāng)作指針 &a[0] 取整個(gè)一維數(shù)組a[0]的地址
(2) 當(dāng)作整個(gè)數(shù)組來(lái)看
a[0] 數(shù)組名:
(1) 當(dāng)作指針 &a[0][0] 取數(shù)組元素a[0][0]的地址
(2) 當(dāng)作整個(gè)一維數(shù)組a[0]來(lái)看
a[0][0] 數(shù)組元素a[0][0] a[0][0] (左值/右值)
a + 1 a是數(shù)組名,在此處當(dāng)作指針 ==&a[0]+1==&a[1]
a[0] + 1 a[0] 是數(shù)組名,在此處當(dāng)作指針 ==&a[0][0]+1==&a[0][1]
a[0][0] + 1 a[0][0]是二維數(shù)組a中的一個(gè)int類型的元素 ==a[0][0]+1
a[1] + 2 a[1]是數(shù)組名,此處當(dāng)作指針 ==&a[1][0]+2==&a[1][2]
*(a + 1) + 2 a是數(shù)組名,在此處當(dāng)作指針 ==*(&a[0]+1)+2==*(&a[1])+2==a[1]+2==&a[1][2]
指針常量 和 常量指針
他們都是指針,只不過(guò)他們之間的屬性有一點(diǎn)區(qū)別。
指針常量:
指針本身不能改變(指針的指向不能變),但是
它所指向的內(nèi)存空間里面的內(nèi)容是可以改變的。
最具有代表性例子,數(shù)組名!
定義方式:
指向?qū)ο蟮念愋?* const 指針變量名;
int a , b; int * const p = &a; p = &b ; //error
常量指針:
是一個(gè)指向常量的地址。指針指向的對(duì)象是常量,
那么指針本身的指向是可以改變的,但是這個(gè)指針指向
內(nèi)存空間中的內(nèi)容是不能夠改變。
最具有代表性例子,字符串
char * p = "abcde"; //"abcde" <=> &'a'
定義方式:
const 類型 * 變量名;
or
類型 const * 變量名;
指針數(shù)組 與 數(shù)組指針
(1) 指針數(shù)組
指針數(shù)組是一個(gè)數(shù)組,只不過(guò)它里面的每一個(gè)元素都是指針罷了!
定義數(shù)組:
數(shù)組元素類型 數(shù)組名[元素個(gè)數(shù)];
“數(shù)組元素類型” : C語(yǔ)言中任意合法的類型都可以。
int * p[4]; //定義了一個(gè)指針數(shù)組,數(shù)組名為p,里面含有4個(gè)int*類型的指針。
(2) 數(shù)組指針
數(shù)組指針是一個(gè)指針,只不過(guò)這個(gè)指針是用來(lái)指向一個(gè)數(shù)組罷了!!
int (*p)[4] ; //定義了一個(gè)數(shù)組指針,指針變量名為p,用來(lái)指向一個(gè)含有4個(gè)int類型元素的數(shù)組的。
如
int a[3][4]; int (*p)[4]; p = a; //&a[0] *(*p + 1) // *(a[0]+1)==*(&a[0][1])==a[0][1] *(*(p + 2)) // *(*(&a[2]))==*(&a[2][0])==a[2][0] *(*(p+3) + 3)// *(*(&a[0]+3)+3)==*(*(&a[3])+3)==*(&a[3][0]+3)==a[3][3]
字符串與指針
字符串就是一串字符。在C語(yǔ)言中,沒(méi)有字符串這個(gè)類型。
C語(yǔ)言字符串是通過(guò) char *(字符指針)來(lái)實(shí)現(xiàn)。
C語(yǔ)言中的字符串,是用""引起來(lái)的一串字符來(lái)表示,并且字符串后面默認(rèn)會(huì)加一個(gè)\0,\0(ASCII為0的那個(gè)字符)字符串結(jié)束的標(biāo)志。
如
"abc" //字符串
"\n" //字符串
"" //字符串 => 空串
'\123' //字符
'\n' //字符
注:
我們只需要保存字符串的首字符地址就可以了,從首字符地址開始找到第一個(gè)\0,前面的這些字符就是字符串里面的字符。
在C語(yǔ)言中的字符串(如: “ssssssabcd”)是保存在一個(gè)叫做 .rodata(只讀數(shù)據(jù))的內(nèi)存區(qū)域,字符串代表是這個(gè)內(nèi)存空間的首地址。
"ssssssabcd" => 表達(dá)式的值 => &'s' char *p="12345" ==&'1' int *p=&'1'; p+1=&'2';
字符數(shù)組:
char s[5] = {'a', 'b', 'c', 'd', 'e'}; //字符數(shù)組,與普通數(shù)組是一樣的,保存在一個(gè).data/??臻g //數(shù)組區(qū)域是可讀可寫的 sizeof(s) == 5 strlen(s) >= 5 //沒(méi)有'\0' 長(zhǎng)度不確定
char s[] = {"abcde"}; //自動(dòng)生成'\0' <=> char s[] = {'a', 'b', 'c', 'd', 'e', '\0'}; //s字符數(shù)組,與普通數(shù)組是一樣的,保存在一個(gè).data/??臻g //數(shù)組區(qū)域是可讀可寫的 sizeof(s) == 6 strlen(s) == 5
char s[] = {"abcde"}; s[1] = 'B'; //OK char ch = s[1]; //OK *(s + 1) = 'B'; //OK ch = *(s + 1); //OK s = s + 1; //ERROR //s是數(shù)組名,數(shù)組名當(dāng)作指針,指針常量 //s的指向 是不能夠改變的,但是s指向的內(nèi)存空間 //里面的內(nèi)容是可變的 printf("%s\n", s); //abcde %s : char* 地址 //把后面的那個(gè)地址當(dāng)作是一個(gè)字符串的首地址,一個(gè)一個(gè)字符進(jìn)行輸出,直到遇到\0才會(huì)結(jié)束!
函數(shù)指針
函數(shù)也有地址 ,那么咱們可以定義一個(gè)指針,去存放一個(gè)函數(shù)的地址,像這樣的指針,稱為函數(shù)指針。
函數(shù)指針如何定義
int * abc(int a, float b) { }
描述函數(shù)abc的類型: int (int , float ) : 是一個(gè)返回值為int類型,帶有一個(gè)Int類型和float類型的參數(shù)的函數(shù)類型
指向函數(shù)的返回值的類型 (*指針變量名) (指向函數(shù)的形參類型列表);
int (* p)(int, int) ;
定義了一個(gè)指針變量p,p是一個(gè)函數(shù)指針,是用來(lái)指向一個(gè)返回值為int類型,并且?guī)в袃蓚€(gè)int類型參數(shù)的函數(shù)的。
函數(shù)指針如何賦值
&函數(shù)名
or
函數(shù)名 : 在C語(yǔ)言中,函數(shù)名本身就可以代表函數(shù)的地址
通過(guò)函數(shù)指針去調(diào)用指向的函數(shù),有如下兩種方案:
p為函數(shù)的指針。
(1) (*p)(實(shí)參列表)
(2) p(實(shí)參列表)
int *p=abc//函數(shù)名 p(a,b);//調(diào)用函數(shù)
二級(jí)指針 與 多級(jí)指針
int a,b;
可以定義一個(gè)指針變量p1,來(lái)保存變量a的地址:
int *p1=&a; b=*p1=*&a=a;//通過(guò)指針p1訪問(wèn)a變量
可以定義一個(gè)指針變量p2,來(lái)保存變量p1的地址:
int *p2=&p1 int b=**p2=*p1=a//通過(guò)指針p2訪問(wèn)a變量
p2保存的是一個(gè)一級(jí)指針p1的地址,所以說(shuō),
p2指向一個(gè)一級(jí)指針,p2就是一個(gè)二級(jí)指針
可以定義一個(gè)指針變量p3,來(lái)保存變量p2的地址:
int *p3=&p2; int b=***p3=**p2=*p1=a;
p3保存的是一個(gè)二級(jí)指針p2的地址,所以說(shuō),
p3指向一個(gè)二級(jí)指針,p3就是一個(gè)三級(jí)指針
到此這篇關(guān)于C語(yǔ)言簡(jiǎn)析指針用途的文章就介紹到這了,更多相關(guān)C語(yǔ)言指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言如何計(jì)算兩個(gè)數(shù)的最小公倍數(shù)
這篇文章主要介紹了C語(yǔ)言如何計(jì)算兩個(gè)數(shù)的最小公倍數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11C語(yǔ)言文字藝術(shù)之?dāng)?shù)據(jù)輸入輸出
這篇文章主要介紹了C語(yǔ)言文字藝術(shù)之?dāng)?shù)據(jù)輸入輸出,C語(yǔ)言的語(yǔ)句用來(lái)向計(jì)算機(jī)系統(tǒng)發(fā)出操作指令。一條語(yǔ)句編寫完成經(jīng)過(guò)編譯后產(chǎn)生若干條機(jī)器指2022-07-07解決Qt設(shè)置QTextEdit行高的問(wèn)題
這篇文章介紹了Qt設(shè)置QTextEdit行高的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之模式匹配字符串定位問(wèn)題
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之模式匹配字符串定位問(wèn)題的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解這部分內(nèi)容,需要的朋友可以參考下2017-10-10