Punteros y pérdidas de memoria en lenguaje C
Pregúntele a cualquiera que use C cuáles son sus cosas que le molestan, y muchos de ellos probablemente responderán sugerencias y pérdidas de memoria. De hecho, estas son las cosas que consumen la mayor parte del tiempo de depuración de un desarrollador. Los punteros y las pérdidas de memoria pueden parecer desalentadores para algunos desarrolladores, pero una vez que comprende los conceptos básicos de los punteros y sus operaciones de memoria asociadas, son excelentes herramientas que tiene en el lenguaje C.
Este artículo compartirá contigo los secretos que los desarrolladores deben conocer antes de comenzar a programar con punteros. El contenido de este artículo incluye:
Tipos de operaciones de puntero que provocan daños en la memoria
Puntos de control que se deben considerar al utilizar la asignación de memoria dinámica
Escenarios que conducen a pérdidas de memoria
p>Si sabe de antemano qué es probable que salga mal, puede evitar cuidadosamente los errores y eliminar la mayoría de los problemas relacionados con el puntero y la memoria.
¿Qué podría salir mal?
Hay varios escenarios de problemas que pueden surgir y causar problemas una vez completada la compilación. Puede utilizar la información de este artículo para evitar muchos problemas al trabajar con punteros.
Memoria no inicializada
En este ejemplo, a p se le han asignado 10 bytes. Estos 10 bytes pueden contener datos basura, como se muestra en la Figura 1.
char *p = malloc (10);
Figura 1. Datos basura
Si un determinado segmento de código intenta acceder a p antes de asignarle un valor, es posible que obtenga valores basura y que su programa tenga un comportamiento impredecible. p puede tener valores que su programa nunca esperó.
Una buena práctica es usar siempre memset y malloc juntos, o usar calloc.
char *p = malloc (10);
memset(p, '\0', 10);
Ahora, incluso si el mismo fragmento de código try Este fragmento también manejará correctamente los valores nulos (que idealmente debería tener) accediendo a p antes de asignarlo, y luego tendrá el comportamiento correcto.
Sobrescritura de memoria
Dado que a p se le han asignado 10 bytes, si un fragmento de código intenta escribir un valor de 11 bytes en p, la operación no le indicará que "coma" automáticamente un byte de alguna otra ubicación. Supongamos que el puntero q representa esta memoria.
Figura 2. Contenido q original
Figura 3. Contenido q sobrescrito
Como resultado, el puntero q tendrá contenido que nunca se esperaba. Incluso si su módulo está lo suficientemente bien codificado, puede tener un comportamiento incorrecto porque un determinado módulo de memoria realiza ciertas operaciones de memoria. El siguiente fragmento de código de muestra también ilustra este escenario.
char *name = (char *) malloc(11);
// Asigna algún valor al nombre
memcpy (p, nombre, 11); // El problema comienza aquí
En este ejemplo, la operación memcpy intenta escribir 11 bytes en p, al que solo se le han asignado 10 bytes.
Como buena práctica, siempre que escriba un valor en un puntero, asegúrese de verificar la cantidad de bytes disponibles y la cantidad de bytes escritos. Normalmente, la función memcpy será el punto de control utilizado para este propósito.
Memoria leída fuera de límites
Memoria leída fuera de límites (sobrelectura) significa que el número de bytes leídos es mayor de lo que debería ser.
Este problema no es demasiado grave y no se discutirá en detalle aquí. El siguiente código proporciona un ejemplo.
char *ptr = (char *)malloc(10);
char nombre[20];
memcpy (nombre, ptr, 20); / El problema comienza aquí
En este ejemplo, la operación memcpy intenta leer 20 bytes de ptr, pero solo se asignan 10 bytes. Esto también puede conducir a resultados no deseados.