26.指针数组和数组指针和函数指针和指针函数


指针数组 : 存放指针的数组

int main()
{
	int arr[10];
	//整形数组
	int* arr2[5];  
	//(整形)指针数组 -->变量名是arr2类型是 int*  [5]
	return 0;
}

数组指针 :指向数组的指针

int main()
{
	int arr[10] = { 0 };
	int(*pArr)[10] = &arr;  //数组指针,&arr表示整个数组的地址

	char str[5] = { 0 };
	char(*pStr)[5] = &str;  //数组指针,&arr表示整个数组的地址

	return 0;
}

使用一维数组指针

void ArrPrint(int arr[], int num) //(int* arr, int num)
{
	int i = 0;
	for (i = 0; i < num; i++)
	{
		printf("%d ",*(arr + i)); //arr[i]
	}
	printf("\n");
}

void ArrPrint1(int (*PArr)[10], int num)
{
	int i = 0;
	for (i = 0; i < num; i++)
	{
 //printf("%d ",(*parr)[i] ); 
		printf("%d ", *((*parr)+i) );
	}
	printf("\n");
}
int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7 ,8 ,9, 10 };
	int num = sizeof(arr) / sizeof(int);
	ArrPrint(arr, num);   //arr表示数组的首元素地址

	ArrPrint1(&arr, num);
	return 0;
}

使用二维数组指针

void ArrPrint2(int arr[][5], int row, int col) //(int* arr, int num)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			//printf("%d ", arr[i][j]); 
			//printf("%d ", *(arr[i] + j));  
			printf("%d ", *( (*arr + i * col) + j));
		}
	}
	printf("\n");
}

void ArrPrint3(int (*PArr)[5], int row, int col)  //(二维数组指针)指向二维数组的指针定义时只需要写列的[],与一维数组指针类似
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			//printf("%d ", PArr[i][j]); 
			//printf("%d ", *(PArr[i] + j));  
			printf("%d ", *( (*(PArr + i) + j) ) );  
		}
	}
printf("\n");
}
int main()
{
	int arr[3][5] = { 1, 2, 3, 4, 5,
					  6, 7 ,8 ,9, 10,
					 11, 12, 13, 14, 15 };
	int num = sizeof(arr) / sizeof(int);
	int col = sizeof(arr[0]) / sizeof(int);
	int row = num / col;
	ArrPrint2(arr, row, col);   //arr表示二维数组的首元素地址(此时与一维数组首元素的意义是一样的)

	ArrPrint3(arr, row, col);  //arr表示二维数组首元素地址(是指二维数组真个第一行数组的地址)
	return 0;
}

总结:
数组指针分一维和二维两种
对一维数组指针解引用有两种方式

 (*parr)[i]
 *((*parr)+i) 

对二维数组指针解引用有三种方式

 PArr[i][j]
 *(PArr[i] + j)
 *( (*(PArr + i) + j) ) 

函数指针 :指向函数地址的指针

int Add(int x, int y)
{
	return x+y;
}

int main()
{
	int arr[5];
	int (*pa)[5] = &arr;
	printf("%p\n", &Add);
	printf("%p\n", Add);
	int (*p)(int, int) = Add;//p是函数指针
	int ret = p(2, 3);       //注意*在这里是不体任何作用的int ret = *p(2, 3);
	printf("%d\n", ret);
	return 0;
}
typedef struct Stu
{
	char name[20];
	int age;
	float score;
}Stu;

int main()
{
	typedef unsigned int uint;

	void (*signal(int, void(*)(int)))(int);

	//简化
	typedef void (*pfun_t)(int);
	//void(*p)(int);

	pfun_t signal(int, pfun_t);

	//signal是一个函数声明
	//signal函数有两个参数,第一个参数是int类型,
	//第二个参数是函数指针类型
	//该函数指针指向的函数,参数是int,返回类型是void
	//signal函数的返回类型是一个函数指针,该函数指针指向的函数,
	//参数是int,返回类型是void

	return 0;
}

函数指针数组

对于函数指针数组的创建如下:

 int my_strlen(const char*str)
 {
	 int len = 0;
	 while (*(str + len++) != '\0');
	 return --len;
 }
 
 int main()
 {
 	int* arr[10];
 	char* arr2[5];
 	//函数指针数组

	char str[] = "xiao du zhen ke ai";
 	int (*ps)(const char*) = &my_strlen;
 	int (*ps2)(const char*) = &my_strlen;
 	int (*ps3)(const char*) = &my_strlen;

 	//int (*psArr[3])(const char*) = {ps, ps2, ps3};//函数指针数组
	int (*psArr[3])(const char*) = { &my_strlen, &my_strlen, &my_strlen };//函数指针数组

	int ret = psArr[0](str);
	printf("length of str = %d \n",ret);
	//存放函数指针的数组
 	
 	return 0;
 }

void menu()
{
	printf("******************************\n");
	printf("***     1. add    2. sub   ***\n");
	printf("***     3. mul    4. div   ***\n");
	printf("***     0.exit             ***\n");
	printf("******************************\n");
}

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;
}

int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	//函数指针数组-转移表
	int (*pArr[5])(int, int) = {0, Add, Sub, Mul, Div};
	do 
	{
		menu();
		printf("请选择:>");
		(void)scanf("%d", &input);
		printf("请输入两个操作数:>");
		(void)scanf("%d%d", &x, &y);
		ret = pArr[input](x, y);
		printf("ret = %d\n", ret);

 	} while (input);
	return 0;
}

**总结: 函数指针无需解引用就能使用,解引用多次也不影响作用 函数指针最大的优势在于: 可以将参数个,数类型及返回值相同的函数归为一类函数放入函数指针数组中去,再以合适的判断条件去调用,就可以极大的简化重复使用的代码 **