[Lenguaje C] Punteros avanzados 1


Un puntero es una variable utilizada para almacenar una dirección. La dirección identifica de forma única un espacio de memoria. El tamaño del puntero es fijo de 4/8 bytes (plataforma de 32 bits/plataforma de 64 bits). Los punteros tienen tipos. El tipo de puntero determina el tamaño de paso entero del puntero y los permisos durante la operación de desreferencia del puntero.

1. Puntero de carácter

Entre los tipos de punteros, sabemos que existe un tipo de puntero llamado puntero de carácter char*.

int main()
{
    
    
	char ch = 'a';
	char *p = &ch;
	*pc = 'b';
	return 0;
}

Por favor mire el siguiente código

int main()
{
    
    
	const char* p = "hello world";
	printf("%s\n", p);
	printf("%c\n", *p);
	return 0;
}

¿Se coloca aquí una cadena en la variable de puntero p?
Insertar descripción de la imagen aquí

De hecho, no es así. La dirección de la siguiente cadena constante es en realidad la dirección de la primera letra. En esencia, la dirección de la primera letra h se le da a p. De hecho, p apunta a esta cadena constante.

El código const char* p = “hello world”; es particularmente fácil para nosotros pensar que la cadena hello world se coloca en el puntero del carácter p, pero la esencia es que se coloca la dirección del primer carácter de la cadena hello world. En p. De hecho, es para almacenar la dirección del primer carácter h de una cadena constante en la variable de puntero p.

Por favor mire la pregunta a continuación

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和str2相同\n");
	else
		printf("str1和str2不相同\n");
	if (str3 == str4)
		printf("str3和str4相同\n");
	else
		printf("str3和str4不相同\n");
	return 0;
}

El resultado final aquí es:
Insertar descripción de la imagen aquí

Aunque el contenido almacenado en str1 y str2 es el mismo, str1 y str2 son dos matrices de caracteres diferentes con direcciones diferentes. Aunque str3 y str4 son dos punteros de caracteres diferentes, ambos apuntan a la misma dirección, str3 y str4. La dirección de almacenamiento es lo mismo.

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

2. Puntero de matriz

2.1 Definición de puntero de matriz

Si un puntero apunta a una matriz, lo llamamos puntero de matriz.
También podemos definir un puntero a una matriz, por ejemplo:

int arr[] = {
    
     9, 15, 10, 8, 2 };
int *p = arr;

arr en sí es un puntero y se puede asignar directamente a la variable de puntero p. arr es la dirección del elemento 0 de la matriz, por lo que int *p = arr; también se puede escribir como int *p = &arr[0];. En otras palabras, las tres formas de escribir arr, p y arr[0] son ​​equivalentes y todas apuntan al elemento 0 de la matriz, o al comienzo de la matriz.
¿Cuál de los siguientes códigos es un puntero de matriz?

int *p1[10];
int (*p2)[10];

La respuesta es int (*p2)[10];
porque p2 primero se combina con *, lo que indica que p2 es una variable de puntero y luego apunta a una matriz de 10 números enteros. Entonces p2 es un puntero que apunta a una matriz, llamado puntero de matriz.
Nota: [] tiene una prioridad más alta que *, por lo que se debe agregar () para garantizar que p se combine con * primero.

2.2 & nombre de matriz VS nombre de matriz

int arr[10];

¿Qué son arr y &arr?
Sabemos que arr es el nombre de la matriz y el nombre de la matriz representa la dirección del primer elemento de la matriz. Entonces, ¿cuál es exactamente el nombre de la matriz &arr? Veamos un fragmento de código:

int main()
{
    
    
	int arr[10] = {
    
    0};
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	return 0;
}

Los resultados de ejecución son los siguientes:
Insertar descripción de la imagen aquí

Se puede ver que la dirección impresa por el nombre de la matriz y el nombre de la matriz es la misma. ¿Son los tres iguales? Veamos otro fragmento de código:

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

Insertar descripción de la imagen aquí

