Lenguaje C elemental - puntero

Hola, nos volvemos a encontrar, el tiempo vuela tan rápido, he escrito tantos blogs en un abrir y cerrar de ojos, en el próximo año, el editor también estudiará y escribirá código en serio, progresaremos juntos, entonces hoy Comencemos a hablar sobre nuestros punteros El capítulo de punteros es un capítulo difícil en el aprendizaje del lenguaje C. No hablemos tonterías, comencemos nuestro estudio.

1. ¿Qué es un puntero?
¿Qué son los punteros?
Dos puntos clave para la comprensión del puntero:

  1. Un puntero es el número de la unidad más pequeña en la memoria, es decir, la dirección
  2. El puntero en el idioma hablado generalmente se refiere a la variable de puntero, que es una variable utilizada para almacenar la dirección de memoria.
    Resumen: El puntero es la dirección, y el puntero en el idioma hablado generalmente se refiere a la variable de puntero

inserte la descripción de la imagen aquí
Almacenamos una dirección en la memoria, cada unidad de memoria corresponde a un número correspondiente, la unidad es un byte y nuestro puntero se usa para almacenar la dirección

variable puntero

Podemos usar & (operador de dirección) para sacar la dirección real de la memoria de la variable y almacenar la dirección en una variable, que es una variable de puntero

#include <stdio.h>
int main()
{
    
    
 int a = 10;//在内存中开辟一块空间
 int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
    //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
中,p就是一个之指针变量。
 return 0;
}

Resumen:
variables de puntero, variables utilizadas para almacenar direcciones. (El valor almacenado en el puntero se trata como una dirección).
La pregunta aquí es: ¿
qué tan grande es una unidad pequeña? (1 byte)
¿Cómo se direcciona?
Después de un cuidadoso cálculo y pesaje, encontramos que es más apropiado asignar un byte a una dirección correspondiente.
Para una máquina de 32 bits, suponiendo que hay 32 líneas de dirección, luego suponiendo que cada línea de dirección genera un nivel alto (voltaje alto) y un nivel bajo (voltaje bajo) cuando el direccionamiento es (1 o 0); entonces 32 ¿
Qué
es la dirección generada por la línea de dirección?

Podemos entenderlo de esta manera, si hay 32 líneas de dirección, cada una de nuestras líneas de dirección se puede representar con 0 y 1, entonces podemos escribirlo como
000000000000000000000000000000000000000000000000000000000000000000000000000000
000001
0
1000000000000000000000000000000
10000000000000000000000000000001
1111111111111111111111111111111111111


Continuar así es equivalente a los 32 métodos de almacenamiento de 2, ¿cuánto son las 32 veces de 2
(2^32Byte == 2^32/1024KB == 2 32/1024/1024MB==2 32/1024/1024/ 1024GB == 4GB) 4G gratis para direccionamiento.

Aquí lo entendemos:
en una máquina de 32 bits, la dirección es una secuencia binaria compuesta por 32 0 o 1, y la dirección debe almacenarse en 4 bytes, por lo que el
tamaño de una variable de puntero debe ser de 4 bytes.
Entonces, si en una máquina de 64 bits, si hay 64 líneas de dirección, el tamaño de una variable de puntero es de 8 bytes para almacenar una dirección.
2. Punteros y tipos de punteros

Todos sabemos que las variables tienen diferentes tipos, enteros, coma flotante, etc. ¿El puntero tiene un tipo?

la respuesta es sí

int num = 10;
p = &num;

Cuando veamos el código anterior, extraiga la dirección de num y guárdela en p, luego todos pensarán en cuál debería ser nuestro tipo de puntero p.

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

El puntero de tipo char* se utiliza para almacenar la dirección de la variable de tipo char.
El puntero de tipo short* se utiliza para almacenar la dirección de la variable de tipo short.
El puntero de tipo int* se utiliza para almacenar la dirección de la variable de tipo int.

