摘要:所以是數(shù)組指針,而是指針數(shù)組。因為對一個二維數(shù)組,可以不知道有多少行,但是必須知道一行多少元素。當二維數(shù)組數(shù)組名傳參,形參接收時,數(shù)組的行可以省略,列不能省略,如果省略了列,我們就無法知道當指針加減跳過幾個字節(jié)。
大家對于指針恐怕都不陌生!
沒學(xué)過C語言那也一定聽過指針吧,指針是C
最強的優(yōu)勢,學(xué)不明白也就成了劣勢!大家不必害怕,指針并沒有那么恐怖,掌握了指針,讓你的C語言更上一層樓!
bug郭和你一起將指針進階學(xué)習(xí)一遍,一起加油!
可能有伙伴就要問了,咋一來就進階指針!
不要慌問題不大,bug郭之前就寫個一篇博客,介紹指針基礎(chǔ)知識!
有興趣的伙伴可以點擊查看C語言指針,樓下大爺都能學(xué)會的小細節(jié)(和bug郭一起學(xué)C系列),建議收藏!
大家都復(fù)習(xí)完了指針基礎(chǔ)吧,那我們就開始指針進階的學(xué)習(xí)吧!
指針基礎(chǔ)的一些概念:
4/8
個字節(jié)(32
位平臺/64
位平臺)。+-
本章重點
6. 字符指針
7. 數(shù)組指針
8. 指針數(shù)組
9. 數(shù)組傳參和指針傳參
10. 函數(shù)指針
11. 函數(shù)指針數(shù)組
12. 指向函數(shù)指針數(shù)組的指針
13. 回調(diào)函數(shù)
14. 指針和數(shù)組面試題的解析
字符指針顧名思義就是一個指針變量,指針指向的空間存放的是一個字符!
char*
字符指針
//基本用法int main(){ char ch = "c"; char* pc = &ch; *pc = "w"; return 0;}
這種基本的用法,bug就不介紹了,相信大家都會!
//進階int main(){ char* pstr = "abcdef"; //pstr字符指針存了字符串,第一個字符(a)的地址 printf("%s",pstr); return 0;}
代碼char* pstr = "abcdef";
特別容易讓我們以為是把字符串abcedf
放到字符指針pstr
里了,但是本質(zhì)是把字符串abcdef
首字符的地址放到了pstr
中。
我們可以知道通過字符指針pstr
我們可以找到字符串abedef
。
為啥我們不直接創(chuàng)建一個字符串變量,而要用這種方式,有何不同呢?
//測試#include int main(){ char str1[] = "hello world."; char str2[] = "hello world."; char *str3 = "hello world."; char *str4 = "hello world."; if(str1 ==str2) printf("str1 and str2 are same/n"); else printf("str1 and str2 are not same/n"); if(str3 ==str4) printf("str3 and str4 are same/n"); else printf("str3 and str4 are not same/n"); return 0;}
輸出結(jié)果
可以看到,字符數(shù)組str1
和str2
不相同,因為str1
和str2
是數(shù)組名,而數(shù)組名就是第一個數(shù)組的地址。str1
和str2
分別開辟了兩個數(shù)組空間,只不過它們存放的內(nèi)容一樣而已!
而str3
和str4
它們都是指向的同一塊空間,因為它們指向的是字符串常量hello world.
這里
str3
和str4
指向的是一個同一個常量字符串。C/C++
會把常量字符串存儲到多帶帶的一個內(nèi)存區(qū)域,
當幾個指針。指向同一個字符串的時候,他們實際會指向同一塊內(nèi)存。但是用相同的常量字符串去初始化不同的數(shù)組的時候就會開辟出不同的內(nèi)存塊。所以str1
和str2
不同,str3
和str4
不同。
數(shù)組指針,我們首先要明確的就是,數(shù)組指針是指針而不是數(shù)組,它是指向數(shù)組的指針!
//判斷數(shù)組指針int* arr1[3]; //指針數(shù)組int (*arr2)[3]; //數(shù)組指針
我們之前學(xué)過C語言操作符,建議收藏,我們知道操作符[]
的優(yōu)先級高于*
。
所以arr2
是數(shù)組指針,而arr1
是指針數(shù)組。
int (arr2*)[3]
:arr2
是一個指針,指向的對象是整型數(shù)組,數(shù)組的元素個數(shù)為3
#include int main(){ int arr[4] = { 1,2,3,4 }; int(*parr)[4] = &arr; //數(shù)組指針存放數(shù)組arr的地址! return 0;}
大家肯定很少見代碼這么寫吧,數(shù)組指針很少這樣使用!
我們已經(jīng)知道了數(shù)組名就是,數(shù)組的首元素地址,而取地址數(shù)組名是數(shù)組的地址 。
那&arr
和arr
有啥區(qū)別呢?
#include int main(){ int arr[4] = { 1,2,3,4 }; int(*parr)[4] = &arr; printf("arr :%p/n",arr); printf("&arr:%p/n", &arr); return 0;}
居然都是第一個元素的地址!
但是我們知道,指針的類型決定了指針加減的步長!
#include int main(){ int arr[4] = { 1,2,3,4 }; int(*parr)[4] = &arr; printf("arr :%p/n",arr); printf("&arr:%p/n", &arr); printf("arr+1 :%p/n", arr+1); //整型指針加1,加一個整型類型大小 printf("&arr+1:%p/n", &arr+1);//數(shù)組指針加1,加一個數(shù)組類型大小 return 0;}
可以看到,數(shù)組指針和首元素地址,指針的類型不同
數(shù)組名
arr
:指針類型是整型 指針加減1
,步長為整型大小(4bit)
&
數(shù)組名:指針類型是數(shù)組 指針加減1
,步長為數(shù)組大小(16bit)
數(shù)組指針正確使用
#include void print_arr1(int arr[3][5], int row, int col){ int i = 0; for(i=0; i<row; i++) { for(j=0; j<col; j++) { printf("%d ", arr[i][j]); } printf("/n"); }}void print_arr2(int (*arr)[5], int row, int col){ int i = 0; for(i=0; i<row; i++) { for(j=0; j<col; j++) { printf("%d ", arr[i][j]); } printf("/n"); }}int main(){ int arr[3][5] = {1,2,3,4,5,6,7,8,9,10}; print_arr1(arr, 3, 5); //數(shù)組名arr,表示首元素的地址 //但是二維數(shù)組的首元素是二維數(shù)組的第一行 //所以這里傳遞的arr,其實相當于第一行的地址,是一維數(shù)組的地址 //可以數(shù)組指針來接收 print_arr2(arr, 3, 5); return 0;}
學(xué)了數(shù)組指針,是不是發(fā)現(xiàn)有點懵了!
//捋一捋int *arr1[3]; //指針數(shù)組//數(shù)組個數(shù)是3,元素是int指針類型的數(shù)據(jù)int (*arr2)[3];//數(shù)組指針//指針,指向數(shù)組,且數(shù)組的類型是int類型,且元素個數(shù)為3int* (*arr3)[3]; //數(shù)組指針//指針,指向數(shù)組,數(shù)組元素是int*類型,且元素個數(shù)為3int (*arr4[3])[3]; //數(shù)組指針指針//指針,指向一個數(shù)組指針,數(shù)組指針的類型是int(*) [3] 指向數(shù)組且為為int類型,元素個數(shù)為3......
就捋到吧,再捋下去就更懵了,兄弟們慢慢學(xué),你可以了的!
在寫代碼的時候難免要把數(shù)組或者指針傳給函數(shù),那函數(shù)的參數(shù)該如何設(shè)計呢?
#include void test(int arr[])//ok?{} //int arr[] 接收就是以int * arr形式接收,因為*arr等價與 arr[]void test(int arr[10])//ok?{} //int arr[10] 同上在形參中都是一個整型指針,形參中的數(shù)組長度無意義void test(int* arr)//ok?{} //整型指針接收數(shù)組名就是首元素地址也就是整型指針void test2(int* arr[20])//ok?{} //int* arr[20]等價于 int* arr[]等價于 int**arr 即二級指針 //而實參就是一個指向整型指針的指針也就是二級指針void test2(int** arr)//ok?{} //二級指針接收int main(){ int arr[10] = { 0 }; int* arr2[20] = { 0 }; test(arr); test2(arr2);}
void test(int arr[3][5])//ok?{} //二維數(shù)組傳參二維數(shù)組接收void test(int arr[][])//ok?{} //error 不知道二維數(shù)組中一維數(shù)組中元素個數(shù)void test(int arr[][5])//ok?{} //可以省略行不能省略列//總結(jié):二維數(shù)組傳參,函數(shù)形參的設(shè)計只能省略第一個[]的數(shù)字。//因為對一個二維數(shù)組,可以不知道有多少行,但是必須知道一行多少元素。//這樣才方便運算。void test(int *arr)//ok?{} //error 二維數(shù)組的數(shù)組名就是首元素地址,即一維數(shù)組的地址,// 也就是數(shù)組指針,應(yīng)該用數(shù)組指針接收 void test(int* arr[5])//ok?{} //error,指針數(shù)組,實參是數(shù)組指針void test(int (*arr)[5])//ok?{} //實參為數(shù)組指針與形參類型相同void test(int **arr)//ok?{} //error int main(){ int arr[3][5] = {0}; test(arr);}
我們來總結(jié)一下!
- 二維數(shù)組的數(shù)組名就是首元素地址,而二維數(shù)組的元素就是一維數(shù)組,所以數(shù)組名的類型就是數(shù)組指針。
- 當二維數(shù)組數(shù)組名傳參,形參接收時,數(shù)組的行可以省略,列不能省略,如果省略了列,我們就無法知道當指針加減跳過幾個字節(jié)。
#include void print(int *p, int sz) //一級指針傳參,一級指針接收{ int i = 0; for(i=0; i<sz; i++) { printf("%d/n", *(p+i)); }}//void print(int p[],int sz) //數(shù)組接收,也即一級指針接收,不提倡這樣寫int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9}; int *p = arr; int sz = sizeof(arr)/sizeof(arr[0]); //一級指針p,傳給函數(shù) print(p, sz); return 0;}
思考:
當一個函數(shù)的參數(shù)部分為一級指針的時候,函數(shù)能接收什么參數(shù)?
//以int型指針為例void test(int* p){}int main(){ int x=0; int* px=&x; int arr[10]; test(&x);//整型地址 test(px);//一級指針 test(arr);//一維數(shù)組名,即首元素地址,int* return 0;}
void test(char** p ){}int main(){ char ch = "c"; char* pc = &ch; char* *ppc = &pc; char* arr[3]; test(&pc); //一級指針的地址,即二級指針 test(ppc); //二級指針 test(arr); //數(shù)組名,首元素地址,首元素為一級指針,所以為二級指針 return 0;}
思考:
當函數(shù)的參數(shù)為二級指針的時候,可以接收什么參數(shù)?
其實和上面一樣,你們可以思考一下!
首先看一段代碼:
#include void test(){ printf("hehe/n");}int main(){ printf("%p/n", test); //函數(shù)名 就是函數(shù)地址 printf("%p/n", &test); //&函數(shù)名 也是函數(shù)地址 return 0;}
運行結(jié)果
那么如何將test()
函數(shù)指針保存起來呢?
void test(){ printf("hehe/n");}//下面pfun1和pfun2哪個有能力存放test函數(shù)的地址?void (*pfun1)(); //函數(shù)指針類型void *pfun2(); //函數(shù),函數(shù)的返回值是void*
函數(shù)指針類型
指針都是有類型的
整型指針int*
數(shù)組指針int (*)[]
函數(shù)指針返回值 (*)(參數(shù)....)
#include int Add(int x, int y){ return x + y;}int main(){ int (*pf)(int, int) = Add; int sum = (*pf)(3, 5); //對函數(shù)指針解引用 printf("sum = %d", sum); sum = pf(3, 5); //因為 Add和&Add相同,即Add等價于 pf printf("sum = %d", sum); return 0;}
有趣的代碼
//代碼1(*(void (*)())0)(); //void (*)()為函數(shù)指針//(void (*)())0 將0強制類型抓換成函數(shù)指針的地址//(*(void (*)())0)() *地址,調(diào)用0地址處的這個函數(shù)//函數(shù)的返回值空,參數(shù)為空
//代碼2void (*signal(int , void(*)(int)))(int);//void(*)(int) 函數(shù)指針,返回值void,參數(shù)int //void (*signal(int , void(*)(int)))(int)// signal是函數(shù)名 //返回值是void(*)(int)// 參數(shù)int 和函數(shù)指針 void(*)(int)//這是一個函數(shù)的聲明
當我們看到代碼2很難看懂這個代碼!
可以簡化嗎?
void (*signal(int , void(*)(int)))(int);//既然這個函數(shù)的返回值類型是 void(*)(int) //那我們可以寫成// void(*)(int) signal(int , void(*)(int));//但是這樣會語法錯誤 error
函數(shù)指針類型重命名
簡化
typedef void(*ptr_t) (int); //正確的類型重命名 ptr_t signal(int, ptr_t); //簡化
上面的代碼出自《C陷阱和缺陷》
有興趣的伙伴可以嘗試閱讀!
數(shù)組是一個存放相同類型數(shù)據(jù)的存儲空間,那我們已經(jīng)學(xué)習(xí)了指針數(shù)組
比如:
int* arr[10]; //整型指針數(shù)組
那要把函數(shù)的地址存到一個數(shù)組中,那這個數(shù)組就叫函數(shù)指針數(shù)組,那函數(shù)指針的數(shù)組如何定義呢?
int (*parr1[10]])(); //int *parr2[10]();
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/122185.html
摘要:因為指針指向的是整個數(shù)組,所以它的類型是數(shù)組指針,所以我們在它的前面進行強制類型轉(zhuǎn)換,把它轉(zhuǎn)換為類型,然后再存放到指針變量內(nèi)部。 前言 通過8道指針筆試題的解析,可以充分的復(fù)習(xí)到指針的相關(guān)知識,并且題目中會結(jié)合許多之前的相關(guān)知識,希望通過本篇文章,對大家所學(xué)的知識進行一個復(fù)習(xí)。 提示:以下...
摘要:結(jié)尾有關(guān)這四道經(jīng)典的指針筆試題講解就到此結(jié)束了,如果覺得文章對自己有所幫助,歡迎大家多多點贊收藏 ?前言 : 今天博主來講解4道經(jīng)典的指針筆試題,很多朋友沒有深刻理...
摘要:故使用無具體類型,又稱通用類型,即可以接收任意類型的指針,但是無法進行指針運算解引用,整數(shù)等。求指針所占字節(jié)而不是解引用訪問權(quán)限大小。數(shù)組就是整個數(shù)組的大小,數(shù)組元素則是數(shù)組元素的大小,指針大小都為。 ...
摘要:之所以這樣說不要認為學(xué)就不需要學(xué)語言,是因為一味的只學(xué)而沒有語言等這些基礎(chǔ)語言的支撐,是很難深入理解的很多東西的。 之所以這樣說不要認為學(xué)PHP就不需要學(xué)C語言,是因為一味的只學(xué)PHP而沒有C語言等這些基礎(chǔ)語言的支撐,是很難深入理解PHP的很多東西的。 這樣的例子其實很多,這里我就舉這個例子吧:PHP的數(shù)組和C語言的數(shù)組的區(qū)別和聯(lián)系。 學(xué)過C語言的朋友當然知道C語言里有數(shù)組; PHP里...
閱讀 2238·2021-11-22 09:34
閱讀 1349·2021-10-11 10:59
閱讀 4449·2021-09-22 15:56
閱讀 3311·2021-09-22 15:08
閱讀 3415·2019-08-30 14:01
閱讀 787·2019-08-30 11:16
閱讀 1139·2019-08-26 13:51
閱讀 2920·2019-08-26 13:43