指针数组
指针数组是数组,数组中的元素是指针。
例如:char*arr[10]是一个指针数组,数组名先和[]结合首先确定它就是一个数组,再者才是指针。
数组指针
数组指针是指针,指针指向一个数组。
对比int*p[10]和int(*p)[10],q前者是指针数组,数组中每个元素都是一个指向int型的指针,后者是一个数组指针,指向一个大小为10个整型的数组
注意:[]的优先级比要高,所以需要加上括号才可以保证p先和结合。
应用讨论arr和&arr的区别:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr);
printf("%p\n", &arr+1);
system("pause");
return 0;
}
由此可以看出虽然arr和&arr的值是一样的,但是意义不同,&arr代表整个数组,所以+1操作后就跳过一个数组,跳过sizeof(int)*10=40;而arr代表数组首元素的地址,+1操作跳过一个元素,即为sizeof(int)=4.
故数组的地址存放时用数组指针(int(*p)[])最合适,那么数组传参怎么办?
一维数组传参:
void test()
{
int arr[3] = { 0 };
print(arr);
}
void print(int arr[3])//ok
{}
void print(int arr[])//ok
{}
void print(int*arr)//ok
{}
二维数组:
void test()
{
int arr[3][4] = { 0 };
print(arr);
}
void print(int arr[3][4])//ok
{}
void print(int arr[][4])//ok
{}
void print(int(*arr)[4])//ok
{}
void print(int **arr)//ok
{}
以上都可以作为二维数组的参数来传参。
数组指针和指针数组的区别:
1、从定义上来看,数组指针是指针,指向一个数组;指针数组是数组,数组中存放的是指针类型的元素。
2、从内存布局上来看,指针数组所占字节由本身决定,每个元素都是指针,32位系统下都是4个字节;而数组指针他首先是指针才是数组,32位系统下永远是4字节。画图理解:
3、根据对指针内存的认识,可以看一道例题
#include<stdio.h>
int main()
{
struct Test
{
int num;
char* pcname;
short sdate;
char ch[2];
short sb[4];
}*p;
printf("%p\n", p);
//p的值为0x100000求表达式的值
printf("%p\n", p + 0x1);//已知结构体大小为20,指针加一,
//加的是所指向类型的大小,即为0x100000+sizeof(Test)=0x100014
printf("%p\n", (unsigned long)p + 0x1);//类型转换为无符号长整型,
//加一就是加一,为0x100001
printf("%p\n", (unsigned int*)p + 0x1 );//强制类型转换为int*,
//加一就是加sizeof(int*)=0x100004
system("pause");
return 0;
}
函数指针
顾名思义,函数指针就是一个指针,这个指针指向的是函数,
其定义为:int(*f)(int a,int b);//声明函数指针,它定义为一个指向返回值为整型,两个参数都为整型的函数。
#include<stdio.h>
void test()
{
;
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
system("pause");
return 0;
}
打印出来函数的地址:
那么函数的地址又该如何存放?
对比数组指针可以存放数组的地址,那么可以用函数指针来存放函数的地址么?
当然可以。例如
void(*pfun1)();//函数指针,指向函数,保存函数的地址
void *pfun2();//相当于返回值类型为void*的pfun2函数
pfun1可以存放函数的地址,由于pfun1先与*结合说明它是指针,指针指向的是一个无参的返回值为void的函数。
函数指针数组
定义:他是一个数组,数组里存放的是指向函数的函数指针(保存函数的地址)。
随便写一个函数指针数组,如:int(*pfun[])()
理解:数组的内容是int(*)()这个函数指针
应用:写一个计算器实现加减乘除(转移表)
#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 = 0;
int ret = 0;
do
{
printf("**********************\n");
printf("*** 1.add 2.sub****\n");
printf("*** 3.mul 4.div****\n");
printf("**********************\n");
printf("请选择: ");
scanf("%d", &input);
} while (input);
switch (input)
{
case 1:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
break;
case 2:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
break;
case 3:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = mul(x, y);
break;
case 4:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = div(x, y);
break;
default:
printf("输入错误");
break;
}
system("pause");
return 0;
}
使用函数指针数组实现时:
#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);
}
else
{
printf("输入有误\n");
}
printf("%d\n", ret);
}
system("pause");
return 0;
}
指向函数指针数组的指针
函数指针数组为:void(*p[])()
所以指向函数指针数组的指针就可以写成:void(*(*pp)
回调函数
回调函数就是一个通过函数指针调用的函数。如果把函数指针(地址)作为参数传递给另一个函数,当这个指针被用来调用他所指向的函数时,这个函数叫做回调函数,回调函数是在特定的事件或条件下发生的,用于对这事件的响应。
例如:模拟实现qsort(冒泡法)
#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 <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, 2, 3, 4, 7, 8, 4, 5, 3, 21, 0 };
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]);
}
system("pause");
return 0;
}