[Langage C avancé 5 - pointeur avancé (2)]


avant-propos

Cet article continue ce qui précède et continue d'apprendre les points de connaissance des pointeurs avancés :

  • paramètre de tableau, paramètre de pointeur
  • pointeur de fonction
  • tableau de pointeurs de fonction

4. Paramètres de tableau, paramètres de pointeur

Tout d'abord, passez en revue et passez en revue les connaissances acquises dans l'article précédent, et dessinez les points de connaissance sur une image pour comparer clairement les similitudes et les différences :
insérez la description de l'image ici
insérez la description de l'image ici

Lors de la programmation, nous devons parfois passer des tableaux ou des pointeurs vers des fonctions. Comment les paramètres des fonctions doivent-ils être conçus ? Les exemples suivants illustrent :

4.1 Transfert de paramètres de tableau unidimensionnel

一维数组接收参数的几种方式
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 Transfert de paramètres de tableau à deux dimensions

二维数组接收参数的几种方式
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);
}

insérez la description de l'image ici

4.3 Transfert des paramètres du pointeur de premier niveau

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

Considérez ce qui suit :
Lorsque vous savez que la partie paramètre formel d'une fonction est un pointeur de premier niveau, quels paramètres doivent être passés lors de l'appel dans la fonction principale ?

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 Transfert de paramètre de pointeur de deuxième niveau

//举例 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, pointeur de fonction

Par analogie avec ce que nous avons appris précédemment , nous pouvons découvrir le mystère de la définition des pointeurs :

  • pointeur de tableau - pointeur vers un tableau
  • pointeur de fonction - un pointeur vers une fonction
    insérez la description de l'image ici
//举例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. Tableau de pointeurs de fonction

Apprendre les définitions par analogie :
insérez la description de l'image ici

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

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

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

L'utilité du tableau de pointeurs de fonction :
une fonction d'une calculatrice simple :

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

On peut constater que lorsque plusieurs fonctions apparaissent, le processus d'appel est similaire, mais le code se répète davantage et est redondant :

//常规的写法非常繁琐
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;
}

Le code est réécrit pour utiliser un tableau de pointeurs de fonction :

//函数指针数组的用法
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;
}

Résumer

Il existe de nombreux pointeurs avancés, et les noms de ces contenus sont similaires. Si vous ne pouvez pas le saisir fermement, cela confondra ces points de connaissance. La première fois que vous ne pouvez pas le saisir pleinement, vous devriez le revoir souvent et apprendre du passé.

Par analogie, diverses définitions peuvent être efficacement distinguées. Continuez à apprendre le contenu avancé des pointeurs dans le prochain article.

Je suppose que tu aimes

Origine blog.csdn.net/taibudong1991/article/details/124077874
conseillé
Classement