Según el código anterior, encontramos que, de hecho, aunque los valores de &arr y arr son los mismos, sus significados deberían ser diferentes.
De hecho: &arr representa la dirección de la matriz, no la dirección del primer elemento de la matriz. El tipo de &arr es: int(*)[10], que es la dirección de un puntero de matriz tipo matriz + 1, omitiendo el tamaño de toda la matriz, por lo que la diferencia entre &arr+1 y &arr es 40.
Para nombres de matrices, &arrayname obtiene la dirección de la matriz.

2.3 Uso de punteros de matriz

¿Cómo se utilizan los punteros de matriz? Dado que el puntero de la matriz apunta a una matriz, la dirección de la matriz debe almacenarse en el puntero de la matriz.

void print_arr(int(*arr)[5], int row, int col)
{
    
    
	int i = 0;
	for (i = 0; i < row; i++)
	{
    
    
		int j = 0;
		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_arr(arr, 3, 5);
	return 0;
}

El nombre de la matriz arr representa la dirección del primer elemento. Pero el primer elemento de la matriz bidimensional es la primera fila de la matriz bidimensional. Entonces, el arr pasado aquí es en realidad equivalente a la dirección de la primera línea, que es la dirección de una matriz unidimensional. Puede recibirse mediante un puntero de matriz.

3. Paso de parámetros de matriz y paso de parámetros de puntero

3.1 Transferencia de parámetros de matriz unidimensional

void test1(int arr[])
{
    
    }
void test1(int arr[10])
{
    
    }
void test1(int *arr)
{
    
    }
void test2(int *arr[20])
{
    
    }
void test2(int **arr)
{
    
    }
int main()
{
    
    
	int arr[10] = {
    
    0};
	int *arr2[20] = {
    
    0};
	test1(arr);
	test2(arr2);
	return 0;
}

3.2 Transferencia de parámetros de matriz bidimensional

void test(int arr[3][5])
{
    
    }
void test(int arr[][5])
{
    
    }
void test(int (*arr)[5])
{
    
    }
void test(int **arr)
{
    
    }
int main()
{
    
    
	int arr[3][5] = {
    
    0};
	test(arr);
}

Resumen: al pasar parámetros a través de una matriz bidimensional, el diseño de parámetros de función solo puede omitir el primer número []. Porque para una matriz bidimensional, no necesita saber cuántas filas hay, pero debe saber cuántos elementos hay en una fila. Esto facilita los cálculos.

3.3 Paso de parámetros de puntero de primer nivel

void print(int *p, int sz)
{
    
    
	int i = 0;
	for(i=0; i<sz; i++)
	{
    
    
		printf("%d\n", *(p+i));
	}
}
int main()
{
    
    
	int arr[10] = {
    
    1,2,3,4,5,6,7,8,9};
	int *p = arr;
	int sz = sizeof(arr)/sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

3.4 Paso de parámetro de puntero secundario

void test(int** ptr)
{
    
    
	printf("num = %d\n", **ptr);
}
int main()
{
    
    
	int n = 10;
	int*p = &n;
	int **pp = &p;
	test(pp);
	test(&p);
	return 0;
}

4. Puntero de función

Primero mire un fragmento de código:

void test()
{
    
    
	printf("hello\n");
}
int main()
{
    
    
	printf("%p\n", test);
	printf("%p\n", &test);
	return 0;
}

El resultado de salida:
Insertar descripción de la imagen aquí
el nombre de la función y el nombre de la función son ambos la dirección de la función.
Entonces, ¿cómo almacenamos la dirección de la función? La respuesta son los punteros de función.

void (*p)() = &test;

p se combina primero con *, lo que indica que p es un puntero. El puntero apunta a una función. La función señalada no tiene parámetros y el tipo de valor de retorno es nulo.
Eche un vistazo a la función a continuación: ¿Cómo se señala con un puntero?

int add(int a,int b)
{
    
    
	return a + b;
}

Respuesta:

int (*p)(int, int) = &add;

puntero de función de llamada
Insertar descripción de la imagen aquí

Gracias a todos por mirar, espero que mi artículo pueda ayudarlos. Gracias por su apoyo, ¡trabajemos juntos! ! !

Supongo que te gusta

Origin blog.csdn.net/qq_58032742/article/details/132090313
Recomendado
Clasificación