Tutorial avanzado de puntero de nivel de niñera - [lenguaje C]

En el blog anterior, presenté brevemente el conocimiento básico de los punteros, el tamaño de los punteros, las operaciones, los punteros secundarios, etc. A continuación, lo llevaré a comprender los punteros en profundidad, para que todos tengan una buena comprensión de los punteros.


Tabla de contenido

puntero de carácter

matriz de punteros

 puntero de matriz

Nombre de matriz VS& nombre de matriz

Cómo usar punteros de matriz

puntero de función

matriz de punteros de función

puntero a matriz de punteros de función


puntero de carácter

En el tipo de puntero, hemos visto un tipo de puntero char*, que es un puntero de carácter, y el tipo de objeto al que apunta este tipo de puntero es un carácter;

Uso general:

#include<stdio.h>

int main(void)
{
    char ch = 'w';
    char *pc = &ch;//*pc就是字符指针
    *pc = 'w';
    return 0;
}

Podemos entender mejor el puntero de caracteres a través de un ejemplo: cuando no nos conviene usar ch para modificar el valor, podemos usar el puntero de caracteres para modificar indirectamente el contenido, lo que es similar a matar personas con un cuchillo.

Pero hay un uso especial de los punteros de caracteres: puede usar punteros de caracteres para crear directamente una cadena constante, como char*p = "abcd"; originalmente usamos una matriz de caracteres para crear una cadena, pero también se pueden crear punteros de caracteres String; pero hay una pequeña diferencia entre los dos: la cadena a la que apunta *p se almacena en el área de código, mientras que la matriz de caracteres se almacena en el área de pila.

int main(void)
{
	char arr[] = "abcdef";
	const char* p = "abcdef";//常量字符串
	printf("%s\n", p);
	printf("%c\n", *p);

	return 0;
}

 Cuando usamos el puntero de carácter p para imprimir la cadena completa y desreferenciar p, el resultado impreso es el siguiente:

 De esto podemos concluir que el puntero de carácter p apunta a la dirección del primer elemento de la cadena, no a la cadena completa.

A través de un ejemplo típico, podemos ver la diferencia entre usar una matriz para crear una cadena y usar un puntero de carácter para crear una cadena:

#include <stdio.h>
int main()
{
	char str1[] = "hello world.";
	char str2[] = "hello world.";
	const char* str3 = "hello world.";
	const char* str4 = "hello world.";
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");

	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");

	return 0;
}

¿Cómo debería ser el resultado de la serie de programas anterior?

Aquí str3 y str4 apuntan a la misma cadena constante. C/C++ almacenará cadenas constantes en un área de memoria separada.Cuando varios punteros apuntan a la misma cadena, en realidad apuntarán al mismo bloque de memoria. Pero cuando se usa la misma cadena constante para inicializar diferentes arreglos, se abrirán diferentes bloques de memoria. Entonces str1 y str2 son diferentes, y str3 y str4 son iguales.

Eso es todo lo que hay que saber sobre los punteros de caracteres.


matriz de punteros

¿Qué es una matriz de punteros? Podemos comenzar con algunas analogías. Matriz de enteros: una matriz que almacena números enteros, matriz de caracteres: una matriz que almacena caracteres; la matriz de punteros, como su nombre lo indica, es una matriz que almacena punteros

int* arr1[10]; //Array de punteros enteros

char *arr2[4]; //Array de punteros de caracteres de primer nivel

char **arr3[5];//Array de punteros de caracteres secundarios

Estos se denominan matrices de punteros.

 La función más utilizada de la matriz de punteros es simular una matriz bidimensional:

int main(void)
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* arr[] = { arr1,arr2,arr3 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}

	return 0;
}

 Coloque tres matrices unidimensionales del mismo tipo en la matriz de punteros y use la matriz de punteros para acceder a simular una matriz bidimensional. Debido a que el nombre de la matriz es la dirección del primer elemento de la matriz, si hay varias matrices, podemos colocar varias matrices en la matriz de punteros para su procesamiento e imprimir estas matrices una por una. El resultado de la ejecución del programa es el siguiente:

Eso es algo de contenido para la matriz de punteros. 


 puntero de matriz

¿Los punteros de matriz son punteros? ¿O una matriz?

La respuesta es: punteros.

Todos conocemos punteros enteros: int * pint; punteros que pueden apuntar a datos enteros. Puntero de punto flotante: float * pf; Un puntero que puede apuntar a datos de punto flotante. El puntero de matriz debe ser: un puntero que pueda apuntar a una matriz.

Entonces, ¿cuál en el siguiente código es un puntero de matriz?

int* p1[10];

int(*p2)[10];

¿Qué son p1 y p2 respectivamente?

Respuesta: p1 es una matriz de punteros, p2 es un puntero de matriz

Debido a que la prioridad de [] es mayor que *, p2 se combina con * primero, lo que indica que p2 es una variable de puntero y luego apunta a una matriz de 10 enteros. Entonces p2 es un puntero que apunta a una matriz, llamado puntero de matriz.


 

Nombre de matriz VS& nombre de matriz

Para la matriz de int arr[10];, ¿qué representa arr y qué representa &arr?

Sabemos que arr es el nombre de la matriz, que representa la dirección del primer elemento de la matriz. ¿Es &arr superfluo? Veamos primero un fragmento de código:

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 printf("%p\n", arr);
 printf("%p\n", &arr);
 return 0;
}

 Se puede ver que la dirección impresa por el nombre de la matriz y el nombre de la &matriz es la misma, pero ¿realmente no hay diferencia entre arr y &arr? La respuesta es que hay una diferencia.

arr es de tipo int* y &arr es de tipo int(*)[10]; 

