[C Language] Advanced Pointers 2

Array of function pointers

An array is a storage space that stores data of the same type. We have already learned about pointer arrays, such as:

int* arr[10];//数组的每个元素是int*

Then you need to store the address of the function in an array, then this array is called a function pointer array. Which of the following is an array of function pointers?

int (*parr1[10])();
int* parr2[10]();
int (*)() parr3[10];

The answer is: parr1. Parr1 is first combined with [], indicating that parr1 is an array. What is the content of the array? It is a function pointer of type int (*)().
The purpose of the function pointer array: transfer table.
Consider the following example of a simple calculator:

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;
	do
	{
    
    
		printf("========================\n");
		printf(" 1:add     2:sub \n");
		printf(" 3:mul     4:div \n");
		printf("========================\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case 1:
			printf("请输入操作数:");
			scanf("%d %d", &x, &y);
			ret = add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("请输入操作数:");
			scanf("%d %d", &x, &y);
			ret = sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("请输入操作数:");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("请输入操作数:");
			scanf("%d %d", &x, &y);
			ret = div(x, y);
			printf("ret = %d\n", ret);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}

So how to implement it using an array of function pointers? Please look at the code below:

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) = {
    
     NULL, 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("ret = %d\n", ret);
	}
	return 0;
}

Pointer to array of function pointers

A pointer to an array of function pointers is a pointer pointing to an array, and the elements of the array are function pointers . Let's look at the following code:

	int (*pf)(int, int);//函数指针
	int (*pfArr[5])(int, int);//函数指针数组
	//&pfArr函数指针数组的地址,p就是指向函数指针数组的指针
	int (*(*p)[5])(int, int) = &pfArr;

Analysis: p is first combined with * to indicate that it is a pointer, then combined with [], indicating that it is an array pointer, and then combined with * to indicate that a pointer points to an array pointer, and then points to the address of a function. The function has two There are int type parameters, and the return value is int.

All in all, the pointer to the function pointer array is based on the function pointer array, plus an * to represent a pointer to point to it.

Callback

A callback function is a function called through a function pointer. If you pass a function pointer (address) as a parameter to another function, and when this pointer is used to call the function it points to, we say it is a callback function. The callback function is not called directly by the implementer of the function, but is called by another party when a specific event or condition occurs to respond to the event or condition.
Insert image description here
First demonstrate the use of the qsort function:
Insert image description here
Insert image description here

