[C language advanced 5 - advanced pointer (2)]


foreword

This article continues the above and continues to learn the knowledge points of advanced pointers:

  • array parameter, pointer parameter
  • function pointer
  • array of function pointers

4. Array parameters, pointer parameters

First, review and review the knowledge learned in the previous article, and draw the knowledge points on a picture to clearly compare the similarities and differences:
insert image description here
insert image description here

When programming, sometimes we need to pass arrays or pointers to functions. How should the parameters of functions be designed? The following examples illustrate:

4.1 One-dimensional array parameter transfer

一维数组接收参数的几种方式
void test(int arr[])//形参与实参的定义相同,用数组接收
{
    
    }
void test(int arr[10])//形参与实参的定义相同,用数组接收,[]内数字可以不写
{
    
    }
void test(int* arr)//形参定义指针来接受数组首元素的地址
{
    
    }
void test2(int* arr[20])//形参与实参的定义相同,定义指针数组来接受参数
{
    
    }
void test2(int** arr)//二级指针,数组里的元素都是指针,就是地址
{
    
    }                   //数组名也是地址,地址的地址用二级指针

//一维数组传参
int main()
{
    
    
	int arr1[10] = {
    
     0 };//一维数组
	int* arr2[20] = {
    
     0 };//指针数组
	test(arr1);
	test2(arr2);
}

4.2 Two-dimensional array parameter transfer

二维数组接收参数的几种方式
void test(int arr[3][5])//形参与实参的定义相同,定义数组收受参数
{
    
    }
void test(int arr[][5])//形参与实参的定义相同。第1个[]内数字可以不写
{
    
    }
void test(int arr[][])//错误的,第2个[]内数字必须写
{
    
    }
void test(int *arr)//错误的,*arr对地址解引用,
{
    
    }				//arr是二维数组名,第一行地址,第一行数组的首元素地址,获得第一个元素0					
void test(int* arr[5])//错误的,这是一个数组,每一个元素是指针,就是地址
{
    
    }
void test2(int(*arr)[5])//指针指向的数组,是一个一维数组,数组有5个元素
{
    
    }
void test2(int** arr)//错误的,二级指针,存放一级指针的地址
{
    
    }                   

//二维数组传参
int main()
{
    
    
	int arr[3][5] = {
    
     0 };//二维数组
	二维数组在传参数组名时,传递的是首元素a[0],即第一行数组的地址
	test(arr);
}

insert image description here

4.3 First-level pointer parameter transfer

void test(int* arr, int sz)
{
    
    
	for (int i = 0; i < sz; i++)
	{
    
    
		printf("%d ", *arr++);
	}
}
int main()
{
    
    
	int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int* pa = arr;//直接把数组名给指针即可
	int sz = sizeof(arr) / sizeof(arr[0]);
	test(pa, sz);
	return 0;
}

Consider the following:
When you know that the formal parameter part of a function is a first-level pointer, what parameters should be passed when calling in the main function?

void test(int* p)
{
    
    }
int main()
{
    
    
	int a = 10;
	int* p = &a;
	int arr[10];
	//传参的几种形式,都是可以的
	test(&a);
	test(p);
	test(arr);

	return 0;
}

4.4 Second-level pointer parameter transfer

//举例 1
void test(int** p)//二极指针,地址的地址
{
    
    }
int main()
{
    
    
	int n = 10;
	int* p = &n;
	int** pp = &p;

	test(pp);
	test(&p);
}
//举例 2
void test(char** ch)
{
    
    }
int main()
{
    
    
	char ch = 'w';
	char* pc = &ch;
	char** ppc = &pc;
	char* arr[5];
	char arr1[3][5];

	test(arr);
	test(ppc);
	test(&pc);
	test(arr1);//错误的,二维数组穿的是第一行的地址,就是第一行数组的地址
	//应该char (*p)[5],参数应该用数组指针传参,指向数组的指针
}				
//举例 3
void test1(int(*p)[5])//数组指针,指针指向数组,这个数组有5个元素,每个元素是int类型
{
    
    }
void test2(int(*p)[3][5])//指针指向整个二维数组
{
    
    
	*p//解引用后代表首行地址
}
int main()
{
    
    
	int arr[3][5];
	test1(arr);//二维数组传递的是第一行地址
	test2(&arr);//传递的是整个二维数组的地址,一般不会这样用
}

5, function pointer

By analogy with what we learned earlier , we can discover the mystery of defining pointers:

  • array pointer - pointer to array
  • function pointer - a pointer to a function
    insert image description here