#include <stdio.h>
int main()
{
 int arr[10] = { 0 };
 printf("arr = %p\n", arr);
 printf("&arr= %p\n", &arr);
 printf("arr+1 = %p\n", arr+1);
 printf("&arr+1= %p\n", &arr+1);
 return 0;
}

 De acuerdo con el código anterior, encontramos que, de hecho, &arr y arr tienen el mismo valor, pero el significado debería ser diferente.

De hecho: &arr representa la dirección de toda la matriz, no la dirección del primer elemento de la matriz. El tipo de datos de &arr es int (*)[10], que es un tipo de puntero de matriz y no int*. Y array +1 omite el tamaño de todo el array, por lo que la diferencia entre &arr+1 y arr+1 es 40.


Cómo usar punteros de matriz

¿Cómo se debe utilizar el puntero de matriz?

El puntero de matriz apunta a la matriz, y la dirección de la matriz debe almacenarse en el puntero de matriz, que generalmente es más conveniente para usar en una matriz bidimensional.

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
 int i = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
void print_arr2(int (*arr)[5], int row, int col)
{
 int i = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
int main()
{
 int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
 print_arr1(arr, 3, 5);
 print_arr2(arr, 3, 5);
 return 0;
}

 Utilizamos la recepción de matrices bidimensionales y la recepción de punteros de matriz respectivamente, los cuales pueden realizar el paso de parámetros de matrices bidimensionales, pero en realidad son punteros en esencia.

Para el nombre de la matriz arr en el programa anterior, representa la dirección del primer elemento, pero el primer elemento de la matriz bidimensional es la primera fila de la matriz bidimensional, por lo que la arr pasada aquí es en realidad equivalente a la dirección de la primera fila, que es unidimensional La dirección de la matriz se puede recibir con un puntero de matriz.


puntero de función

Como su nombre lo indica, un puntero a una función es un puntero de función.

¿La función tiene una dirección? Si es así, definitivamente podemos usar punteros para apuntar a la dirección de la función. Veamos primero un fragmento de código:

#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);
 return 0;
}

Resultado de salida:  se emiten dos direcciones, ambas direcciones de la función de prueba, lo que prueba que la función tiene una dirección, por lo que debe haber un puntero de función. Y sabemos que el nombre de la función y el nombre de la función & en el puntero de la función tienen el mismo significado, aquí podemos distinguirlo de la matriz.

Entonces, ¿qué tipo de puntero deberíamos usar para recibir el puntero de función? Así es como podemos escribir de manera análoga a los punteros de matriz:

Cuando se haya determinado la función definida, utilizaremos el valor de retorno y los parámetros de la función personalizada para imitar el puntero de función. Por ejemplo:

suma int(int x, int y)

{

        devuelve x+y;

}

//Definir int (*pf)(int, int) = &add; o int (*pf)(int, int) = add;

prueba nula()

{

       .......

}

//Definir void(*pd)() = &prueba o void(*pd)() = prueba;

Cuando llamamos a una función, podemos usar el método más primitivo, escribir directamente la función para llamarla o usar un puntero de función para llamarla.

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

int main(void)
{
	int (*pf)(int,int) = add;
	int r = add(3, 5);
	int m = pf(4, 5);
	printf("%d %d\n", r, m);

	return 0;
}

Este programa usa dos métodos para llamar a la función de agregar, los cuales se pueden llamar con éxito. El resultado es el siguiente:  Este es el puntero de función, que generalmente usamos en la función de devolución de llamada. Si no conoce la función de devolución de llamada, puede visitar la página de inicio del autor, que tiene una explicación de la función de devolución de llamada. ! ! ! 


matriz de punteros de función

Una matriz es un espacio de almacenamiento para almacenar el mismo tipo de datos. La matriz de punteros se explicó anteriormente. Luego, la dirección de la función debe almacenarse en una matriz. Luego, esta matriz se denomina matriz de punteros de función. Cómo definir una matriz de punteros de función?

//plantilla

int(*parr1[10])();

Parr1 primero se combina con [], lo que indica que parr1 es una matriz, ¿cuál es el contenido de la matriz? es un puntero de función de tipo int (*)().

Propósito de la matriz de punteros de función: tabla de transferencia  

Cuando estamos programando, necesitamos definir algunas funciones del mismo tipo, y cuando la función principal llama a cada función, las operaciones básicas son más o menos las mismas, si escribimos código, habrá contenido redundante y lógica poco clara. En este punto, usamos una serie de punteros de función, que pueden mejorar la legibilidad del código.

La implementación de la calculadora se puede realizar utilizando una matriz de punteros de función.

#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 input = 1;
int ret = 0;
 int(*p[5])(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 = (*p[input])(x, y);
 }
 else
 printf( "输入有误\n" );
 printf( "ret = %d\n", ret);
 }
 return 0;
}

Esto es más claro que usar el lenguaje de cambio de mayúsculas y minúsculas y hace que el código sea conciso y claro.


puntero a matriz de punteros de función

Un puntero a una matriz de punteros a funciones es un puntero que apunta a una matriz, y los elementos de la matriz son todos punteros a funciones; entonces, ¿cómo definirlo?

Para evitar confusiones, distingo entre las dos definiciones de módulo anteriores y los punteros a matrices de punteros de función:

void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[5])(const char*) = &pfunArr;
 return 0;
}

De hecho, podemos agregar matrices y punteros para seguir configurando, por lo que cada vez será más complicado, pero si te interesa, puedes seguir explorando, no diré más aquí.

Lo anterior es todo el contenido de Pointer Advanced. Gracias por mirar. Espero que puedan señalar mis defectos y errores. ¡Continuaré mejorando con su apoyo! !

Supongo que te gusta

Origin blog.csdn.net/m0_74755811/article/details/131666246
Recomendado
Clasificación