1. 首先,在C語言中函數是一種function-to-pointer的方式,即對於一個函數,會將其自動轉換成指針的類型.
代碼如下:
#include<stdio.h>
void fun()
{
}
int main(void)
{
printf("%p %p %p\n", &fun, fun, *fun);
return 0;
}
-------------------------------------------------------------------------------------------
這三個值的結果是一樣的. 其實對於最後的那個*fun, 即使前面加上很多個*號, 其結果也不變, 即**fun, ***fun的結果都是一樣的.
對於這個問題, 因為之前講過函數是一種function-to-pointer方式, 其會自動轉換成指針的類型, &fun是該函數的地址, 為指針類型, fun是一個函數, 會轉換成其指針類型, 而對於*fun, 由於fun已經變成了指針類型, 指向這個函數, 所以*fun就是取這個地址的函數, 而又根據function-to-pointer, 該函數也轉變成了一個指針, 所以以此類推, 這三個值的結果是相同的.
===================================================
2. 如何調用一個地址上的函數
如果知道了一個函數所在的地址, 可以將其強制轉化成某一種類型的函數指針, 然後再根據這個指針去調用這個地址的函數. 如:
代碼如下:
#include<stdio.h>
void f(int i)
{
printf("i = %d\n", i);
}
int main(void)
{
unsigned long add;
add = (unsigned long)f;
((void (*)(int))add)(10);
(*(void (*)(int))add)(20);
return 0;
}
---------------------------------------------------------------------------------------
使用(void (*)(int))的方式可以將一個地址轉換成一個帶int參數且沒有返回值的函數的指針類型, 然後再去調用, 由於第1點中講的function-to-pointer, 所以最後兩條語句中加與不加那個*號效果都是一樣的. 在嵌入式方面經常用到這種方式.
=====================================================
3. 函數指針數組的用法.
有時候需要定義一個數組, 其內容為一系列的函數指針, 然後對其進行調用, 如:
代碼如下:
#include<stdio.h>
int max(int v1, int v2)
{
return (v1 > v2 ? v1 : v2);
}
int min(int v1, int v2)
{
return (v1 < v2 ? v1 : v2);
}
int sum(int v1, int v2)
{
return (v1 + v2);
}
代碼如下:
int main(void)
{
int (*p[3])(int, int);
p[0] = max;
p[1] = min;
p[2] = sum;
printf("p[0] = %d\n", (p[0])(3, 5));
printf("p[1] = %d\n", (p[1])(4, 6));
printf("p[2] = %d\n", (p[2])(1, 2));
return 0;
}
-----------------------------------------------------------------------------------------
雖然感覺這種方法有點累贅, 但是也算是一種使用的方式, 所以介紹一下.
============================================
4.返回一個指向數組的指針的方式
可以讓函數返回一個指向數組的一個指針, 如:
代碼如下:
#include<stdio.h>
#include<stdlib.h>
int (*p())[10]
{
int (*m)[10];
int i;
m = (int (*)[10])malloc(10 * sizeof(int));
if (m == NULL) {
printf("malloc error\n");
exit(1);
}
for (i = 0; i < 10; i++)
*(*m+i) = i+1;
return m;
}
代碼如下:
int main(void)
{
int (*a)[10];
int i;
a = p();
for (i = 0; i < 10; i++)
printf("%d ", *(*a+i));
printf("\ndone\n");
return 0;
}
-------------------------------------------------------------------
這種方式中,int (*a)[10]是一個指向一維數組的一個指針, 而p()也是返回一個指向一維數組的一個指針.
===================================================
5.返回一個函數指針的指針
/============================================/
/ 在看到快速排序的例子中使用到返回指針的函數.所以特此查找到這篇文章,覺得很好... /
/============================================/
對這個問題, signal()函數是最好的例子.
void (*signal (int signo, void (*func)(int)))(int);
很多朋友剛開始看這個函數定義的時候是不太懂, 其實可以一步一步地慢慢看, 我以前是這樣分析的, 希望能對大家有用.
int (*p)();
這是一個函數指針, p所指向的函數是一個不帶任何參數, 並且返回值為int的一個函數.
int (*fun())();
這個式子與上面式子的區別在於用fun()代替了p,而fun()是一個函數,所以說就可以看成是fun()這個函數執行之後,它的返回值是一個函數指針,這個函數指針(其實就是上面的p)所指向的函數是一個不帶任何參數,並且返回值為int的一個函數.
所以說signal()可以看成是signal()函數(它自己是帶兩個參數,一個為整型,一個為函數指針的函數), 而這個signal()函數的返回值也為一個函數指針,這個函數指針指向一個帶一個整型參數,並且返回值為void的一個函數.
=================================
signal函數返回的其實是指向以前的信號處理程序的指針, 所以舉一個例子來說明返回指向函數的指針的用法.
代碼如下:
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
void sig_fun2(int signo)
{
printf("in sig_fun2:%d\n", signo);
}
void sig_fun1(int signo)
{
printf("in sig_fun1:%d\n", signo);
}
int main(void)
{
unsigned long i;
if (signal(SIGUSR1, sig_fun1) == SIG_ERR) {
printf("signal fun1 error\n");
exit(1);
}
(signal(SIGUSR1, sig_fun2))(30);
printf("done\n");
return 0;
}
====================================================
6. 使用函數指針作為參數的情況 (以前的記錄提到過.)
在函數的參數中, 可能會帶有一個函數指針, 這在signal()函數中是出現了的.
其實在很多排序函數中就是使用的這個參數為函數指針的方式來進行調用的.比如Quicksort
例如:
代碼如下:
#include<stdio.h>
int max(int v1, int v2)
{
return (v1 > v2 ? v1 : v2);
}
int min(int v1, int v2)
{
return (v1 < v2 ? v1 : v2);
}
int sum(int v1, int v2)
{
return (v1 + v2);
}
int fun(int a, int b, int (*call)(int, int))
{
return (call(a, b));
}
int main(void)
{
printf("max=%d\n", fun(1, 2, max));
printf("min=%d\n", fun(3, 4, min));
printf("sum=%d\n", fun(5, 6, sum));
return 0;
}