Explicación detallada de las partes avanzadas del lenguaje C (nivel principiante de punteros)

¡Hola a todos! Hace algún tiempo me estuve preparando para el concurso de modelos matemáticos y ya terminé. Date prisa y continúa ofreciéndote contenido en lenguaje C. Hoy les daré una explicación de la parte básica de los punteros.

Cuando hablamos de punteros en lenguaje C, en realidad estamos discutiendo un concepto muy importante, porque los punteros son uno de los núcleos del lenguaje C. Nos permiten acceder directamente a los datos en la memoria, lo cual es muy útil a la hora de escribir programas eficientes y flexibles. Echemos un vistazo más profundo al concepto y uso de punteros.


Tabla de contenido

1. ¿Qué es un puntero? 

1. Comprensión preliminar de los consejos

 2. El tamaño del puntero.

3. Resumen

2. Punteros y tipos de punteros

 3. El significado de los tipos de punteros

 1. Puntero + - entero

2.Desreferencia 

4. Puntero salvaje

1. Causas de los punteros salvajes

①El puntero no está inicializado

② Acceso fuera de límites del puntero 

Editar

③Libere el espacio señalado por el puntero 

5. Aritmética de punteros

1. Puntero + - entero

 2. Puntero - puntero

 3. Operaciones relacionales sobre punteros.

 4.Atención

6. Punteros y matrices

7. puntero secundario 

8. Matriz de punteros


 

1. ¿Qué es un puntero? 

1. Comprensión preliminar de los consejos

  Dos puntos clave para entender los punteros:
1. Un puntero es el número de la unidad más pequeña en la memoria, es decir, la dirección.
2. Los punteros mencionados en el lenguaje hablado normal generalmente se refieren a variables de puntero, que son variables utilizadas para almacenar direcciones de memoria. 
 
Resumen: Los punteros son direcciones. Los punteros en el lenguaje hablado generalmente se refieren a variables de puntero.
Diagrama de memoria:
Variables de puntero:
Podemos usar & (operador de dirección) para obtener la dirección de memoria real de la variable y almacenar la dirección en una variable, que es una variable de puntero.
#include<stdio.h>
int main()
{
	int a = 7;//创建变量时,在内存里开辟的一篇空间
	int* pa = &a;//这里我们对变量a,取出它的地址,可以使用&操作符
	//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
	//中,p就是一个之指针变量
	return 0;
}

Resumen: las variables de puntero son variables que se utilizan para almacenar direcciones. (Los valores almacenados en punteros se tratan como direcciones) 


 2. El tamaño del puntero.

En lenguaje C, el tamaño de los punteros varía según la arquitectura de la computadora y el sistema operativo. Normalmente, el tamaño de un puntero está relacionado con la cantidad de bits de la computadora. En sistemas de 32 bits, el tamaño del puntero suele ser de 4 bytes (32 bits), mientras que en sistemas de 64 bits, el tamaño del puntero suele ser de 8 bytes (64 bits).

3. Resumen

  • Los punteros se utilizan para almacenar direcciones y las direcciones identifican de forma única un espacio de direcciones.
  • El tamaño del puntero es de 4 bytes en plataformas de 32 bits y de 8 bytes en plataformas de 64 bits.

2. Punteros y tipos de punteros

Las variables tienen diferentes tipos, enteras, de coma flotante, etc. ¿El puntero tiene un tipo?

Los punteros tienen:

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;
Como puede ver aquí, la definición de punteros es: escriba + * .
de hecho:
Un puntero de tipo char* se utiliza para almacenar la dirección de una variable de tipo char .
El puntero de tipo corto* se utiliza para almacenar la dirección de la variable de tipo corto .
El puntero de tipo int* se utiliza para almacenar la dirección de la variable de tipo int

 A continuación, explore el significado de los tipos de punteros.


 3. El significado de los tipos de punteros

El tipo de puntero determina cuánta autoridad tiene al eliminar la referencia al puntero (cuántos bytes se pueden manipular)

Por ejemplo: la desreferencia del puntero char* solo puede acceder a un byte, mientras que la desreferencia del puntero int* puede acceder a cuatro bytes. 

 1. Puntero + - entero

