成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深入理解C語言指針——挑戰(zhàn)C指針筆試題 (和bug郭一起學(xué)C系列)

miracledan / 1348人閱讀

摘要:所以是數(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ǔ)的一些概念:

  1. 指針就是個變量,用來存放地址,地址唯一標識一塊內(nèi)存空間。
  2. 指針的大小是固定的4/8個字節(jié)(32位平臺/64位平臺)。
  3. 指針是有類型,指針的類型決定了指針的+-
  4. 整數(shù)的步長,指針解引用操作的時候的權(quán)限。
  5. 指針的運算。

本章重點
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ù)組str1str2不相同,因為str1str2是數(shù)組名,而數(shù)組名就是第一個數(shù)組的地址。str1str2分別開辟了兩個數(shù)組空間,只不過它們存放的內(nèi)容一樣而已!
str3str4它們都是指向的同一塊空間,因為它們指向的是字符串常量hello world.

這里str3str4指向的是一個同一個常量字符串。C/C++會把常量字符串存儲到多帶帶的一個內(nèi)存區(qū)域,
當幾個指針。指向同一個字符串的時候,他們實際會指向同一塊內(nèi)存。但是用相同的常量字符串去初始化不同的數(shù)組的時候就會開辟出不同的內(nèi)存塊。所以str1str2不同,str3str4不同。

數(shù)組指針

數(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

數(shù)組指針的使用

#includeint main(){	int arr[4] = { 1,2,3,4 };	int(*parr)[4] = &arr;  //數(shù)組指針存放數(shù)組arr的地址!	return 0;}

大家肯定很少見代碼這么寫吧,數(shù)組指針很少這樣使用!
我們已經(jīng)知道了數(shù)組名就是,數(shù)組的首元素地址,而取地址數(shù)組名是數(shù)組的地址 。
&arrarr有啥區(qū)別呢?

#includeint main(){	int arr[4] = { 1,2,3,4 };	int(*parr)[4] = &arr;  	printf("arr :%p/n",arr);	printf("&arr:%p/n", &arr);	return 0;}

居然都是第一個元素的地址!
但是我們知道,指針的類型決定了指針加減的步長!

#includeint 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ù),那函數(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);}

二維數(shù)組傳參

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ù)?

其實和上面一樣,你們可以思考一下!

函數(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ù)....)

#includeint 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ù)組

數(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

相關(guān)文章

  • C語言------(8道)試題全面解析

    摘要:因為指針指向的是整個數(shù)組,所以它的類型是數(shù)組指針,所以我們在它的前面進行強制類型轉(zhuǎn)換,把它轉(zhuǎn)換為類型,然后再存放到指針變量內(nèi)部。 前言 通過8道指針筆試題的解析,可以充分的復(fù)習(xí)到指針的相關(guān)知識,并且題目中會結(jié)合許多之前的相關(guān)知識,希望通過本篇文章,對大家所學(xué)的知識進行一個復(fù)習(xí)。 提示:以下...

    vspiders 評論0 收藏0
  • 4道經(jīng)典試題講解 ~

    摘要:結(jié)尾有關(guān)這四道經(jīng)典的指針筆試題講解就到此結(jié)束了,如果覺得文章對自己有所幫助,歡迎大家多多點贊收藏 ?前言 : 今天博主來講解4道經(jīng)典的指針筆試題,很多朋友沒有深刻理...

    tianren124 評論0 收藏0
  • C語言進階:進階續(xù)

    摘要:故使用無具體類型,又稱通用類型,即可以接收任意類型的指針,但是無法進行指針運算解引用,整數(shù)等。求指針所占字節(jié)而不是解引用訪問權(quán)限大小。數(shù)組就是整個數(shù)組的大小,數(shù)組元素則是數(shù)組元素的大小,指針大小都為。 ...

    ingood 評論0 收藏0
  • 不要認為學(xué)PHP就不需要學(xué)C語言

    摘要:之所以這樣說不要認為學(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里...

    KoreyLee 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<