C語言學習之七——指針_4_函數

!!!注意:因為簡書的顯示格式緣故,所以“ * ”顯示會出現問題,可能有些星號由于疏忽未改動格式,造成沒有顯示,請多多包含,如有錯誤,請留言或聯系本人更正,謝謝!

  1. 指向函數的指針簡介
    函數指針變量:指的是存儲一個指向函數的指針的變量。因為函數在編譯時會被分配一個入口地址,而這個入口地址即為函數的指針。見例1.

//例1
/#include<stdio.h>
int max(int x, int y)
{
int z;
if( x > y )
{
z = x;
}
else
{
z = y;
}

return z;
}
void main()
{
int max(int, int);
int (p)();
int a, b, c;
p = max;
scanf("%d %d", &a, &b);
c = (
p)(a, b);
printf("a = %d, b = %d, max = %d\n\n", a, b, c);
}
//輸入:55 66
//輸出:a = 55, b = 66, max = 66

  1. 用函數指針作函數參數
    函數指針變量常用的用途之一是把指針作為參數傳遞到其他函數。(這里指針的作用就是作為一個實參被傳遞到其他函數中使用,其實質就是實現函數的嵌套作用,當然傳遞的只是函數的地址,然后通過地址再調用該函數。)
    例題1:設一個函數process,在調用它的時候,每次實現不同的功能。輸入a和b兩個數,第一次調用process時找出a和b中大者,第二次找出其中小者,第三次求a與b之和。

//例題1,方法1
/#include <stdio.h>
void main()
{
int max(int, int); /* 函數聲明 /
int min(int, int); /
函數聲明 /
int add(int, int); /
函數聲明 */

void process( int, int, int(fun)() ); / 函數聲明 */

int a, b;
printf("Endter a and b: ");
scanf("%d %d", &a, &b);

printf("max = ");
process(a, b, max);

printf("min = ");
process(a, b, min);

printf("sum = ");
process(a, b, add);
}

int max(int x, int y) /* 函數定義 */
{
return x > y ? x : y;
}

int min(int x, int y) /* 函數定義 */
{
return x < y ? x : y;
}

int add(int x, int y)
{
return x + y;
}

void process( int x, int y, int(fun)() ) / 函數定義 /
{
int result;
result = (
fun)(x, y);
printf("%d\n", result);
}
//Endter a and b: 6 9
//max = 9
min = 6
sum = 15
(這里實現了兩層嵌套,主函數3次調用process函數,再process函數分別調用max,min,add函數)

//例題1,方法2
/#include<stdio.h>
void main()
{
int a, b, ma, mi, su;
int (p1)(), (p2)(), (p3)();
int max(int, int), min(int, int), sum(int, int);
p1 = max, p2 = min, p3 = sum;
printf("Please input two numbers: \n");
scanf("%d%d", &a, &b);
ma = (
p1)(a, b), mi = (p2)(a, b), su = (p3)(a, b);
printf("The maximum number is: %d\n", ma);
printf("The minimum number is: %d\n", mi);
printf("The sum is: %d\n", su);
}

int max(int x, int y)
{
return x > y ? x : y;
}

int min(int x, int y)
{
return x < y ? x : y;
}

int sum(int x, int y)
{
return x + y;
}
//Please input two numbers: 6 9
The maximum number is: 9
The minimum number is: 6
The sum is: 15
(這里實現一層嵌套,即主函數分別調用max,min,sum函數進行計算)

  1. 返回指針值的函數
    函數可以返回指針型的數據,即指針(地址)。
    返回指針值的函數的一般定義形式:類型名 *函數名(參數列表); (例 int *function(int x, int y);)
    例題2:有若干個學生的成績(每個學生有4門課程),要求在用戶輸入學生序號以后,能輸出該學生的全部成績。