int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;

	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc + 1);
	printf("%p\n", pi);
	printf("%p\n", pi + 1);
	return 0;
}

2.Desreferencia 

 Se puede ver que los valores de pc y pi son iguales, después de ejecutar *pc=0, solo se cambia el valor del primer byte.

Después de ejecutar *p=0, solo se cambia el valor de cuatro bytes.


4. Puntero salvaje

Concepto: un puntero comodín significa que la posición señalada por el puntero es desconocida (aleatoria, incorrecta y sin restricciones claras)

1. Causas de los punteros salvajes

①El puntero no está inicializado

int main()
{
	int* pa;
	*pa = 10;
	return 0;
}

Incluso el compilador nos impide utilizar punteros no inicializados.

Acceso fuera de límites del puntero 

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	for (int i = 0; i <= 11; i++)
	{
		*(p++) = i;
	}
	return 0;
}

Cuando el rango señalado por el puntero excede el rango de la matriz arr , p es un puntero salvaje:  naturalmente, se informará un error.

③Libere el espacio señalado por el puntero 

int* createInt() {
    int num = 5;
    int* ptr = &num;
    return ptr;
}

int main() {
    int* ptr = createInt();
    printf("%d\n", *ptr);  // 输出5,但是这是不安全的操作

    // 在这之后,ptr成为了野指针,因为它指向的内存空间已经被释放

    printf("%d\n", *ptr);  // 未定义的行为,可能输出垃圾值或导致程序崩溃

    return 0;
}

En el ejemplo anterior, la función createInt()crea una variable entera num, asigna su dirección a un puntero ptry devuelve el puntero. En main()la función, imprimimos ptrel valor señalado por el puntero y el resultado es 5. Pero createInt()una vez finalizada la función, numfinaliza el ciclo de vida de la variable y se libera el espacio de memoria que ocupa. En este momento, el puntero ptraún conserva la dirección de memoria anterior y se convierte en un puntero salvaje. En operaciones de impresión posteriores, intentamos acceder ptral valor señalado por el puntero comodín. Esta es una operación insegura y puede provocar un comportamiento indefinido del programa. 


 

5. Aritmética de punteros

1. Puntero + - entero

  • La suma y resta de punteros de números enteros se refiere a la suma y resta de punteros, donde el número entero representa el desplazamiento que se suma o resta. Esta operación se utiliza normalmente para mover un puntero una cierta distancia para acceder a la ubicación de memoria a la que apunta el puntero.
  • Las operaciones de suma y resta de puntero se basan en el tamaño del tipo de datos al que apunta el puntero. Por ejemplo, si un puntero apunta a una intvariable de un tipo, agregar 1 al puntero hará que el puntero apunte a una intvariable del siguiente tipo. De manera similar, disminuir el puntero en 1 hará que el puntero apunte a una intvariable del tipo anterior. 
#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5 };
	int* pa = arr;
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", *(pa++));
	}
	return 0;
}

 

 2. Puntero - puntero

La operación puntero-puntero se refiere a restar dos punteros para obtener el desplazamiento entre ellos. Esta operación se suele utilizar para calcular la distancia entre dos punteros o el número de elementos. 

A continuación podemos usar esto para simular e implementar la función strlen()

int my_strlen(char* pa)
{
	char* start = pa;
	while (*pa)
	{
		pa++;
	}
	return pa - start;
}

int main()
{
	char arr[] = "hello";
	printf("%d", my_strlen(arr));
	return 0;
}

 

 3. Operaciones relacionales sobre punteros.

  • ==: Determina si dos punteros son iguales. Si dos punteros apuntan a la misma dirección de memoria, son iguales y se devuelven 1; en caso contrario, se devuelven 0.
  • !=: Determina si dos punteros no son iguales. Si los dos punteros apuntan a direcciones de memoria diferentes, no son iguales y devuelven 1; en caso contrario, devuelven 0.
  • >: determina si un puntero es mayor que otro puntero. El tamaño del puntero se compara en función de la dirección de memoria señalada por el puntero. Si la dirección señalada por el primer puntero es posterior a la dirección señalada por el segundo puntero, entonces el primer puntero es mayor que el segundo puntero, devuelve 1; en caso contrario, devuelve 0.
  • <: determina si un puntero es más pequeño que otro puntero. El tamaño del puntero se compara en función de la dirección de memoria señalada por el puntero. Si la dirección señalada por el primer puntero está antes de la dirección señalada por el segundo puntero, entonces el primer puntero es más pequeño que el segundo puntero, devuelve 1; en caso contrario, devuelve 0.
  • >=: determina si un puntero es mayor o igual que otro puntero. Devuelve si el primer puntero es mayor que el segundo puntero o si los dos punteros son iguales 1; en caso contrario 0.
  • <=: determina si un puntero es menor o igual que otro puntero. Devuelve si el primer puntero es menor que el segundo puntero o si los dos punteros son iguales; en caso contrario, 1devuelve0

 4.Atención

