指針---進階篇(二)
- 前言
- 一、函數指針
- 1.拋磚引玉
- 2.如何判斷函數指針?(方法總結)
- 二、函數指針數組
- 1.什么是函數指針數組?
- 2.講解函數指針數組
- 3.模擬計算器:講解函數指針數組
- 三、指向函數指針數組的指針
- 四、回調函數
- 五、qsort排序
前言
那么好了好了,寶子們,從今天開始開始總結暑假博客,從指針開始,后續,來吧開始整活!??
一、函數指針
1.拋磚引玉
直接上代碼:
//拋磚引玉
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}
我打印的是函數的地址。但是如果我們想要把函數的地址保存起來,我們該怎么樣操作呢?
void test()
{printf("hehe\n");
}
//下面pfun1和pfun2哪個有能力存放test函數的地址?
void (*pfun1)();
void *pfun2();
在這里我們需要明白一點,當時我們學數組的時候,我們知道數組名就是數組首元素的地址,在這里函數也是一樣的,函數名也可以代表函數的首元素地址!
首先,能給存儲地址,就要求pfun1或者pfun2是指針,那哪個是指針?前面的進階一里面我們講過了:數組指針。我們呢可以類比一下
答案是:pfun1可以存放。pfun1先和*結合,說明pfun1是指針,指針指向的是一個函數,指向的函數無參數,返回值類型為void。
2.如何判斷函數指針?(方法總結)
比如說下面這段代碼:
int add(int x, int y)//加法
{return x + y;
}int main()
{int (*pf)(int, int) = add;int m = add(3, 4);int n = pf(4, 5);printf("%d %d\n", m, n);return 0;
}
在這里我來教一下大家怎樣判別,什么是函數指針,指針函數,數組指針,指針數組之類的。
就以這個為例:int (*pf)(int,int)=add;
在這個語句里面變量是pf,pf被一個小括號擴住,pf先與 *結合,所以說它以指針結尾。首先分析完了他是一個指針,然后他是什么類型的指針呢?后面是參數,兩個參數類型都是int,前面是返回類型也是int,所以說它是一個標標準準的函數指針。
(在這里一個規律就是:變量和XX先結合就以XX為結尾)
二、函數指針數組
1.什么是函數指針數組?
首先我們要明白什么是數組?
數組的概念是:數組是一個儲存相同元素的集合。
不要害怕他前面這么復雜。又是函數,又是指針,又是數組,我們該如何判斷呢?還是運用我上面的規律總結。
2.講解函數指針數組
好的,我們現在直接上栗子:
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 (*jia)(int, int) = add;int (*jian)(int, int) = sub;int (*cheng)(int, int) = mul;int (*chu)(int, int) = div;int (*pfarr[4])(int, int) = { add,sub,mul,div };//上面的數字里面儲存的都是各個函數名,所以就是儲存的函數的地址return 0;
}
我們來分析一下這個 函數指針數組:
int (*pfarr[4])(int, int) = { add,sub,mul,div };
看這樣復雜的語句的時候,我們先看變量名,變量名是pfarr,先看變量名與誰先結合,由于這里的方括號[ ]的結合度比 *高,所以pfarr先與方括號[ ]結合,所以說它就是以數組來結尾的。
只要你有幾個函數,并且函數的返回類型都是一模一樣的,你就可以把這幾個函數的地址放在一個數組里面,那么這個數組就叫做函數指針數組!
如何寫一個函數指針數字呢?那當然是從函數指針來寫起,然后再加一個數組
3.模擬計算器:講解函數指針數組
1.常規的使用普通函數來實現
#include <stdio.h>
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 a / b;
}//常規的使用普通函數來實現
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf("*************************\n");printf("請選擇:");scanf("%d", &input);switch (input){case 1:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("選擇錯誤\n");break;}} while (input);return 0;
}
2.函數指針數組實現
#include <stdio.h>
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 a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //轉移表while (input){printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf("*************************\n");printf("請選擇:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("輸入操作數:");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);}elseprintf("輸入有誤\n");printf("ret = %d\n", ret);}return 0;
}
三、指向函數指針數組的指針
何為指向函數指針數組的指針?簡單的來講就是函數指針數組的地址
指向函數指針數組的指針是一個 指針 指針指向一個 數組 ,數組的元素都是 函數指針 ;
上代碼:
#define _CRT_SECURE_NO_WARNINGS 1
void test(const char* str)
{printf("%s\n", str);
}
int main()
{//函數指針pfunvoid (*pfun)(const char*) = test;//函數指針的數組pfunArrvoid (*pfunArr[5])(const char* str);pfunArr[0] = test;//指向函數指針數組pfunArr的指針ppfunArrvoid (*(*ppfunArr)[10])(const char*) = &pfunArr;return 0;
}
四、回調函數
回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。
五、qsort排序
接下來我通過用qsort排序來展示一下回調函數的魅力:
#include <stdio.h>
//qosrt函數的使用者得實現一個比較函數
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}
使用回調函數,模擬實現qsort(采用冒泡的方式)。
注意:這里第一次使用 void* 的指針,講解 void* 的作用。
#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };//char *arr[] = {"aaaa","dddd","cccc","bbbb"};int i = 0;bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}
好了,今天的分享就到這里了
如果對你有幫助,記得點贊👍+關注哦!
我的主頁還有其他文章,歡迎學習指點。關注我,讓我們一起學習,一起成長吧!
?
?