Visto aquí, ¿tenemos alguna duda, es decir, definimos el tipo de variable puntero, aunque su tamaño es el mismo, pero alguna vez nos hemos puesto a pensar por qué la definimos así?

La respuesta es que el tipo de puntero determina cuánto agregar 1. Es como una persona con piernas largas y una persona con piernas cortas. Todos son un paso, pero la longitud del paso es diferente. Este es el papel de nuestra variable de puntero tipo. Usamos código para que todos entiendan mejor

2.1 puntero ± entero

#include <stdio.h>
//演示实例
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;
}

inserte la descripción de la imagen aquí

El primer &n le quita el tamaño al entero entero, aunque su dirección es la misma que las demás, pero es la variable entera de la variable n, ocupando cuatro bytes, por lo que le suma 1 para saltarse cuatro direcciones

La segunda pc es la dirección almacenada en el primer byte de los cuatro bytes de la variable entera, por lo que suma 1 para omitir una dirección
pi también es la dirección de toda la variable n, y usamos un puntero entero para recibir, entonces, ¿qué se salta al agregar 1 también tiene un tamaño de cuatro bytes, y un byte es una dirección

Resumen:
el tipo de puntero determina cuánta autoridad (cuántos bytes se pueden manipular) al eliminar la referencia del puntero.
Por ejemplo: quitar la referencia a un puntero char* solo puede acceder a un byte, mientras que quitar la referencia a un puntero int* puede acceder a cuatro bytes.

3. Puntero salvaje

Concepto: un puntero salvaje significa que la ubicación a la que apunta el puntero es desconocida (aleatoria, incorrecta y sin restricciones claras)

3.1 Causas de los punteros salvajes

  1. el puntero no está inicializado
