[C Avanzado] Gestión de memoria dinámica (1)

contenido

1. ¿Por qué existe la asignación de memoria dinámica?

2. Introducción a las funciones de memoria dinámica

      2.1, malloc y gratis

      2.2, calloc

      2.3, reasignar

3. Errores comunes de memoria dinámica

      3.1 Operación de desreferenciación en puntero NULL

      3.2 Acceso transfronterizo al espacio de desarrollo dinámico

      3.3 Usar liberación libre para memoria desarrollada no dinámicamente

      3.4 Uso libre para liberar parte de una memoria desarrollada dinámicamente

      3.5 Liberar la misma pieza de memoria dinámica varias veces

      3.6 Abre la memoria dinámicamente y olvídate de liberarla (pérdida de memoria)


1. ¿Por qué existe la asignación de memoria dinámica?

  • Los métodos de desarrollo de memoria que hemos dominado son:
int val = 20;//在栈空间上开辟四个字节
char arr[1000] = {0};//在栈空间上开辟1000个字节的连续空间
  • Sin embargo, la forma de apertura del espacio antes mencionada tiene dos características:
  1. El tamaño del espacio a abrir es fijo.
  2. Cuando se declara una matriz, se debe especificar la longitud de la matriz y la memoria que necesita se asigna en el momento de la compilación.

Pero la necesidad de espacio no se limita a lo anterior. A veces, el tamaño del espacio que necesitamos solo se puede conocer cuando el programa se está ejecutando, y la forma en que se compila la matriz para abrir espacio no se puede satisfacer. Por ejemplo, el tamaño de 1000 bytes definido por el tipo char en el código anterior, si solo se necesitan 10 bytes, los 990 bytes restantes se desperdiciarán. .

En este momento, solo puede intentar abrir el almacenamiento dinámico.

  • Revise la asignación de espacio abierta por la memoria dinámica:

2. Introducción a las funciones de memoria dinámica

2.1, malloc y gratis

  • malloc:

El lenguaje C proporciona una función para el desarrollo de la memoria dinámica:

void* malloc (size_t size);

Esta función solicita un espacio libre contiguo en la memoria y devuelve un puntero a este espacio.

  1. Si la apertura tiene éxito, se devuelve un puntero al espacio abierto.
  2. Si el desarrollo falla, se devuelve un puntero NULL, por lo que se debe comprobar el valor de retorno de malloc.
  3. El tipo del valor devuelto es void*, por lo que la función malloc no conoce el tipo del espacio abierto, y el propio usuario
  4. para decidir.
  5. Si el tamaño del parámetro es 0, el comportamiento de malloc no está definido por el estándar y depende del compilador.
  • Nota: use la función malloc para hacer referencia al archivo de encabezado #include<stdlib.h>
  • P.ej:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……

	//释放
	return 0;
}
  • gratis:

El lenguaje C proporciona otra función gratuita, que es especialmente utilizada para la liberación y recuperación de memoria dinámica, el prototipo de función es el siguiente:

void free (void* ptr);
  • La función libre se utiliza para liberar la memoria asignada dinámicamente.
  1. Si el espacio al que apunta el parámetro ptr no se asigna dinámicamente, el comportamiento de la función libre no está definido.
  2. Si el parámetro ptr es un puntero NULL, la función no hace nada.
  • Tanto malloc como free se declaran en el archivo de encabezado stdlib.h.
  • Por ejemplo, hay enlaces de liberación y uso en el código anterior, y todos los códigos se perfeccionan de la siguiente manera:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

2.2, calloc

El lenguaje C también proporciona una función llamada calloc, que también se usa para la asignación dinámica de memoria. El prototipo es el siguiente:

void* calloc (size_t num, size_t size);
  • num representa el número de elementos y size representa el tamaño de cada elemento.
  1. La función de la función es abrir un espacio para num elementos de tamaño e inicializar cada byte del espacio a 0.
  2. La única diferencia con la función malloc es que calloc inicializará cada byte del espacio solicitado en ceros antes de devolver la dirección.
  • P.ej:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