#include <stdlib.h>//qsort需要引入头文件
int int_cmp(const void * p1, const void * p2)
{
    
    
	return (*( int *)p1 - *(int *) p2);
}
int main()
{
    
    
	int arr[] = {
    
     1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	qsort(arr, sz, sizeof (int), int_cmp);
	for (i = 0; i< sz; i++)
	{
    
    
		printf( "%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

Use the callback function to simulate the implementation of qsort (using bubbling method)

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(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, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	//char *arr[] = {"aaaa","dddd","cccc","bbbb"};
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz, sizeof(int), int_cmp);
	for (i = 0; i < sz; i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

The pointer of void* is a pointer without a specific type. It can receive any type of address. This type of pointer cannot be directly dereferenced or directly performed pointer operations.

Test qsort sorting structure data

struct Stu
{
    
    
	char name[10];
	int age;
};
//按年龄排序
int cmp_stu_age(const void* p1, const void* p2)
{
    
    
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
//按姓名排序
int cmp_stu_name(const void* p1, const void* p2)
{
    
    
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
int main()
{
    
    
	struct Stu arr[] = {
    
     {
    
    "zhangsan", 17}, {
    
    "lisi", 18},{
    
    "wangwu", 15} };
	int sz = sizeof(arr) / sizeof(arr[0]); 
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_age);
	int i = 0;
	for (i = 0; i < sz; i++) 
	{
    
    
		printf("%d\n", arr[i].age);
	}
	return 0;
}

Analysis of classic topics on pointers and arrays

The array name is the address of the first element of the array, but there are two exceptions:
1. sizeof (array name), the array name here represents the entire array, and the calculation is the size of the entire array, in bytes.
2.&Array name, the array name here represents the entire array, and the address of the entire array is taken out.
Please look at the following questions:

//一维数组
int a[] = {
    
    1,2,3,4};
printf("%d\n",sizeof(a));//4*4=16字节
printf("%d\n",sizeof(a+0));//数组名a是数组首元素地址,a+0还是首地址,地址大小为4/8字节
printf("%d\n",sizeof(*a));//数组名a是数组首元素地址,*a就是首元素,大小为4字节
printf("%d\n",sizeof(a+1));//数组名a是数组首元素地址,a+1就是第二个元素的地址,大小为4/8字节
printf("%d\n",sizeof(a[1]));//数组第二个元素,大小为4字节
printf("%d\n",sizeof(&a));//&a是数组的地址,数组的地址也是地址大小为4/8字节
printf("%d\n",sizeof(*&a));//*和&相互抵消,所以*&a相当于a,所以大小为16个字节
printf("%d\n",sizeof(&a+1));//&a是整个数组的地址,&a+1就是跳过整个数组,但结果任然是一个地址,大小为4/8字节
printf("%d\n",sizeof(&a[0]));//表示首元素地址,大小为4/8个字节
printf("%d\n",sizeof(&a[0]+1));//表示第二个元素的地址,大小为4/8个字节
//字符数组
char arr[] = {
    
    'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//arr表示整个数组,计算的是整个数组的大小,总共6个字节
printf("%d\n", sizeof(arr+0));//arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));//arr表示数组首元素的地址,*arr就是首元素,大小1个字节
printf("%d\n", sizeof(arr[1]));//arr[1]就是数组第二个元素,大小是1个字节
printf("%d\n", sizeof(&arr));//&arr是数组的地址,但是数组的地址也是地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr+1));//&arr + 1是跳过整个数组后的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr[0]+1));//表示第二个元素的地址,是4/8个字节

printf("%d\n", strlen(arr));//因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找直到找到\0,所以结果就是随机值
printf("%d\n", strlen(arr+0));//arr + 0是首元素的地址,和第一个一样,也是随机值
printf("%d\n", strlen(*arr));//error
//strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参,就会从97这个地址开始统计字符串长度,这就非法访问内存了
printf("%d\n", strlen(arr[1]));//error 原因同上
printf("%d\n", strlen(&arr));//&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计
printf("%d\n", strlen(&arr+1));//原因同上也是随机值
printf("%d\n", strlen(&arr[0]+1));//&arr[0] + 1是第二个元素的地址。结果也是随机值
char arr[] = "abcdef";//等价于[a b c d e f \0]
printf("%d\n", sizeof(arr));//7个字节
printf("%d\n", sizeof(arr+0));//arr + 0是首元素的地址,大小1个字节
printf("%d\n", sizeof(*arr));//*arr其实就是首元素,大小1个字节
printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小1个字节
printf("%d\n", sizeof(&arr));//&arr是数组的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr+1));//&arr + 1是跳过一个数组的地址,结果仍然是地址大小为4/8个字节
printf("%d\n", sizeof(&arr[0]+1));//&arr[0] + 1是第二个元素的地址 大小为4/8个字节

printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr+0));//6
printf("%d\n", strlen(*arr));//error
printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr+1));//跳过整个数组向后数,后面是未知的所以结果是随机值
printf("%d\n", strlen(&arr[0]+1));//从第二个元素往后数,长度为5
char* p = "abcdef";
printf("%d\n", sizeof(p));//p是一个指针变量大小就是4/8个字节
printf("%d\n", sizeof(p+1));//p+1是'b'的地址,是地址大小就是4/8个字节
printf("%d\n", sizeof(*p));//*p 就是'a',大小就是1个字节
printf("%d\n", sizeof(p[0]));//p[0]--> *(p+0) --> *p 大小1个字节
printf("%d\n", sizeof(&p));//&p --> char** 大小4/8个字节
printf("%d\n", sizeof(&p+1));//直接跳到字符串后面的,实际还是地址,大小4/8个字节
printf("%d\n", sizeof(&p[0]+1));//&p[0] + 1得到是'b'的地址,大小4/8个字节

printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p+1));//5
printf("%d\n", strlen(*p));//error
printf("%d\n", strlen(p[0]));//error
printf("%d\n", strlen(&p));//随机值
printf("%d\n", strlen(&p+1));//随机值
printf("%d\n", strlen(&p[0]+1));//5
//二维数组
int a[3][4] = {
    
    0};
printf("%d\n",sizeof(a));//3*4*4 = 48
printf("%d\n",sizeof(a[0][0]));//4
printf("%d\n",sizeof(a[0]));//a[0]是第一行这个一维数组的数组名,数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节
printf("%d\n",sizeof(a[0]+1));//a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&,a[0]表示数组首元素的地址,也就是a[0][0]的地址,所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节
printf("%d\n",sizeof(*(a[0]+1)));//计算的是第一行第2个元素的大小,为4个字节
printf("%d\n",sizeof(a+1));//a是数组首元素的地址,是第一行的地址,a+1就是第二行的地址,是地址大小就是4/8个字节  (它的类型是int(*)[4])
printf("%d\n",sizeof(*(a+1)));//*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小,就是16个字节
printf("%d\n",sizeof(&a[0]+1));//&a[0]是第一行的地址,&a[0]+1 是第二行的地址,是地址大小就是4/8个字节
printf("%d\n",sizeof(*(&a[0]+1)));//计算的是第二行的大小,16个字节
printf("%d\n",sizeof(*a));//a是数组首元素的地址,就是第一行的地址,*a 就是第一行,*a --> *(a+0) --> a[0],大小为16个字节
printf("%d\n",sizeof(a[3]));//第三行的大小,16个字节

Summarize:

  1. sizeof(array name), the array name here represents the entire array, and the size of the entire array is calculated.
  2. &Array name, the array name here represents the entire array, and the address of the entire array is taken out.
  3. In addition, all array names represent the address of the first element.

Guess you like

Origin blog.csdn.net/qq_58032742/article/details/132180316