首先要說(shuō)明的是,在C語(yǔ)言中,()、[]運(yùn)算符的優(yōu)先級(jí)別要高于*指針運(yùn)算符。
因此,下面基于運(yùn)算符優(yōu)先級(jí)來(lái)討論一下C語(yǔ)言中指針用法里很容易混淆的幾種情況:
int *p;//p為指向整型數(shù)據(jù)的指針變量
int *p[4];//p為一個(gè)指針數(shù)組,里面有4個(gè)元素,每個(gè)元素都是一個(gè)指向整型變量的指針。因?yàn)閇]運(yùn)算符的優(yōu)先級(jí)別高,因此p首先與[4]結(jié)合,也就是說(shuō)p是一個(gè)數(shù)組名,接下來(lái)再看該數(shù)組中的元素究竟是什么,從前面的int *可以看出數(shù)組中的元素是指向整型變量的指針。
int (*p)[4];//p是一個(gè)指針,它指向的是一個(gè)含有4個(gè)整型元素的數(shù)組。因?yàn)?)運(yùn)算符優(yōu)先級(jí)別高,因此p先與*結(jié)合,這樣就確定了p肯定是一個(gè)指針,接下來(lái)的工作就是看看究竟p這個(gè)指針指向什么,拋開(*p)不看,假如是int a[4]的話,那大家都會(huì)知道這個(gè)數(shù)組a是一個(gè)包含4個(gè)整型變量元素的一維數(shù)組,因此指針p就是指向這樣一個(gè)數(shù)組——包含4個(gè)整型元素的數(shù)組。
int *p();//p是一個(gè)函數(shù)名稱,該函數(shù)沒(méi)有任何參數(shù),該函數(shù)返回一個(gè)指針,該指針指向一個(gè)整型變量。同樣,先從優(yōu)先級(jí)來(lái)分析,因?yàn)?)的優(yōu)先級(jí)別高,因此p首先與()結(jié)合成p(),因此p就是一個(gè)函數(shù)名字,接下來(lái)再看該函數(shù)的一些特性,比如參數(shù)以及返回值之類的東西。
int (*p)();//p是一個(gè)指針,該指針指向一個(gè)函數(shù),該函數(shù)沒(méi)有參數(shù),且返回一個(gè)整型變量。利用優(yōu)先級(jí)來(lái)分析,p先與*結(jié)合,因此就能夠首先確定出p是一個(gè)指針了,下面再看該指針指向什么東西,就像分析int (*p)[4]一樣,拋開(*p)不看,如果是int fun()的話,就能夠知道這是一個(gè)不帶參數(shù)且返回整型變量的函數(shù),因此指針p就是指向這樣一個(gè)函數(shù)。
好了,有了上面的分析,相信大家對(duì)指針里這幾個(gè)比較容易混淆的用法必然很清楚了,當(dāng)然在指針的使用中還有指向指針的指針,比如int **p;以及指向多維數(shù)組的多重指針,但是相信有了以上基礎(chǔ)之后,只要認(rèn)真分析,肯定就能把問(wèn)題迎刃而解了吧?
下面就來(lái)看一個(gè)稍微復(fù)雜些的指針?lè)矫娴膽?yīng)用:
int (*p(char op))(int, int);
不知道大家是否可以看懂上面這一行中定義的東西,你能告訴我p是什么嗎?呵呵,我先把謎底給大家,讓大家一睹為快,p是一個(gè)函數(shù)名字。下面就來(lái)分析一下:
根據(jù)優(yōu)先級(jí)來(lái)看p會(huì)首先與(char op)結(jié)合,因此p必定是一個(gè)函數(shù)名字,由p來(lái)表征的這個(gè)函數(shù)只含有一個(gè)字符型的參數(shù)op,并且該函數(shù)返回一個(gè)指針,如果是
int *p(char op)的話,大家都會(huì)很清楚的知道該函數(shù)會(huì)返回一個(gè)指針,且該指針會(huì)指向一個(gè)整型變量,但是對(duì)于int (*p(char op))(int, int);而言,p表征的這個(gè)函數(shù)肯定會(huì)返回一個(gè)指針,那么該指針到底會(huì)指向什么東西呢?呵呵,如果給你int (指針哈哈)(int,int),你肯定也會(huì)知道“指針哈哈”是指向一個(gè)函數(shù)的,該函數(shù)還有兩個(gè)整型參數(shù),且返回一個(gè)整型值,那么好了,知道了這一點(diǎn)就應(yīng)該能夠知道這里的p表示的真正含義了吧:p為一個(gè)函數(shù)名字,該函數(shù)帶有一個(gè)char型參數(shù),且返回一個(gè)指向函數(shù)的指針,該指針指向的函數(shù)包含兩個(gè)整型參數(shù)、返回一個(gè)整型變量。哈哈,看懂沒(méi)?
通常情況下,如果遇到類似問(wèn)題時(shí),我們不會(huì)把問(wèn)題一次性搞得如此復(fù)雜,而是會(huì)拆解開來(lái),一般都是先用typedef定義一個(gè)指向函數(shù)的指針,再用它定義好的這個(gè)東東去再定義一個(gè)函數(shù),這個(gè)函數(shù)的返回值就是我們用typedef定義的那個(gè)東東喲,呵呵,請(qǐng)看下面的示例:
// 定義指向這類函數(shù)的指針
typedef int (*FP_CALC)(int, int);
FP_CALC s_calc_func(char op);//聲明一個(gè)函數(shù)
其實(shí),上面的兩行就相當(dāng)于下面的這一行啊:
int (*s_calc_func(char op))(int, int);//完成同樣的功能——聲明一個(gè)函數(shù)
但是如果我們不是來(lái)聲明一個(gè)函數(shù),而是來(lái)定義一個(gè)指向函數(shù)的指針變量時(shí),
如果不用typedef的方式,那么將會(huì)是如下的樣子:
int (*s_fp)(int, int);
這多少讓大家不太容易接受,因?yàn)槲覀兪熘⒊R姷亩x變量的方式是:類型 變量名,如int a;
而上面這種方式定義變量,看似有點(diǎn)像函數(shù)聲明了,呵呵,因此在使用到指向函數(shù)的指針時(shí),通常都先采用typedef的方法來(lái)聲明一個(gè)指向函數(shù)的指針,然后就可以用“類型 變量名”這種方式來(lái)定義了:
typedef int (*FP_CALC)(int, int);
FP_CALC s_fp;//這多好看呀,看得舒服吧?
下面再給出一個(gè)完整的引用,有興趣的讀者可以仔細(xì)研究研究,真的很有趣味:
-----------------------------------------------------------------------------------
typedef的使用中,最麻煩的是指向函數(shù)的指針,如果沒(méi)有下面的函數(shù),你知道下面這個(gè)表達(dá)式的定義以及如何使用它嗎?
int (*s_calc_func(char op))(int, int);
如果不知道,請(qǐng)看下面的程序,里面有比較詳細(xì)的說(shuō)明
// 定義四個(gè)函數(shù)
int add(int, int);
int sub(int, int);
int mul(int, int);
int div(int, int);
// 定義指向這類函數(shù)的指針
typedef int (*FP_CALC)(int, int);
// 我先不介紹,大家能看懂下一行的內(nèi)容嗎?
int (*s_calc_func(char op))(int, int);
// 下一行的內(nèi)容與上一行完全相同,
// 定義一個(gè)函數(shù)calc_func,它根據(jù)操作字符 op 返回指向相應(yīng)的計(jì)算函數(shù)的指針
FP_CALC calc_func(char op);
// 根據(jù) op 返回相應(yīng)的計(jì)算結(jié)果值
int calc(int a, int b, char op);
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return b? a/b : -1;
}
// 這個(gè)函數(shù)的用途與下一個(gè)函數(shù)作業(yè)和調(diào)用方式的完全相同,
// 參數(shù)為op,而不是最后的兩個(gè)整形
int (*s_calc_func(char op)) (int, int)
{
return calc_func(op);
}
FP_CALC calc_func(char op)
{
switch (op)
{
case '+': return add;
case '-': return sub;
case '*': return mul;
case '/': return div;
default:
return NULL;
}
return NULL;
}
int calc(int a, int b, char op)
{
FP_CALC fp = calc_func(op); // 下面是類似的直接定義指向函數(shù)指針變量
// 下面這行是不用typedef,來(lái)實(shí)現(xiàn)指向函數(shù)的指針的例子,麻煩!
int (*s_fp)(int, int) = s_calc_func(op);
// ASSERT(fp == s_fp); // 可以斷言這倆是相等的
if (fp) return fp(a, b);
else return -1;
}
void test_fun()
{
int a = 100, b = 20;
printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));
printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));
printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));
printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));
}
運(yùn)行結(jié)果
calc(100, 20, +) = 120
calc(100, 20, -) = 80
calc(100, 20, *) = 2000
calc(100, 20, /) = 5