指针数组
指针数组,顾名思义是一个数组,是一个用来存放指针的数组,数组里可以是整形,浮点型,当然也可以是指针类型.
int *arr1[3];
char *arr2[3];
char **arr3[1][2];
数组指针
数组指针是一个指针,有能力指向一个数组
int (*p)arr[3];//p先和*结合,说明p是一个指针,指向一个大小为3的整形数组,[]的优先级要高于*,所以要加上()保证*先与p结合
我们先来看一段代码
int arr[3] = {0};
printf("%p\n", arr);
printf("%p\n", arr + 1);
printf("%p\n", &arr + 1);
这产生的结果是截然不同的,数组首元素的地址和数组的地址的值是相同的,但是意义是不同的,给arr+1,是加上一个元素的大小,给&arr+1,是加上整个数组的大小.
这样为了区分普通元素的地址与整个数组的地址,就需要数组指针来保存整个数组的地址.
int arr[3] = { 0 };
int (*pi)arr[3] = &arr;
数组和指针传参
一维数组传参
#include<stdio.h>
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int *arr)
{}
void test2(int *arr[10])
{}
void test2(int **arr)
{}
int main()
{
int arr[10] = {0};
int *arr2[10] = {0};//指针数组
test(arr);
test2(arr2);
return 0;
}
任何数组传参,都会降维成指向其内部元素的指针.
二维数组传参
void test(int arr[3][5])
{}
void test(int arr[][5])//二维或多维数组传参,第一个[]中的数字可以省略,其他数字绝对不能省略
{}
void test(int **arr)
{}
void test(int (*arr)[5])//数组指针
{}
int main()
{
int arr[3][5] = {0};
test(arr);
return 0;
}
一级指针传参
#include<stdio.h>
void print(int *p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d\n", *(p + i));
}
}
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int *p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
print(p, sz);
system("pause");
return 0;
}
当一个函数的参数部分为一级指针的时候,函数能接受一级指针和一维数组
二级指针传参
#include<stdio.h>
void test(int **ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 20;
int *p = &n;
int **pp = &p;
test(pp);
test(&p);
system("pause");
return 0;
}
当函数的参数为二级指针时,可以接受二级指针和指针数组
函数指针
在C程序中,所有变量都有地址,那么函数有没有地址呢
#include<stdio.h>
void test(int **ptr)
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
system("pause");
return 0;
}
函数是有地址的,函数的地址想要保存起来,要怎么保存呢.首先要保存地址,那么就必须是一个指针,这就是函数指针
void (*pfun)();
函数指针数组
数组是一个存放相同数据类型的存储空间,已经知道了指针数组.,那么要把函数的地址存放到一个数组中,那么这个数组就叫做函数指针数组
int (*part[10])()//part先和[]结合,说明prat是一个数组,数组里面存放着函数地址
函数指针数组的用途:转移表
#include<stdio.h>
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;
}
void menu()
{
printf("****************************\n");
printf("*** 1.add 2.sub ***\n");
printf("*** 3.mul 4.div ***\n");
printf("*** 0.exit ***\n");
printf("****************************\n");
}
int main()
{
int input = 0;
int ret = 0;
int x, y;
int(*p[4])(int x, int y) = { add, sub, mul, div };
do
{
menu();
printf("请选择功能->");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入操作数:");
scanf("%d%d", &x, &y);
ret = (*p[input - 1])(x, y);
printf("结果是:%d\n", ret);
}
else if (input != 0)
{
printf("输入值error,请重新输入\n");
}
} while (input);
system("pause");
return 0;
}
指向函数指针数组的指针
指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素是函数指针
回调函数
回调函数就是一个通过函数指针调用的函数,如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应.
使用回调函数,模拟实现qsort
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
int my_int_comp(const void *x, const void *y)
{
if(*(int *)x > *(int *)y)
return 1;
else if(*(int *)x < *(int *)y)
return -1;
else
return 0;
}
int my_char_comp(const void *x, const void *y)
{
if(*(char *)x > *(char *)y)
return 1;
else if(*(char *)x < *(char *)y)
return -1;
else
return 0;
}
void swap(char *dst, char *str,int size)
{
while(size--)
{
*dst ^= *str;
*str ^= *dst;
*dst ^= *str;
dst++,str++;
}
}
void my_qsort(void *base, int x, int size, int (*my_comp)(const void *x, const void *y))
{
int i = 0;
assert(base);
for(i = 0; i < x - 1; i++)
{
int j = 0;
int flag = 0;
for(; j< x - 1 - i; j++)
{
if(my_comp((char *)base + j*size, (char *)base + (j+1)*size) > 0)
{
flag = 1;
swap((char *)base + j*size, (char *)base + (j+1)*size, size);
}
}
if(flag == 0)
break;
}
}
int main()
{
int i = 0;
int arr[] = {1,2,85,6,56,59,1,4,9,659,4,6,93,29,5,32,59};
char brr[] = "ansuxizhxasnjopmxioashubshasaa";
int sz = sizeof(arr)/sizeof(arr[0]);
int num = strlen(brr);
my_qsort(arr, sz, sizeof( int ), my_int_comp);
for(i = 0; i < sz; i++)
{
printf("%d ",arr[i]);
}
printf("\n");
//my_qsort(brr, num, sizeof( char ), my_char_comp);
//printf("%s\n", brr);
return 0;
}