#include <stdio.h>
int main()
{
    
     
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

No definimos el tipo de la variable puntero *p

  • 2 puntero fuera de los límites de acceso
#include <stdio.h>
int main()
{
    
    
    int arr[10] = {
    
    0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
    
    
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

Nuestra matriz solo tiene diez elementos, pero el alcance de nuestro acceso está más allá del rango de la matriz,
y el contenido de la dirección detrás de la desreferencia aquí es el contenido de la dirección detrás de la dirección de nuestra matriz, que puede ser un número aleatorio

Aquí, el editor usa una metáfora para describir al braco salvaje. El braco salvaje es en realidad un perro feroz. Si no se usa razonablemente, causará resultados irreversibles. Pero solo necesitamos atarlo con una cuerda para que sea bien, y aquí, NULL (puntero nulo) generalmente se usa como una cadena.

  • Cómo evitar los punteros salvajes
  1. inicialización del puntero
  2. Puntero cuidadoso fuera de los límites
  3. El puntero apunta al espacio para liberar incluso si está configurado en NULL
  4. Evite devolver la dirección de una variable local
  5. Verifique la validez del puntero antes de usarlo
#include<stdio.h>
int* test()
{
    
    
	int a = 10;
	return &a;
}
int main()
{
    
    
	int* p = test();
	printf("%p", p);

	return 0;
}
#include<stdio.h>
int* test()
{
    
    
	int a = 10;
	return &a;
}
int main()
{
    
    
	int* p = test();
	*p = 100;

	return 0;
}

También queremos evitar el código anterior, porque las variables locales se destruyen automáticamente cuando quedan fuera del alcance, pero nuestra dirección no se destruirá al final. análisis

  1. Verifique la validez del puntero antes de usarlo
#include <stdio.h>
int main()
{
    
    
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
    
    
        *p = 20;
   }
    return 0;
}

4.1 Puntero ± Entero

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
    
    
     *vp++ = 0;
}

Cambie el contenido de la dirección vp de punto flotante a 0 y cambie cinco direcciones.
Debido a que vp es un puntero de tipo flotante, el movimiento ± del puntero de tipo flotante es unidades flotantes.

4.2 Puntero-Puntero
Hemos usado la función strlen para encontrar la longitud de una cadena antes, y ahora también podemos usar un puntero para encontrar la longitud de una cadena.

#include<stdio.h>
#include<string.h>
int main()
{
    
    
	char str[] = "abcdef";
	int len = strlen(str);
	printf("%d ", len);
	return 0;
}

Esta es la longitud de la cadena que usamos para encontrar la función strlen, ahora usamos el puntero para encontrar, definimos una función my_strlen para encontrar la longitud de la cadena

#include<stdio.h>
int my_strlen(char* str)
{
    
    
	int count = 0;
	while (*str != '\0')
	{
    
    
		count++;
		str++;
	}
	return count;
}
int main()
{
    
    

	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d", len);
	return 0;
}

Por supuesto, también hemos usado la idea de la función recursiva para escribir código antes, y aquí lo traeremos de vuelta para recordar

#include<stdio.h>
int my_strlen(char* str)
{
    
    
	if (*str != '\0')
	{
    
    
		return 1 + my_strlen(str+1);
	}
}
int main()
{
    
    

	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d", len);
	return 0;
}

Ahora tenemos al menos tres formas de encontrar la longitud de una cadena

4.3 Operaciones relacionales sobre punteros

for(vp = &values[N_VALUES]; vp > &values[0];)
{
    
    
    *--vp = 0;
}
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
    
    
    *vp = 0

De hecho, la tarea se puede completar con éxito en la mayoría de los compiladores, pero aún debemos evitar escribir de esta manera, porque el estándar no garantiza que funcione.

Estándar: 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.

5. Punteros y matrices

Echemos un vistazo a la siguiente cadena de código

#include <stdio.h>
int main()
{
    
    
 int arr[10] = {
    
    1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

inserte la descripción de la imagen aquí

Se puede ver que el contenido de sus direcciones es el mismo, y siempre hemos enfatizado en el estudio anterior que el nombre del arreglo es la dirección del primer elemento, salvo dos excepciones especiales (sizeof) (&), en cualquier otro caso el el nombre de la matriz es la dirección del primer elemento

Dado que el nombre de la matriz se puede almacenar como una dirección en un puntero, nos es posible usar un puntero para acceder a uno.

#include<stdio.h>
int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,0 };
	int* p = arr;//存放首元素地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
    
    
		printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

inserte la descripción de la imagen aquí
Entonces puede usar un puntero para acceder a la dirección de la matriz

Entonces p+i en realidad calcula la dirección del subíndice i de la matriz arr.
6. Puntero secundario

Una variable de puntero también es una variable, y una variable tiene una dirección.¿Dónde se almacena la dirección de la variable de puntero?

inserte la descripción de la imagen aquí
*ppa encuentra pa desreferenciando la dirección en ppa, y *ppa realmente accede a pa.int
b = 20;
*ppa = &b;//equivalente a pa = &b;

**ppa primero encuentra pa a través de *ppa, y luego desreferencia pa: *pa, luego encuentra a

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

7. Matriz de punteros

¿Una matriz de punteros es un puntero o una matriz?
Respuesta: una matriz. es una matriz de punteros.
Matrices Ya conocemos las matrices de enteros, las matrices de caracteres.

inserte la descripción de la imagen aquí

Lo anterior debe ser int arr[4]

inserte la descripción de la imagen aquí
Entonces, ¿cómo es nuestra matriz de punteros?
inserte la descripción de la imagen aquí
El puntero también está terminado, y aprenderé más sobre los punteros más adelante, porque los punteros son realmente importantes. Si conoce el lenguaje C, debe conocer los punteros. Este es el final de nuestro intercambio de hoy, gracias Todos tienen que apoyarte, tu apoyo es mi motivación, bye

Supongo que te gusta

Origin blog.csdn.net/2301_76895050/article/details/131648435
Recomendado
Clasificación