//例題2
/#include<stdio.h>
void main()
{
double score[][4] = {{60.0, 70.0, 80.5, 90.5}, {56.0, 89.0, 67.0, 88.0}, {34.2, 78.5, 90.5, 66.0}}; //定義數組,并輸入3個學生的成績
double * search(double (*s)[4], int n), *p; //聲明返回指針值的函數search和指針變量p
int num, i;

printf("Please input student Id: ");
scanf("%d", &num);
p = search(score, num); /* 調用函數search,并將返回的指針賦值給指針變量p,即p中存儲的 是search函數的返回值。*/
for(i = 0; i < 4; i++)
{
printf("The score is: %5.2f\n", *(p + i));
}
}

double * search(double (*s)[4], int n) //定義返回指針值的函數search
{
double *p;
p = *(s + n);
return p;
}
//Please input student Id: 1
The score is: 56.00
The score is: 89.00
The score is: 67.00
The score is: 88.00

  1. 指針函數和函數指針的區別
    指針函數:指針函數是指帶指針的函數,即本質是一個函數。
    函數指針:函數指針是指向函數的指針變量,因而函數指針本身首先應是指針變量,只不過該指針變量指向函數。

  2. 指針數組和指向指針的指針
    指針數組的概念:一個數組,若其元素均為指針類型數據,稱為指針數組,也就是說,指針數組中的每一個元素都相當于一個指針變量。
    一維指針數組的定義形式為:類型名 *數組名[數組長度]; (例:int *name[4];) 見例2,例3.

//例2
/#include <stdio.h>

void main()
{
int a[5] = {1, 3, 5, 7, 9};
int name[5] = {&a[0], &a[1], &a[2], &a[3], &a[4]}; / 定義指針數組name,并將數組a 的各個元素的地址賦給指針數組 name,即name其實也是一個數組, 只不過其數組元素存儲的數值是其 他數組元素的地址。*/
int i;
for( i=0; i < 5; i++ )
{
printf("%d ", *name[i]);
}
printf("\n");
}
//輸出:1 3 5 7 9

//例3
/#include<stdio.h>
void main()
{
char name[]={"This is the first semester.", "I studied in UNSW.","C language.","I dno't know!","Thank you!"}; //定義一個指針數組name,里面存儲的是5個字符串的首地址
int i;
for (i = 0; i < 5; i++)
{
printf("%s\n", name[i]); /
通過找出指針數組name中各元素存儲的字符串地址來,輸出 字符串*/
}
}

  1. 指向指針的指針
    定義一個指向指針數據的指針變量一般形式: char * * p;
    解釋:這里p的前面有兩個" * "號。運算符的結合性是從右到左,因此 * * p相當于 * ( * p),顯然 * p是指針變量的定義形式。如果沒有最前面的" * " (即,只是“ * p”),那就是定義了一個指向字符數據的指針變量。現在它前面又有一個" * "號(即“ * p”),表示指針變量p是指向 * p的。 * p就是指向那個指向存儲字符數據值的變量(i)的地址(&i)的指針。見例4,例5,例6.

//例4.
/#include<stdio.h>

void main()
{
int i = 5, j =6, k = 7;
int *p1 = &i, *p2 = &j;
int **ip;

      //p1 = &i, p2 =&j;  // 與int *p1 = &i, *p2 = &j 等價

* ip = p1;    /* *ip = &*p1;也可行,&*p1就等價于i的地址;當然也可以在定義指向指針指針的變量ip時,將p1的地址賦給**ip,即“int **ip = &p1;”。我們可以理解為,1)*ip中存儲的是p1的地址,ip中存儲的是*ip的地址,由于指針的符號優先級是右結合的,所以我們先算“*ip”,變量“ip”通過“*”得到變量“*ip”的地址(由此可以說明變量“ip”中存儲的是變量“*ip”的地址),然后變量“*ip”后通過“*”得到p1(即i的地址)(由此可以說明變量“*ip”中存儲的是變量“i”的地址),最后變量“**ip”通過“*”得到*p1所指向的值(即i的值)。注意,這一步我們還看不出“int **ip = &p1;”與“*ip = p1;或*ip = &*p1;”的區別,這里起的作用是相同的 。不同處,請看例5*/

printf(" * p1: %o\n", * p1);
printf(" * p2: %o\n", * p2);
printf(" * * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("&* ip: %o\n", &* ip);
printf("ip: %o\n", ip);
}
//輸出:p1: 5
// * p2: 6 // p1,p2指向的是i,j存儲的值(“
”取值操作符)
** ip: 5 // ip指向的是i存儲的值5
&i: 15744334504
&j: 15744334510 //&i,&j指代的是i,j的地址 (“
”取地址操作符)
p1: 15744334504
p2: 15744334510 //p1,p2內存單元中分別存儲的是i,j的地址
// * ip: 15744334504 /
ip中存儲的是i的地址,因為這里“ip = p1;”將p1賦給*ip,而p1中存儲的是i的地址 /
& * ip: 15744334520
ip: 15744334520 //這個就是
ip的地址。