En comparación con la función mallo, la función malloc es más eficiente. La función malloc en sí misma no tiene la función de inicialización y devuelve directamente la dirección.

2.3, reasignar

La aparición de la función realloc hace que la gestión dinámica de la memoria sea más flexible.

A veces encontramos que el espacio solicitado en el pasado es demasiado pequeño, y a veces sentimos que el espacio solicitado es demasiado grande.Para usar la
memoria en un tiempo razonable, debemos ajustar de manera flexible el tamaño de la memoria. La función realloc puede
ajustar el tamaño de la memoria asignada dinámicamente.

El prototipo de la función es el siguiente:

void* realloc (void* ptr, size_t size);
  • ptr es la dirección de memoria para ajustar
  • el tamaño es el nuevo tamaño después del ajuste
  • El valor devuelto es la posición inicial de la memoria ajustada.
  • Sobre la base de ajustar el tamaño del espacio de memoria original, esta función también moverá los datos en la memoria original al nuevo espacio.
  • Hay dos situaciones en las que realloc ajusta el espacio de memoria:
  1. Caso 1: hay suficiente espacio después del espacio original 
  2. Caso 2: No hay suficiente espacio después del espacio original

  •  Caso 1

En el caso 1, para expandir la memoria, agregue espacio directamente después de la memoria original y los datos en el espacio original no cambiarán.

  • Caso 2

Cuando es el caso 2, cuando no hay suficiente espacio después del espacio 54 original, el método de expansión es: encontrar otro espacio continuo de tamaño adecuado en el espacio de almacenamiento dinámico para usar. Esta función devuelve una nueva dirección de memoria.

Debido a las dos situaciones anteriores, se debe prestar atención al uso de la función de reasignación. P.ej:

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//需要增容
	int* ptr = (int*)realloc(p, 80);
	if (NULL != ptr)
	{
		p = ptr;
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

3. Errores comunes de memoria dinámica

3.1 Operación de desreferenciación en puntero NULL

#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(INT_MAX);
	//INT_MAX:整型最大的值
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//出问题,因为malloc开辟的空间过大,超过限制了,所以会返回一个控指针,此时p就是一个空指针
	return 0;
}
  • En este punto, depuramos para ver si p está vacío:

  • La forma correcta de escribir es la siguiente: debe juzgar si p es un puntero nulo
#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(INT_MAX);
	//INT_MAX:整型最大的值

    // 判断:
 	if (p == NULL)
		return 0;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//出问题,因为malloc开辟的空间过大,超过限制了,所以会返回一个控指针,此时p就是一个空指针
	return 0;
}

3.2 Acceso transfronterizo al espacio de desarrollo dinámico

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//申请10个字符的空间:
	char* p = (char*)malloc(10 * sizeof(char));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//使用
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = 'a' + i; // i=10的时候越界访问
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}
  • La ortografía correcta es la siguiente:
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 'a' + i;
	}

3.3 Usar liberación libre para memoria desarrollada no dinámicamente

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

3.4 Uso libre para liberar parte de una memoria desarrollada dinámicamente

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}

3.5 Liberar la misma pieza de memoria dinámica varias veces

void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);//重复释放
}
  • No se puede volver a liberar un espacio, pero se puede volver a liberar asignándolo a un puntero nulo, de la siguiente manera:
void test()
{
	int* p = (int*)malloc(100);
	free(p);
    p = NULL;
	free(p);//重复释放
}

3.6 Abre la memoria dinámicamente y olvídate de liberarla (pérdida de memoria)

#include<stdio.h>
#include<stdlib.h>
void test()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 0;
	}
	//使用
	//……
	//忘记释放,就会出现内存泄露
}
int main()
{
	test();
	return 0;
}
  • Si olvida liberar, habrá una pérdida de memoria
  1. Para funciones sin devolución de tipo void, la liberación debe realizarse dentro de la función; de lo contrario, no se encontrará la función después de salir de la función.
  2. Para funciones con un valor de retorno, el valor de retorno se puede liberar en la función principal

En resumen, se liberará el espacio de la aplicación.

Supongo que te gusta

Origin blog.csdn.net/bit_zyx/article/details/122737321
Recomendado
Clasificación