Se permite comparar un puntero a un elemento de matriz con un puntero a una ubicación de memoria después del último elemento de la matriz, pero no con un puntero a una ubicación de memoria antes del primer elemento.


6. Punteros y matrices

1. Un puntero es una variable que se utiliza para almacenar una dirección de memoria. Las variables de puntero pueden apuntar a cualquier tipo de datos, incluidas las matrices. A través de punteros, podemos acceder y manipular indirectamente los datos en la memoria.
2. Una matriz es una matriz que puede almacenar un conjunto de números. El tamaño de la matriz depende del tipo y la cantidad de elementos.
3. El nombre de la matriz es la dirección del primer elemento de la matriz y la dirección se puede colocar en una variable de puntero. Accediendo a elementos de una matriz a través de punteros 

  • Nombre de la matriz y puntero: en lenguaje C, el nombre de la matriz puede considerarse como un puntero al primer elemento de la matriz. Por ejemplo, para una matriz int arr[5], arrse puede considerar como arr[0]un puntero a. Por lo tanto, puede acceder a los elementos de la matriz mediante punteros, como *arrel primer elemento de la matriz y *(arr + 1)el segundo elemento de la matriz.
  • Además, las operaciones aritméticas de punteros también se pueden aplicar a nombres de matrices. Por ejemplo, arr + 1representa la dirección del segundo elemento de la matriz, arr + 2representa la dirección del tercer elemento de la matriz. Esto se debe a que los elementos de la matriz se almacenan de forma contigua en la memoria.
int main()
{
	int arr[] = { 1,2 };
	int* pa = arr;
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

 

Se puede ver que el nombre de la matriz generalmente representa la dirección del primer elemento de la matriz, pero hay dos excepciones:
1. sizeof (nombre de la matriz), el nombre de la matriz se coloca solo dentro de sizeof, el nombre de la matriz representa la matriz completa , y se calcula el tamaño de la matriz, y la unidad es la palabra Festival.
2.& Nombre de la matriz, el nombre de la matriz representa la matriz completa y se extrae la dirección de la matriz. La dirección de la matriz es la misma que la dirección del primer elemento de la matriz, pero el tipo y el significado son diferentes.


 

7. puntero secundario
 

Las variables de puntero también son variables. Las variables tienen direcciones. Entonces, ¿dónde se almacena la dirección de la variable de puntero?
Este es el puntero secundario. 

int main()
{
	int a = 10;
	int* pa = &a;//一级指针
	int** ppa = &pa;//二级指针
	printf("%d\n", a);
	**ppa = 0;//通过两次解引用来改变值
	printf("%d\n", a);
	return 0;
}

 


8. Matriz de punteros

Una matriz de punteros es una matriz, una matriz que almacena punteros. 

Puede utilizar una matriz de punteros para simular una matriz bidimensional 

int main()
{
	int arr1[] = { 1,2,4,6 };
	int arr2[] = { 7,2,4,4 };
	int arr3[] = { 1,2,9,6 };

	int* p[] = { arr1,arr2,arr3 };

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 


Los punteros son un concepto poderoso y complejo en lenguaje C. Al utilizar punteros, podemos acceder y modificar directamente los datos en la memoria, logrando operaciones de memoria flexibles y eficientes. Sin embargo, debe tener cuidado al utilizar punteros para evitar problemas de punteros nulos y salvajes. Espero que este artículo le ayude a comprender la parte del puntero del lenguaje C.

Supongo que te gusta

Origin blog.csdn.net/qq_74415153/article/details/132861164
Recomendado
Clasificación