前言:
强化数组指针的理解:
在C语言指针详解(2)-CSDN博客中我们模拟实现了一个二维数组,可能大家对其中的原理还有些模糊,这一章开始之前先梳理一遍。
一维数组的模拟实现:
再剖析二维数组之前,先来看看一维数组的模拟实现。
int main() {int arr[] = {1,2,3,4,5,6,7,8,9};int(*a)[9] = &arr;int i = 0;for (i = 0; i < 9; i++){printf("%d ", (*a)[i]);}return 0; }
通过画图理解:
这里解引用a就可以找到数组的首元素。
二维数组的模拟实现:
void Print_arr2(int (*arr2)[4],int a,int b) {int i = 0;for (i = 0; i < a; i++){int j = 0;for (j = 0; j < b; j++){printf("%d", arr2[i][j]);}printf("\n");} } int main() {int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//可以看作是一维数组的数组Print_arr2(arr, 3, 4);//这里传进去arr,相当于传进去的是arr首元素的地址,但是arr是一个二维数组,传进去的是第组一维数组}
当然也可以这样打印我的二维数组:
void Print_arr2(int (*arr2)[4],int a,int b)
{int i = 0;for (i = 0; i < a; i++){int j = 0;for (j = 0; j < b; j++){printf("%d", (*(arr2+i))[j]);//这里做了改动,如果大家理解这里的话也可以,原理和一维数组的打印类似}printf("\n");}
}
int main()
{int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//可以看作是一维数组的数组Print_arr2(arr, 3, 4);//这里传进去arr,相当于传进去的是arr首元素的地址,但是arr是一个二维数组,传进去的是第组一维数组}
函数指针:
这里介绍一下函数指针,函数指针可以指向一个函数,当然函数指针里面存的就是整个函数的地址,例如:
我想实现两个数相加之后得到的数平方。
可以这样写:
#include<stdio.h>
int Add(int a,int b)
{int sum = 0;sum = a + b;return sum;
}
int app(int a, int b, int (*c)(int a, int b))
{return (*c)(a, b) * (*c)(a, b);//调用Add函数
}
int main()
{int a = 0;int b = 12;scanf("%d %d", &a, &b);int c = Add(a,b);printf("%d\n", c);int an = 0;an = app(a, b, Add);//由于我要使用Add函数求和可以把Add函数传进去printf("%d\n", an);return 0;}
这里的 int (*c)(int a,int b)就是函数指针。
解读函数指针int (*c)(int a,int b)
int 表示函数的返回 类型,*表示是指针,c表示这个指针的变量名,后面的()里面的的是函数的形参。
函数的地址这里有两种表示方式:
1、&Add
2、Add
我们可以取出函数的地址放进函数指针中。然后需要的时候直接用函数指针找到函数然后调用。
函数指针数组:
刚刚讲完函数指针后,我们可以把好多个函数指针放在数组中,就有了函数指针数组,里面存的是每个函数的地址。
当需要时候可以取出,(*arr[0])(int ,int )
例如:
int main() {int a = 0;int b = 0;Add(a,b);Mul(a,b);Div(a, b);Sub(a, b);int (*arr[4])(int ,int ) = {Add,Mul,Div,Sub};//函数指针数组里面存放着函数地址 }
函数指针数组实例(计算器)
如下是调用函数可以写出一个计算器。
#include<stdio.h>
void mnue()
{printf("*******************************************\n");printf("********** 1.Add 2.Sub*************\n");printf("********** 3.Mul 4.Div*************\n");printf("********** 0.exit *************\n");printf("*******************************************\n");
}
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 input = 0;do{mnue();printf("请选择需要的计算器<<");scanf("%d", &input);int a = 0;int b = 0;int c = 0;switch (input){case 1:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Add(a,b);printf("%d\n", c);break;case 2:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Sub(a, b);printf("%d\n", c);break;case 3:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Mul(a, b);printf("%d\n", c);break;case 4:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Div(a, b);printf("%d\n", c);break;case 0:printf("退出计算器\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}
这组代码我主要用的是函数的调用,当然如果要把它改成指针取用它该怎么做呢?
我们可以把这些函数的地址放在指针函数数组中!
函数指针数组模拟实现计算机
#include<stdio.h>
void mnue()
{printf("*******************************************\n");printf("********** 1.Add 2.Sub*************\n");printf("********** 3.Mul 4.Div*************\n");printf("********** 0.exit *************\n");printf("*******************************************\n");
}
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 input = 0;do{mnue();printf("请选择需要的计算器<<");scanf("%d", &input);int a = 0;int b = 0;int c = 0;int (*arr[5])(int, int) = { NULL, Add,Sub,Mul,Div };//转移表,函数指针数组//由于选择的时候从1开始,所以再数组前面加一个空指针,if (input == 0){printf("退出计算机\n");}else if(input<=4&&input>=1){printf("请输入你要计算的数字<<");scanf("%d%d", &a, &b);c = (*arr[input])(a, b);printf("%d\n", c);}else{printf("选择错误,请重新选择\n");}} while (input);return 0;
}
这样就可以利用函数指针数组。
函数指针数组,也被叫作是转移表!
使用排序函数qsort
首先再C语言中,库函数中有qsort这样一个函数,这个函数是干什么的呢,通过查看C plusplus可以看到:
分析:
这个函数的返货类型是void,参数有void* base,size_t num,size_t size,int, compar(const void *,const void *)base意思是需要排序的数组的第一个元素的地址。
num,意思是这个数组中有多少个要排序的成员。
size,意思是每个元素的大小。
compar,是个函数,是用作比较两个元素的函数,返回类型是int,需要传进去两个元素的地址,而且这个比较函数需要自己写,因为电脑不知道你是怎么比较的,你得写出来。
第一个类型的值小于第二个返回-1
第一个类型的值等于第二个返回0
蒂耶戈类型的值大于第二个返回1
大于0降序
小于0升序
类型基本上都是void,size_t,原因是你要进行排序,但是不清楚你要排序的元素是什么类型的,有可能是int型,有可能是char类型,也有可能是double,float类型,所以这里传进去的时候类型只能写成void类型。
使用一下qsort函数看看效果:
我想要降序,也就是指向元素如果比第二个大就往前排。
#include<stdlib.h>
int compar(const void*p1,const void *p2)
{return *(int*)p2 - *(int*)p1;//降序
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, 4, compar);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
模拟实现qsort函数
我可以模拟实现qsort函数,我们排序可以用冒泡排序去排序(原函数用的不是冒泡排序)
写my_qsort函数
先来熟悉一下冒泡排序:
int main() {int arr[] = {1,2,3,4,5,6,7,8,9,10};int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz-1; i++){int j = 0;for (j = 0; j < sz - 1 - i; j++){if (arr[j] < arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}return 0; }
需要遍历sz-1次,每次需要比较sz-1-i次。
需要注意事项:
1、写出来的函数因为为参数类型为size_t(无符号整型),返回类型是void,所以在比较的时候,需要注意强转。
2、我们需要写出COM()函数,保证和原函数的compar()的写法一样,返回类型就是int,返回正数,负数,还有0三种情况。
3、还需要写出一个交换的函数,也就是当条件满足时,要进行交换。
代码如下:
void my_qsort(void *base,size_t size,size_t num,int (*com)(void *p1,void *p2))
{int i = 0;for (i = 0; i < (int)num-1; i++){int j = 0;for (j = 0; j < (int)num - 1 - i; j++){if (COM((char*)base + j * size, (char*)base + (j + 1)*size) <0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
写 int COM(void *p1,void *p2)判断函数:
代码如下:
int COM(void *f1,void *f2)
{return *(int*)f1 - *(int*)f2;
}
写void Swap()交换函数:
注意事项:
1、 因为不知道传进去的类型是什么,但是我们可以找到索要交换元素的每个元素的首元素,
2、找到首元素后,我们可以找到一个最小单位,也就是char*类型的只访问1个字节,不论是什么类型,都可以一个字节一个字节交换!
void Swap(char *tuf1,char *tuf2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *tuf1;*tuf1 = *tuf2;*tuf2 = tmp;tuf1++;tuf2++;}
}
完整代码:
int COM(void *f1,void *f2)
{return *(int*)f1 - *(int*)f2;
}
void Swap(char *tuf1,char *tuf2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *tuf1;*tuf1 = *tuf2;*tuf2 = tmp;tuf1++;tuf2++;}
}
void my_qsort(void *base,size_t size,size_t num,int (*com)(void *p1,void *p2))
{int i = 0;for (i = 0; i < (int)num-1; i++){int j = 0;for (j = 0; j < (int)num - 1 - i; j++){if (COM((char*)base + j * size, (char*)base + (j + 1)*size) <0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
void test1(int * arr,int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);my_qsort(arr, 4, sz, COM);test1(arr, sz);return 0;
}