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

contenido

1. Preguntas clásicas de prueba escrita

      Pregunta 1

      Pregunta 2

      Pregunta 3

      Pregunta 4

2. Desarrollo de memoria de programas C/C++

3. Matriz flexible

       3.1 Características de los arreglos flexibles

       3.2, el uso de arreglos flexibles

       3.3 Ventajas de los arreglos flexibles


1. Preguntas clásicas de prueba escrita

Pregunta 1

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}
//请问运行Test 函数会有什么样的结果?

Resultado en ejecución: el programa falla

  • problema principal:

La variable de puntero str coloca un puntero nulo y luego llama a la función GetMemory, que pasa la variable de puntero str en sí misma, p es en realidad una copia temporal de str, la p actual es NULL y malloc está en el área de almacenamiento dinámico en este momento Se han solicitado 100 bytes de espacio y se devuelve la dirección de inicio. Suponga que devuelve 0x0012ff80 y lo pone en p. p es un parámetro formal. Una vez que se ejecuta la función GetMemory, p se destruye. En este momento, el 100- tamaño de byte No se puede encontrar la dirección del espacio. El cambio de p no provocará el cambio de str. En este momento, str sigue siendo un puntero nulo. En este momento, si coloca hola mundo en str y lo toma, habrá un problema, y ​​se accederá ilegalmente a la memoria.

  • Preguntas menores:
  1. El uso de la función malloc no determina si es un puntero nulo
  2. No lanzado después del final.
  • Solución: pasar la dirección
  • ley uno:
void GetMemory(char** p)
{
	*p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}
  • Ley dos:
char* GetMemory(char* p)
{
	p = (char*)malloc(100);
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}

Pregunta 2

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
//请问运行Test 函数会有什么样的结果?
  • resultado:

  • Analizar gramaticalmente:

Primero, se crea una variable de puntero str y se le asigna un puntero nulo, str recibe el valor de retorno de GetMemory, la matriz p se coloca hello world\0, y es un espacio abierto en la pila, la matriz está solo dentro de GetMemory function Efectivo, se destruirá cuando la función esté fuera. Incluso si se devuelve la dirección, pero fuera de la función, el espacio de hello world\0 ya no existe. En este momento, str es un puntero salvaje. Para acceder a la la memoria nuevamente es acceder a la memoria ilegalmente, así que imprima un valor aleatorio

  • Solución:
  • Método 1: (modificación estática)
char* GetMemory(void)
{
	static char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
  • Ley dos:
char* GetMemory(void)
{
	char *p = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

Pregunta 3

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}
//请问运行Test 函数会有什么样的结果?
  • resultado:

  • Analizar gramaticalmente:

Aunque el resultado muestra hola como se esperaba, hay un problema con este código, es decir, no se libera, lo que provocará pérdidas de memoria.

  • Solución:
void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
	str = NULL;
}

Pregunta 4

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
//请问运行Test 函数会有什么样的结果?
  • resultado:

  • Analizar gramaticalmente:

Primero, abra 100 bytes de espacio y colóquelo en str, strcpy copiará hello\0 en str, y luego liberará str para liberar el espacio señalado por str, pero free en sí mismo no hará que str se convierta en un puntero nulo. a str, pero el espacio apuntado por str ha sido liberado y devuelto al sistema operativo antes, y no puede ser usado nuevamente.Si copia world a str, accederá a la memoria ilegalmente.

  • Solución: (asigne str a NULL)
void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

2. Desarrollo de memoria de programas C/C++

  •  Varias áreas de asignación de memoria de programa C/C++:
  1. Área de pila (stack): cuando se ejecuta la función, se pueden crear en la pila las unidades de almacenamiento de las variables locales en la función, y estas unidades de almacenamiento se liberan automáticamente cuando finaliza la ejecución de la función. La operación de asignación de memoria de pila está integrada en el conjunto de instrucciones del procesador, que es muy eficiente, pero la capacidad de memoria asignada es limitada. El área de la pila almacena principalmente variables locales, parámetros de función, datos de retorno, direcciones de retorno, etc. asignados por funciones en ejecución.
  2. Heap area (heap): Generalmente asignada y liberada por el programador, si el programador no la libera, puede ser reclamada por el SO al final del programa. El método de asignación es similar a una lista enlazada.
  3. El segmento de datos (área estática) (estático) almacena variables globales y datos estáticos. Liberado por el sistema después de que finaliza el programa.
  4. Segmento de código: el código binario que almacena el cuerpo de la función (funciones miembro de clase y funciones globales).
  • Con esta imagen, podemos entender mejor el ejemplo de la palabra clave estática que modifica las variables locales.

