前言:
强化数组指针的理解:
在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;
}