例4

//例5
/#include<stdio.h>

void main()
{
int i = 5, j =6, k = 7;
int * p1 = &i, * p2 = &j;
int * * ip = &p1; //這里直接將&p1賦給* * ip,即將p1賦給* ip(就是將i的地址賦給* ip,由此說明* ip就是p1)

printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);

printf("http://///////////////////////////////////\n");

// * ip = p2; //注意這里,由定義“int ip = &p1;”可得,“ip”表示的是變量“p1”,而變量“p1”指向的是變量i”(即“p1”的內存單元中存儲的是變量“i”的地址)。然而我們這里將“p2”賦給“ip”,而變量“p2”指向的是變量“j”。因此,“ip”所指向的變量改變了,即p1所指向的變量改變了,即p1指向了p2所指向的變量(然而如果后面指針變量p2所向的變量改變,p1并不隨p2改變,這與Python有很大的不同,見例6)//
printf("
p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);
}
//輸出:* p1: 5
*p2: 6
**ip: 5
&i: 36752415064 //地址
&j: 36752415070
p1: 36752415064
p2: 36752415070
// * ip: 36752415064
ip: 36752415100
& * ip: 36752415100
/////////////////////////////////////
*p1: 6
*p2: 6
**ip: 6
&i: 36752415064
&j: 36752415070
p1: 36752415070
p2: 36752415070
// * ip: 36752415070
ip: 36752415100
& * ip: 36752415100

例5

//例6
/#include<stdio.h>

void main()
{
int i = 5, j =6, k = 7;
int *p1, *p2;
int **ip = &p1;
p1 = &i, p2 =&j;

printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);

printf("http://///////////////////////////////////\n");

// * ip = p2;
printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);

printf("http:///////////////////////////////////////\n");
p2 = &k;
printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("&k: %o\n", &k);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);
}
//輸出:*p1: 5
*p2: 6
**ip: 5
&i: 733256244 //地址
&j: 733256250
p1: 733256244
p2: 733256250
// * ip: 733256244
ip: 733256260
& * ip: 733256260
/////////////////////////////////////
*p1: 6
*p2: 6
**ip: 6
&i: 733256244
&j: 733256250
p1: 733256250
p2: 733256250
// * ip: 733256250
ip: 733256260
& * ip: 733256260
///////////////////////////////////////
*p1: 6
*p2: 7
**ip: 6
&i: 733256244
&j: 733256250
&k: 733256254
p1: 733256250
p2: 733256254
// * ip: 733256250
ip: 733256260
& * ip: 733256260

  1. 指針數組作main函數的形參
    指針數組的一個重要應用是作為main函數的形參。在以往的程序中,main函數的第一行一般寫成這個形式:void main(); 實際上,main函數可以有參數,如:void main(int argc, char *argv[ ])。這里argc和argv就是main函數的形參。顯然不可能在程序中得到。實際上實參是和命令一起給出的。也就是在一個命令行中包括命令名和需要傳給main函數的參數。見例7.

//例7
/#include <stdio.h>
/#include <stdlib.h>

void main (int argc, char *argv[])
{
int i;

printf ("the number of argc is : %d\n", argc);
argc += 1;

for(i=1; i < argc; i++)
{
printf ("the argc of %d is : %s\n", i, argv[i]);
}
}
//the number of argc is : 1
the argc of 1 is : null

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內容