共和國的的建設(shè)者可要好好學(xué)好指針哦!
文章目錄1. 指針就是個(gè)變量,用來存放地址,地址唯一標(biāo)識一塊內(nèi)存空間。
2. 指針的大小是固定的4/8個(gè)字節(jié)(32位平臺(tái)/64位平臺(tái))。
3. 指針是有類型,指針的類型決定了指針的+-整數(shù)的步長,指針解引用操作的時(shí)候的權(quán)限。
4. 不同數(shù)據(jù)類型的指針之間唯一的不同是,指針?biāo)赶虻淖兞炕虺A康臄?shù)據(jù)類型不同。
5. 指針的運(yùn)算。
1、 字符指針在指針的類型中我們知道有一種指針類型為字符指針 char* ;
一般使用:
int main()
{char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
還有一種使用方式如下:
int main()
{const char* pstr = "hello bit.";//這里并不是把一個(gè)字符串放到pstr指針變量里,而是將字符串的首字符的地址放到了pstr中。
printf("%s\n", pstr);
return 0;
}
`直接上題目練習(xí),在題目中深度了解字符指針
//輸出什么?
#includeint main()
{char str1[] = "hello bit.";//————————1
char str2[] = "hello bit.";//————————2
const char *str3 = "hello bit.";//————————3
const char *str4 = "hello bit.";//————————4
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;
}
答案:
分析:1和2分別創(chuàng)建了一個(gè)全新的數(shù)組,再進(jìn)行比較的時(shí)候,操作系統(tǒng)會(huì)對他們的本質(zhì),即首字符地址,進(jìn)行比較,既然是兩個(gè)數(shù)組,那么他們的首字符地址一定不同(雙胞胎都有不同的基因),所以拿1和2進(jìn)行比較的時(shí)候會(huì)輸出“str1 and str2 are not same”
str3是一個(gè)字符指針,指針的本質(zhì)是字符串首字符的地址,str3、str4兩個(gè)指針指向的都是同一個(gè)字符串的首字符的地址,所以str3和str4是相同的。
如何理解?:一家人有一個(gè)共同的家,通過一家三口中的每一個(gè)人我們都能找到這個(gè)家。
所以此時(shí)會(huì)輸出“str3 and str4 are same”
再來一題關(guān)于const的使用的重要性
int main()
{char* pstr= "hello bit.";
*pstr = "666";
printf("%s\n", pstr);
return 0;
}
輸出:
為什么這里我們沒有任何輸出?
分析:字符串首字符的地址首先傳給了pstr,程序繼續(xù)進(jìn)行,走到27行,pstr被更改了,但是指針pstr仍是“h”的地址,內(nèi)容變?yōu)椤?66”,此時(shí)進(jìn)行輸出,操作系統(tǒng)無法判斷出輸出內(nèi)容。
假設(shè)我們使用了const進(jìn)行修飾:
int main()
{const char* pstr= "hello bit.";
*pstr = "666";//————5
printf("%s\n", pstr);
return 0;
}
5處在編譯器里會(huì)有提示,提示表達(dá)式左側(cè)必須為可以修改的標(biāo)量,所以,媽媽再也不用擔(dān)心我的pstr會(huì)被改變了,在實(shí)際中大大增強(qiáng)了安全性、實(shí)用性。
結(jié)論:合理使用const進(jìn)行限制可以減少某些bug的產(chǎn)生。
類比:
整型數(shù)組————存放整形的數(shù)組
字符數(shù)組————存放字符的數(shù)組
得出:
指針數(shù)組————存放指針(地址)的數(shù)組
int* arr1[10]; //整形指針的數(shù)組
char *arr2[4]; //一級字符指針的數(shù)組
char **arr3[5];//二級字符指針的數(shù)組
const char *arr[4]={"EDG","AG","QG","AE"};//字符指針數(shù)組
模擬二重?cái)?shù)組
#includeint arr1[4]={1,2,3,4};
int arr2[4]={2,3,4,5};
int arr3[4]={3,4,5,6};
int arr4[4]={4,5,6,7};
int *arr[4]={arr1,arr2,arr3,arr4};
for(int i=0;i<=4;i++)
{for(int j=0;j<=4;j++)
{printf("%d",arr[i][j]);
//printf("%d",*(arr[i]+j));
}
}
3、 數(shù)組指針
3.1 數(shù)組指針的定義數(shù)組指針是指針?還是數(shù)組?
答案是:指針。
我們已經(jīng)熟悉:
整形指針: int * pint; 能夠指向整形數(shù)據(jù)的指針。
浮點(diǎn)型指針: float * pf; 能夠指向浮點(diǎn)型數(shù)據(jù)的指針。
那數(shù)組指針應(yīng)該是:能夠指向數(shù)組的指針
int*p; //整形指針
float*q;//浮點(diǎn)型指針
int(*b)[];//數(shù)組指針
解釋:p先和*結(jié)合,說明p是一個(gè)指針變量,然后指著指向的是一個(gè)大小為10個(gè)整型的數(shù)組。所以p是一個(gè)
指針,指向一個(gè)數(shù)組,叫數(shù)組指針。
這里要注意:[]的優(yōu)先級要高于*號的,所以必須加上()來保證p先和*結(jié)合。
3.2 &數(shù)組名VS數(shù)組名對于下面的數(shù)組:
int arr[10];
arr 和 &arr 分別是啥?
我們知道arr是數(shù)組名,數(shù)組名表示數(shù)組首元素的地址。
那&arr數(shù)組名到底是啥?
我們看一段代碼:
#includeint main()
{int arr[10] = {0};
printf("%p\n", arr);
printf("%p\n", &arr);
return 0;
}
可見數(shù)組名和&數(shù)組名打印的地址是一樣的。
難道兩個(gè)是一樣的嗎?
我們再看一段代碼:
#includeint main()
{int arr[10] = {0 };
printf("arr = %p\n", arr);
printf("arr = %p\n", arr+1);
printf("&arr= %p\n", arr[0]);
printf("arr+1 = %p\n", arr[0]+1);
printf("&arr+1= %p\n", &arr);
printf("&arr+1= %p\n", &arr+1);
return 0;
}
分析:
根據(jù)上面的代碼我們發(fā)現(xiàn),其實(shí)&arr和arr,雖然值是一樣的,但是意義是不一樣的.
事實(shí)上,&arr表示的是整個(gè)數(shù)組的地址,而arr僅僅表示數(shù)組首元素的地址,因?yàn)?arr表示整個(gè)數(shù)組的地址,所以才有&arr+1跳過整個(gè)數(shù)組的大小
那數(shù)組指針是怎么使用的呢?
既然數(shù)組指針指向的是數(shù)組,那數(shù)組指針中存放的應(yīng)該是數(shù)組的地址。
來樣例:
#includevoid ErWei(int arr[2][3],int m,int n)
{for(int i=0;ifor(int j=0;j printf("%d",arr[i][j]);
}
printf("\n")
}
}
int main()
{int arr[2][3]={1,2,3,4,5,6};
ErWei(arr,2,3);
return 0;
}
4、 數(shù)組傳參和指針傳參
4.1一維數(shù)組傳參1:C語言中,當(dāng)一維數(shù)組做函數(shù)參數(shù)時(shí),編譯器總是把它解析成一個(gè)指向其首元素的指針。
2:實(shí)際傳遞的數(shù)組大小與函數(shù)形參指定的數(shù)組大小沒有關(guān)系。
3:數(shù)組傳參本質(zhì)上傳遞的是數(shù)組首元素的地址。
4:一維數(shù)組傳參可以由:
4.1 一維數(shù)組接受
4.2 一級或二級指針接受
4.3 指針數(shù)組接受
4.2二維數(shù)組傳參二維數(shù)組作為參數(shù)傳遞到函數(shù)有三種方式:
1:直接傳遞
2:指針傳遞,將二維數(shù)組的第一行傳遞
3:利用二級指針進(jìn)行傳遞
如下形式都是允許的:
void test(int arr[3][5])
{}
void test(int arr[][5])
{}
//總結(jié):二維數(shù)組傳參,函數(shù)形參的設(shè)計(jì)只能省略第一個(gè)[]的數(shù)字。
//因?yàn)閷σ粋€(gè)二維數(shù)組,可以不知道有多少行,但是必須知道一行多少元素。
//這樣才方便運(yùn)算
void test(int (*arr)[5])
int main()
{int arr[3][5] = {0};
test(arr);
}
4.3一級指針傳參直接上題目:
當(dāng)一個(gè)函數(shù)的參數(shù)部分為一級指針的時(shí)候,函數(shù)能接收什么參數(shù)?
答案:
1、(地址類)一級指針變量
2、(地址類)一維數(shù)組數(shù)組名
3、(地址類)整型變量
4.4二級指針傳參直接上題目
當(dāng)函數(shù)的參數(shù)為二級指針的時(shí)候,可以接收什么參數(shù)?
答案:(本質(zhì)上都是地址)
1、二級指針變量
2、數(shù)組名
3、一級指針變量地址
5、 函數(shù)指針先推理:
數(shù)組指針:指向數(shù)組的指針
int (*p)[10];
函數(shù)指針:指向函數(shù)的指針
int (*p)(void,void);//p就是一個(gè)存放函數(shù)地址的指針
再看代碼:
#includevoid test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
輸出的是兩個(gè)地址,這兩個(gè)地址是 test 函數(shù)的地址。
結(jié)論:函數(shù)名和&函數(shù)名都是函數(shù)的地址
保存test的方式:
void (*pfun1)()=&test;
寫一個(gè)簡單的函數(shù)指針:
#includevoid Add(int x, int y)
{return x + y;
}
int main()
{int (*pf)(int,int) = &Add;
//int (*pf)(int,int)=Add;
int ret = (*pf)(2, 3);
//int ret=pf(2,3);
printf("%d", ret);
}
《C陷阱和缺陷》中的題目:大家做著玩吧
//分析代碼題目:
//代碼1
(*(void (*)())0)();
//代碼2
void (*signal(int , void(*)(int)))(int);
結(jié)束函數(shù)指針。
6、 函數(shù)指針數(shù)組前面我們已經(jīng)學(xué)習(xí)了函數(shù)指針
int(*p)(void,void);
數(shù)組是一個(gè)存放相同類型數(shù)據(jù)的存儲(chǔ)空間,那要把函數(shù)的地址存到一個(gè)數(shù)組中,那這個(gè)數(shù)組就叫函數(shù)指針數(shù)組
在這里理解起來函數(shù)指針數(shù)組不會(huì)是困難的事情,我們先來瞧瞧函數(shù)指針數(shù)組的樣子:
int (*p[10])(void,void)
p 先和 [] 結(jié)合,說明 p是數(shù)組,數(shù)組的內(nèi)容是什么呢?
是 int (*)() 類型的函數(shù)指針。
函數(shù)指針數(shù)組的用途:轉(zhuǎn)移表
直接給兄弟們上例子:
未使用函數(shù)指針數(shù)組做轉(zhuǎn)移表的計(jì)算器是非常臃腫的:
#includevoid menu()
{printf("***********************************\n");
printf("************1.Add 2.Sub***********\n");
printf("************3.Mul 4.Div***********\n");
printf("************5.exit******************\n");
printf("***********************************\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 ret = 0;
int x, y = 0;
menu();
printf("你要進(jìn)行什么計(jì)算:");
scanf_s("%d", &input);
switch (input)
{case 1:
{ printf("請輸入操作數(shù):");
scanf_s("%d %d", &x, &y);
ret = Add(x, y);
printf("%d\n", ret);
}
break;
case 2:
printf("請輸入操作數(shù):");
scanf_s("%d %d", &x, &y);
ret = Sub(x, y);
printf("%d\n", ret);
break;
case 3:
printf("請輸入操作數(shù):");
scanf_s("%d %d", &x, &y);
ret = Mul(x, y);
printf("%d\n", ret);
break;
case 4:
printf("請輸入操作數(shù):");
scanf_s("%d %d", &x, &y);
ret = Div(x, y);
printf("%d\n", ret);
break;
case 0:
printf("已退出");
default:
printf("請重新輸入");
break;
}
} while (input);
return 0;
}
此時(shí)我們加上函數(shù)指針數(shù)組用作轉(zhuǎn)移表:
#includevoid menu()
{printf("***********************************\n");
printf("************1.Add 2.Sub***********\n");
printf("************3.Mul 4.Div***********\n");
printf("************5.exit******************\n");
printf("***********************************\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;
int ret = 0;
int x, y = 0;
do
{menu();
printf("請選擇功能:");
scanf_s("%d", &input);
if (input >= 0&&input<=4)
{ printf("請輸入操作數(shù):");
scanf_s("%d %d", &x, &y);
int (*pf[5])(int, int) = {NULL,Add,Sub,Mul,Div };
ret = pf[input](x, y);
printf("%d\n", ret);
}
else
{ printf("請重新輸入......\n");
}
} while (input);
}
結(jié)論:代碼2更加簡潔,代碼量更少,功能實(shí)現(xiàn)與1相同,而且2更讓你更加便于后期增加功能。
聽起來比較繞,但理解起來只需要在函數(shù)指針數(shù)組的基礎(chǔ)上再加上一個(gè)指針,如下:
int(*p[10])(int,int);//函數(shù)中指針數(shù)組
int(*(*pp)[10])(int,int);//指向函數(shù)指針數(shù)組的指針
是不是很簡單啊!
8、 回調(diào)函數(shù)先來看看來自維基百科的對回調(diào)(Callback)的解析:
In computer programming, a callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.
再來看看來自Stack Overflow某位大神簡潔明了的表述:
A “callback” is any function that is called by another function which takes the first function as a parameter。 也就是說,函數(shù) F1 調(diào)用函數(shù) F2 的時(shí)候,函數(shù) F1 通過參數(shù)給 函數(shù) F2 傳遞了另外一個(gè)函數(shù) F3 的指針,在函數(shù) F2 執(zhí)行的過程中,函數(shù)F2 調(diào)用了函數(shù) F3,這個(gè)動(dòng)作就叫做回調(diào)(Callback),而先被當(dāng)做指針傳入、后面又被回調(diào)的函數(shù) F3 就是回調(diào)函數(shù)。到此應(yīng)該明白回調(diào)函數(shù)的定義了吧?
機(jī)制
⑴定義一個(gè)回調(diào)函數(shù);
⑵提供函數(shù)實(shí)現(xiàn)的一方在初始化的時(shí)候,將回調(diào)函數(shù)的函數(shù)指針注冊給調(diào)用者;
⑶當(dāng)特定的事件或條件發(fā)生的時(shí)候,調(diào)用者使用函數(shù)指針調(diào)用回調(diào)函數(shù)對事件進(jìn)行處理
實(shí)例:用回調(diào)函數(shù)改進(jìn)基礎(chǔ)版計(jì)算器
#includevoid menu()
{printf("***********************************\n");
printf("************1.Add 2.Sub***********\n");
printf("************3.Mul 4.Div***********\n");
printf("************5.exit******************\n");
printf("***********************************\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 calc (int(*pf)(int, int))
{int ret = 0;
int x = 0;
int y = 0;
printf("請輸入操作數(shù):");
scanf_s("%d %d", &x, &y);
ret = pf(x, y);
printf("%d\n", ret);
}
int main()
{int input = 0;
do
{menu();
printf("你要進(jìn)行什么計(jì)算:");
scanf_s("%d", &input);
switch (input)
{case 1:
calc(Add);
break;
case 2:
calc(Sub);
break;
case 3:
calc(Mul);
break;
case 4:
calc(Div);
break;
case 0:
printf("已退出");
default:
printf("請重新輸入");
break;
}
} while (input);
return 0;
}
回調(diào)函數(shù)結(jié)束。
本期就講到這里。下期見友友們!
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
本文題目:保姆式教學(xué)--指針的進(jìn)階-創(chuàng)新互聯(lián)
網(wǎng)頁網(wǎng)址:http://jinyejixie.com/article42/cshchc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、域名注冊、動(dòng)態(tài)網(wǎng)站、小程序開發(fā)、全網(wǎng)營銷推廣、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容