De hecho, a las variables locales ordinarias se les asigna espacio en el área de la pila.La característica del área de la pila es que las variables creadas anteriormente se destruyen cuando quedan fuera del alcance. Sin embargo, las variables modificadas por estática se almacenan en el segmento de datos (área estática).La característica del segmento de datos es que las variables creadas anteriormente no se destruyen hasta el final del programa, por lo que el ciclo de vida se hace más largo.

3. Matriz flexible

En C99, el último elemento de una estructura puede ser una matriz de tamaño desconocido, que se denomina miembro de "matriz flexible".

  • P.ej:
typedef struct st_type
{
	int i;
	int a[0];//柔性数组成员
}type_a;
  • Algunos compiladores informarán un error que no se puede compilar y se puede cambiar a:
typedef struct st_type
{
	int i;
	int a[];//柔性数组成员
}type_a;

3.1 Características de los arreglos flexibles

  1. Un miembro de matriz flexible en una estructura debe estar precedido por al menos otro miembro.
  2. El tamaño de esta estructura devuelta por sizeof no incluye la memoria de la matriz flexible.
  3. Las estructuras que contienen miembros de arreglos flexibles usan la función malloc() para asignar memoria dinámicamente, y la memoria asignada debe ser mayor que el tamaño de la estructura para acomodar el tamaño esperado del arreglo flexible.
  • P.ej:
typedef struct st_type
{
	int i;
	int a[0];//柔性数组成员
}type_a;
int main()
{
	printf("%d\n", sizeof(type_a));//输出的是4
	return 0;
}

3.2, el uso de arreglos flexibles

typedef struct st_type
{
	int i;
	int a[0];//柔性数组成员
}type_a;
//代码一:
int main()
{
	type_a* p = (type_a*)malloc(sizeof(type_a) + 100 * sizeof(int));
	//业务处理
	p->i = 100;
	int i = 0;
	for (i = 0; i < 100; i++)
	{
		p->a[i] = i;
	}
	free(p);
	p = NULL;
	return 0;
}

De esta forma, el miembro de matriz flexible a es equivalente a obtener un espacio continuo de 100 elementos enteros.

3.3 Ventajas de los arreglos flexibles

  • La estructura type_a anterior también se puede diseñar como:
typedef struct st_type
{
	int i;
	int* p_a;
}type_a;
//代码2
int main()
{
	type_a* p = (type_a*)malloc(sizeof(type_a));
	p->i = 100;
	p->p_a = (int*)malloc(p->i * sizeof(int));
	//业务处理
	int i = 0;
	for (i = 0; i < 100; i++)
	{
		p->p_a[i] = i;
	}
	//释放空间
	free(p->p_a);
	p->p_a = NULL;
	free(p);
	p = NULL;
	return 0;
}

El código 1 y el código 2 anteriores pueden cumplir la misma función, pero la implementación de la matriz flexible del método 1 tiene dos ventajas:

  • El primer beneficio es: fácil liberación de memoria.

Si nuestro código está en una función que utilizan otros, realiza una segunda asignación de memoria y devuelve la estructura completa al usuario. El usuario puede liberar la estructura llamando gratis, pero el usuario no sabe que los miembros de la estructura también deben estar libres, por lo que no puede esperar que el usuario se entere. Por lo tanto, si asignamos la memoria de la estructura y la memoria requerida por sus miembros al mismo tiempo, y devolvemos un puntero de estructura al usuario, el usuario puede liberar toda la memoria haciendo un free.

  • El segundo beneficio es: esto es bueno para la velocidad de acceso.

La memoria contigua es beneficiosa para mejorar la velocidad de acceso y reducir la fragmentación de la memoria.

Supongo que te gusta

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