指针与数组中的难点剖析
1. 指针数组
指针数组可以说成是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占四个字节。
首先先定义一个指针数组,既然是数组,名字就叫arr
char* arr[]={"hello","world","fun","abcd"};
arr就是我定义的一个指针数组,它有四个元素,每个元素是一个char *类型的指针,这些指针存放着其对应字符串的首地址。
使用:
指针数组常用在主函数传参,在写主函数时,参数有两个,一个确定参数个数,一个这是指针数组用来接收每个参数(字符串)的地址。
int main(int argc, char *argv[]);
此时可以想象内存映像图,主函数的栈区有一个叫argv的数组,这个数组的元素是你输入的参数的地址,指向着只读数据区。
如果是向子函数传参,这和传递一个普通数组的思想一样,不能传递整个数组过去,如果数组很大,这样内存利用率很低,所以应该传递数组的首地址,用一个指针接收这个地址。因此,指针数组对应着二级指针。
void fun(char** p)//实参是指针的地址,那用二级指针很合理
{
}
int main()
{
char* arr[4];
fun(arr) //实参为指针数组的首地址,是指针的地址
}
2. 数组指针
数组指针可以说成是”数组的指针”,首先这个变量是一个指针,其次,”数组”修饰这个指针,意思是说这个指针存放着一个数组的首地址,或者说这个指针指向一个数组的首地址。
我们来定义一个数组指针,既然是指针,我们就叫pa
char(* pa)[4];
pa是一个指针指向一个char [4]的数组,每个数组元素是一个char类型的变量,所以我们不妨可以写成:char[4] (*pa);这样就可以直观的看出pa的指向的类型,不过在编辑器中不要这么写,因为编译器根本不认识,这样写只是帮助我们理解。
指针数组和数组指针的区别:
指针数组和数组指针写法十分相似。指针数组char* arr[4]中只是因为[ ]的比较级高于,所以arr和[ ]结合为arr[ ],是数组,而char*则是他的元素类型;数组指针char(* pa)[4]中必须让pa先和*结合成*pa代表这是一个指针,而剩下的部分代表这个指针是指向一个数组的。
3. 函数指针
void (*pfun)( )
这就是一个函数指针,其作用就是存储函数的地址。pfun因为()的优先级高于*,所以给*pfun加括号,说明pfun是一个指针,指向的函数无参数,返回值为void。
看两段有趣的代码:
( * ( void ( * ) ( ) ) 0 ) ( );
void (*signal(int,void(*)(int)))(int);
4. 函数指针数组
定义:
把函数的地址存到一个数组中,这个数组就叫函数指针数组。
int (*parr[10])( );
parr 先和 [ ] 结合,说明parr是数组,数组的元素是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 ret = 0;
int input = 1;
int(*arr[])(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 = (*arr[input])(x, y);
}
else
printf("操作有误");
printf("ret=%d\n", ret);
}
return 0;
}
运行结果:
5. 指向函数指针数组的指针
指向函数指针数组的指针值一个指针,指针指向一个数组,数组的元素都是函数指针;
定义:
void (*(*pfunArr)[10])(const char*)==&pfunArr
函数指针的应用:回调函数
使用回调函数,模拟模拟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 = 0; i < size; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
void bubble_sort(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 - 1 - i; 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, 5, 6, 7, 8, 0 };
int i = 0;
bubble_sort(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;
}
运行结果: