目錄
創(chuàng)新互聯(lián)是一家專業(yè)提供南樂(lè)企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站制作、成都做網(wǎng)站、H5開(kāi)發(fā)、小程序制作等業(yè)務(wù)。10年已為南樂(lè)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進(jìn)行中。指針數(shù)組
數(shù)組指針
arr與&arr的區(qū)別
數(shù)組指針
1.數(shù)組指針的創(chuàng)建格式:
2.數(shù)組指針的用處
數(shù)組參數(shù),指針參數(shù)
一維數(shù)組傳參
二維數(shù)組傳參(注意事項(xiàng))
一級(jí)指針傳參
二級(jí)指針傳參
函數(shù)指針
函數(shù)指針數(shù)組
函數(shù)指針真正用處用法
指針數(shù)組是指在一組數(shù)中能夠存放多個(gè)相同指針類型的一組數(shù)
指針數(shù)組的書(shū)寫(xiě)格式:
當(dāng)然還可以類比出三級(jí)指針,四級(jí)指針等等等等....
指針的初始化:
如int* arr[5]={0};
在這里我們將數(shù)組arr里的每一個(gè)元素賦了0,也就相當(dāng)于將指針數(shù)組里面的所有元素都變?yōu)榱丝罩羔槪@是因?yàn)樵诰幾g器中,NULL相當(dāng)于0被強(qiáng)制類型轉(zhuǎn)換為了(void*)類型,所以NULL本質(zhì)上就是0。
數(shù)組指針數(shù)組指針是一種指針類型,是一個(gè)指向數(shù)組的指針。
數(shù)組指針的書(shū)寫(xiě)格式:
#includeint main()
{
int arr[5]={0};
char s[5]={0};
int (*p)[5]=&arr;//這個(gè)就是數(shù)組指針的格式,
//也可以用其他類型如char等
char (*b)[5]=&s;
return 0;
}
arr與&arr的區(qū)別創(chuàng)造一個(gè)int型數(shù)組int arr[5]={0}; 我們都知道arr是數(shù)組名,也就是首元素的地址,但&arr表示的是什么?
在編譯器中輸入以下代碼:
#includeint main()
{
int arr[5] = { 0 };
printf("%p\n", arr);
printf("%p\n",arr + 1);
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
return 0;
}
最終輸出結(jié)果如下:
觀察上面的輸出后的圖,我們可以看到arr與&arr的地址是相同的,但arr與&arr其實(shí)是兩個(gè)完全不同的概念。
我們可以看到,arr+1后的地址與arr的地址相差了4,這是因?yàn)閍rr是數(shù)組名,相當(dāng)于存放了數(shù)組首元素的地址,也就是一個(gè)int*類型的指針,所以每加一后都會(huì)直接跳過(guò)四個(gè)字節(jié),讀取到數(shù)組中下一個(gè)元素。而我們?cè)倏聪?arr與&arr+1的地址,經(jīng)過(guò)計(jì)算后得到兩地址相差的數(shù)值大小為20,我們會(huì)發(fā)現(xiàn),這剛好是我們創(chuàng)建數(shù)組的所占的總共空間大?。?0個(gè)字節(jié))。
也就是說(shuō),&arr其實(shí)取到的并不是數(shù)組首元素地址,類型并不為int*指針,而取到的是整個(gè)數(shù)組的地址,類型為數(shù)組指針,所以當(dāng)我們加一的時(shí)候,由于是數(shù)組指針加一,所以會(huì)跳過(guò)20個(gè)字節(jié)。那么數(shù)組指針具體又是什么呢?
數(shù)組指針就像int型會(huì)有int指針,char類型有char指針,數(shù)組也會(huì)有對(duì)應(yīng)的數(shù)組指針,例如int型數(shù)組,數(shù)組指針的書(shū)寫(xiě)格式就為int(*)[],具體用法如下:
數(shù)組指針的應(yīng)用
1.數(shù)組指針的創(chuàng)建格式:Ⅰ:訪問(wèn)一維數(shù)組
#includeint main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*p)[10] = &arr;
int i = 0;
for (i = 0; i< 10; i++)
{
printf("%d ",*((*p) + i));
}
return 0;
}
這里雖然訪問(wèn)一維數(shù)組用這種方法繁冗且不建議使用,但還是做下解釋。
Ⅱ:訪問(wèn)二維數(shù)組
如果要寫(xiě)一個(gè)函數(shù),將遍歷二維數(shù)組將每一個(gè)元素打印出來(lái),我們會(huì)怎么寫(xiě)呢?
在以前會(huì)使用下面的方法:
#includevoid print(int a[3][5], int x, int y)
{
int i = 0;
int j = 0;
for (i = 0; i< x; i++)
{
for (j = 0; j< y; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
print(arr, 3, 5);
return 0;
}
但現(xiàn)在,我們可以用數(shù)組指針的方式來(lái)實(shí)現(xiàn):
#includevoid print(int(*p)[5], int x, int y)
{
int i = 0;
int j = 0;
for (i = 0; i< x; i++)
{
for (j = 0; j< y; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
print(arr, 3, 5);
return 0;
}
在二維數(shù)組中例如arr[3][5],其中的“[3]”所代表的是有3行元素,“[5]”代表的是每行元素有5列。而arr[5]則代表一行的地址
所以當(dāng)我們?cè)趥鲄r(shí),只需要將形參定為int型的指針數(shù)組,先將每一行的地址傳入,就可以實(shí)現(xiàn)遍歷數(shù)組的作用。
再次理解:
#includeint main()
{
int a[10] = { 0 };
int* p = a;
//*(a+i)==*(p+i)==a[i]==p[i]
}
數(shù)組參數(shù),指針參數(shù)
一維數(shù)組傳參看下面代碼,判斷傳參是否正確:
#includevoid test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int *arr)//ok?
{}
void test2(int *arr[20])//ok?
{}
void test2(int **arr)//ok?
{}
int main()
{
int arr[10]={0};
int *arr2[20]={0};
test(arr);
test2(arr2);
return 0;
}
一維數(shù)組傳參經(jīng)驗(yàn)總結(jié):
所以上述代碼中的傳參都是正確的。
二維數(shù)組傳參(注意事項(xiàng))看下面代碼,判斷傳參是否正確:
#includevoid test(int arr[3][5])//ok? ----1
{}
void test(int arr[][])//ok? ----2
{}
void test(int arr[][5])//ok? ----3
{}
void test(int *arr)//ok? ----4
{}
void test(int (*arr)[5])//ok? ----5
{}
void test(int **arr)//ok? ----6
{}
int main()
{
int arr[3][5]={0};
test(arr);
}
二維數(shù)組傳參經(jīng)驗(yàn)總結(jié):
綜上,2,4,6是錯(cuò)誤的傳參形式。
一級(jí)指針傳參Q:當(dāng)函數(shù)的參數(shù)為一級(jí)指針時(shí),函數(shù)能接收什么參數(shù)?
A:可以傳入一個(gè)地址,或數(shù)組名,或直接傳入一個(gè)一級(jí)指針。
二級(jí)指針傳參Q:當(dāng)函數(shù)的參數(shù)為二級(jí)指針時(shí),函數(shù)能接收什么參數(shù)?
A:可以傳入一級(jí)指針的地址、二級(jí)指針、指針數(shù)組的數(shù)組名。
函數(shù)指針函數(shù)不同于數(shù)組,函數(shù)名與在函數(shù)名前加上&本質(zhì)上是沒(méi)有區(qū)別的,下面是函數(shù)指針的一些使用:
#includeint Add(int x, int y)
{
return x + y;
}
void Fun(char x)
{
;
}
int main()
{
//Add與&Add本質(zhì)上沒(méi)有區(qū)別,都表示為同一個(gè)地址
printf("%p\n", Add);
printf("%p\n", &Add);
//函數(shù)指針的創(chuàng)建舉例
int (*p)(int, int) = Add;
int (*pa)(int, int) = &Add;
void (*ppa)(char) = Fun;
//函數(shù)指針的調(diào)用也同函數(shù)名一樣,可以直接用名或者在前面加上解引用符
printf("%p\n", p);
printf("%p\n", *p);
//函數(shù)的調(diào)用
printf("%d\n", Add(1, 2));
printf("%d\n", (&Add)(1, 2));//這里特別注意,要將&Add用小括號(hào)括起來(lái),否則Add就會(huì)先與后面的(1,2)結(jié)合,從而無(wú)法調(diào)用函數(shù)。
printf("%d\n", p(1, 2));
printf("%d\n", (*p)(1, 2));//*p也是先要用小括號(hào)括起來(lái),否則會(huì)與后面的(1,2)結(jié)合,從而無(wú)法調(diào)用函數(shù)得到想得到的結(jié)果。
return 0;
}
特別注意:以上面代碼為例,若要以&Add或者*p這種形式來(lái)使用,要先用小括號(hào)括起來(lái),否則Add/p就會(huì)先與后面的(1,2)結(jié)合,從而無(wú)法調(diào)用函數(shù)。
在學(xué)習(xí)函數(shù)指針時(shí),又偶然發(fā)現(xiàn)了一道很經(jīng)典,非常,特別,詭異的題目:
//請(qǐng)分析下面這段代碼:
(*(void(*)())0)();
??????????????????????????????????????????????????????????????????????????????????????
在剛看到這段代碼時(shí)我的心情如上👆。心想:“魔法,這一定是魔法”。但其實(shí)冷靜思考過(guò)后,最終還是理解了這一段離譜且詭異的代碼:
首先從最里開(kāi)始,void(*)? (),這樣單獨(dú)拆開(kāi)后我們不難發(fā)現(xiàn),這是一個(gè)函數(shù)指針類型,只不過(guò)是一個(gè)void型的函數(shù)且不用傳參,在這整體上再套多一個(gè)小括號(hào)并在后面加上數(shù)字0,變?yōu)?void(*)?()?)0的樣子,這里最外一層的小括號(hào)其實(shí)是強(qiáng)制類型轉(zhuǎn)換符,將0這個(gè)地址上放入一個(gè)函數(shù)指針(也就是放了一個(gè)函數(shù))。而最終變?yōu)椋?(void(*)())0)(),其實(shí)是調(diào)用了0地址上的這個(gè)參數(shù)為無(wú)參,返回類型是void的函數(shù)。所以總結(jié)來(lái)說(shuō),整個(gè)代碼是在調(diào)用0地址處的函數(shù)。
但是?。。。?/p>
當(dāng)我們將上面代碼在編譯器中正式運(yùn)行時(shí)是不可能的,會(huì)出現(xiàn)運(yùn)行中止或報(bào)錯(cuò)或根本不運(yùn)行。這是因?yàn)榈刂?是我們普通用戶禁止被使用的地址,我們是無(wú)法使用的,因?yàn)?地址是開(kāi)機(jī)啟動(dòng)時(shí)才訪問(wèn)的地址。
再來(lái)看一條簡(jiǎn)單一點(diǎn)的代碼(可能)
void (*signal(int,void(*)(int)))(int);
上面代碼要這么看:void(* signal(int,void(*)(int)) )(int);
這樣子就不難看出(應(yīng)該不難)signal(int,void(*)(int))是一個(gè)函數(shù)的聲明,因?yàn)楹瘮?shù)的參數(shù)位置如果是調(diào)用的話,則不應(yīng)該為類型,所以這個(gè)是函數(shù)的聲明,這是一個(gè)函數(shù)名為signal,參數(shù)為int型和函數(shù)指針型的函數(shù),函數(shù)名有了,參數(shù)也有了,現(xiàn)在缺少的就是返回類型,這個(gè)返回的類型便是剩下的→void ( *)(int)。
Tip:在這里要特別注意,*總是要和名字在一起,不可以寫(xiě)為void (?*)(int) signal(int,void(*)(int))的形式
看吧,不難吧(后仰攤手)
什么??還是難???那好吧,下面我們嘗試著簡(jiǎn)化一下這樣的代碼(其實(shí)我也覺(jué)得難)
將void(*)(int)這樣類型的函數(shù)指針類型重命名為pfun_t,這里要用到typedef,但注意?。〔皇菍?xiě)為這樣:typedef void(* )(int) pfun_t。而是要寫(xiě)為:typedef void(* pfun_t)(int) 這里這么寫(xiě)是因?yàn)?總要與名字在一起(上面tip里有說(shuō)過(guò))。
經(jīng)過(guò)函數(shù)指針的重命名后,上面的代碼可以最終簡(jiǎn)化為:
pfun_t signal(int,pfun_t);
按照字面意思,我們可以知道,這是一組存放函數(shù)指針類型元素的數(shù)組。
函數(shù)指針數(shù)組的使用:
#includeint Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int (*arr[5])(int, int) = { Add,Sub,Mul,Div };
int i = 0;
for (i = 0; i< 5; i++)
{
printf("%d\n",arr[i](8, 4));
}
return 0;
}
函數(shù)指針可以利用寫(xiě)一個(gè)函數(shù),使其形參的類型為函數(shù)指針類型,從而達(dá)到一個(gè)函數(shù)可以調(diào)用多個(gè)不同函數(shù)的一個(gè)函數(shù)。
我們先寫(xiě)下下面這樣的一段代碼:
#includevoid Menu()
{
printf("******************************\n");
printf("**** 1.Add 2.Sub ****\n");
printf("**** 3.Mul 4.Div 0.exit ****\n");
printf("******************************\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int input = 0;
do
{
int x = 0;
int y = 0;
Menu();
printf("請(qǐng)輸入你要的操作");
scanf("%d", &input);
switch (input)
{
case 0:
printf("結(jié)束操作\n");
break;
case 1:
printf("請(qǐng)輸入你想要操作的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
printf("%d\n", Add(x, y));
break;
case 2:
printf("請(qǐng)輸入你想要操作的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
printf("%d\n", Sub(x, y));
break;
case 3:
printf("請(qǐng)輸入你想要操作的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
printf("%d\n", Mul(x, y));
break;
case 4:
printf("請(qǐng)輸入你想要操作的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
printf("%d\n", Div(x, y));
break;
default:
printf("輸入錯(cuò)誤,請(qǐng)重新輸入");
break;
}
} while (input);
}
在上面我們會(huì)發(fā)現(xiàn)case1,2,3,4大量代碼是重復(fù)冗余的,且Add,Sub,Mul,Div函數(shù)都是返回的int型,且都有兩個(gè)int型的參數(shù),對(duì)于這種情況,我們可以利用寫(xiě)一個(gè)函數(shù),來(lái)調(diào)用這些形式上差不多相同的函數(shù),能夠做到縮減代碼量的目的,而調(diào)用這些函數(shù)以形參形式傳過(guò)去,就需要用到函數(shù)指針類型。
在這里我們創(chuàng)建一個(gè)Cal函數(shù),其參數(shù)形式為函數(shù)指針型,若以上面函數(shù)來(lái)舉例,則寫(xiě)出如下代碼:
void Cal(int (*fun)(int,int))
{}
然后再將重復(fù)的代碼放入Cal函數(shù)內(nèi)之后刪去,便可以達(dá)到減少重復(fù)代碼的目的了。下面是完整的更改后的代碼:
#includevoid Menu()
{
printf("******************************\n");
printf("**** 1.Add 2.Sub ****\n");
printf("**** 3.Mul 4.Div 0.exit ****\n");
printf("******************************\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
void Cal(int (*fun)(int, int))
{
int x = 0;
int y = 0;
printf("請(qǐng)輸入你想要操作的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
printf("%d\n", fun(x, y));
}
int main()
{
int input = 0;
do
{
Menu();
printf("請(qǐng)輸入你要的操作");
scanf("%d", &input);
switch (input)
{
case 0:
printf("結(jié)束操作\n");
break;
case 1:
Cal(Add);
break;
case 2:
Cal(Sub);
break;
case 3:
Cal(Mul);
break;
case 4:
Cal(Div);
break;
default:
printf("輸入錯(cuò)誤,請(qǐng)重新輸入");
break;
}
} while (input);
}
看起來(lái)比上一種寫(xiě)法干凈整潔了許多。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前名稱:C語(yǔ)言中多種指針相關(guān)類型詳解-創(chuàng)新互聯(lián)
當(dāng)前鏈接:http://m.2m8n56k.cn/article10/cciido.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷推廣、網(wǎng)站設(shè)計(jì)公司、靜態(tài)網(wǎng)站、ChatGPT、微信公眾號(hào)、網(wǎng)頁(yè)設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:[email protected]。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容