//举例1
void test()
{
    
    
	printf("hehe\n");
}
int main()
{
    
    
	printf("%p\n", test);//函数名就是地址
	printf("%p\n", &test);
	
	return 0;
}
//举例2
int add(int x, int y)
{
    
    
	return x + y;
}
int test(char* ch)
{
    
    }
int main()
{
    
    
	//int arr[10];
	//arr
	//&arr
	//int* p = arr;
	//int(*p)[10] = &arr;

	int(*pa)(int, int) = add;//就是函数指针变量,将函数的地址保存起来
	int ret = (*pa)(2, 3);//此处的*不起作用,有无都行
	/*int ret = add(2, 3);

	int ret = pa(2, 3);*/
	printf("%d\n", ret);
	//int(*pc)(char*) = test;
	return 0;
}
int main()
{
    
    
	void(*p)();//这个p的类型函数指针类型,去掉p后,剩下的是void(*)(),指针p指向的地址是一个参数是空,返回类型是空的函数

	//代码1
	(*void(*)()0)();
	解释说明:
	void(*)()是函数指针类型
	(void(*)()0,将0强制转换成函数指针类型,则指针0指向的地址里有一个函数
	*void(*)()0 地址解引用,就是函数名了
	(*void(*)()0)(),调用0地址处放的函数*/

	//代码2
	void(*signal(int, void(*)()(int)))(int);
	解释说明:
	signal(int, void(*)()(int)) 函数两个参数,一个int,一个函数指针
	void(*)()(int)是一个函数指针类型,指向的函数的参数是int,返回值是空
	//如同函数声明 int add(int, int);
	//去掉函数名和参数后,剩下的int就是函数的返回类型
	void(*signal(int, void(*)()(int)))(int)中去除函数名 signal(int, void(*)()(int))后,
	只剩下 void(* )(int),	它就是函数的返回类型,返回的是函数指针类型
	
	//代码2也可以简化:
	typedef void(*pfun_t)(int);
	pfun_t signal(int, pfun_t);
	
}

6. Array of function pointers

Learning definitions by analogy:
insert image description here

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

函数指针数组:
int(*parr1[5])();
上面去掉数组名parr[5]后,剩下int(*)(),就是函数指针类型,这个数组有5个元素,每个元素都是int(*)()类型

parr1 先和 [] 结合,说明 parr1是数组,数组的内容:是 int (*)() 类型的函数指针
即数组里的每个元素都是指针,即地址,每个地址都存有一个函数,对指针解引用就能调用函数

The usefulness of the array of function pointers:
a function of a simple calculator:

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

It can be found that when multiple functions appear, the calling process is similar, but the code is repeated more and is redundant :

//常规的写法非常繁琐
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int res = 0;
	do
	{
    
    
		menu();
		printf("请选择 ==> ");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case 1:
			printf("请输入两个操作数 ==> ");
			scanf("%d %d", &x, &y);
			res = add(x, y);
			printf("ret=%d\n", res);
			break;
		case 2:
			printf("请输入2个操作数:>");
			scanf("%d %d", &x, &y);
			res = sub(x, y);
			printf("ret=%d\n", res);
			break;
		case 3:
			printf("请输入2个操作数:>");
			scanf("%d %d", &x, &y);
			res = mul(x, y);
			printf("ret = %d\n", res);
			break;
		case 4:
			printf("请输入2个操作数:>");
			scanf("%d %d", &x, &y);
			res = div(x, y);
			printf("ret = %d\n", res);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			break;
		}
	} while (input);
	return 0;
}

The code is rewritten to use an array of function pointers:

//函数指针数组的用法
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int res = 0;
	int(*paar[5])(int, int) = {
    
     0,add,sub,mul,div };
	do
	{
    
    
		menu();
		printf("请选择 ==> ");
		scanf("%d", &input);
		if (input==0)
		{
    
    
			printf("退出计算器\n");
		}
		else if (input >= 1 && input <= 4)
		{
    
    
			printf("请输入2个操作数:>");
			scanf("%d%d", &x, &y);
			res = (*paar[input])(x, y);//直接调用函数
			printf("%d\n", res);
		}
		else
		{
    
    
			printf("选择错误,重新输入数字\n");
		}		
	} while (input);
	return 0;
}

Summarize

There are many advanced pointers, and the nouns of these contents are similar. If you can't grasp it firmly, it will confuse these knowledge points. The first time you can't fully grasp it, you should review it often and learn from the past.

By analogy, various definitions can be effectively distinguished. Continue to learn advanced pointer content in the next article.

Guess you like

Origin blog.csdn.net/taibudong1991/article/details/124077874