Asignación dinámica de memoria en C: malloc(), calloc()

⚡ Resumen inteligente

La asignación dinámica de memoria en C reserva y libera memoria del montón en tiempo de ejecución utilizando las funciones malloc(), calloc(), realloc() y free() de la biblioteca stdlib.h, lo que permite a los programas dimensionar matrices y estructuras de forma flexible cuando se desconocen los requisitos antes de la ejecución.

  • 🧠 Pila vs montón: Las variables básicas utilizan la pila automática, mientras que la memoria dinámica reside en el montón y se gestiona manualmente mediante punteros.
  • 📦 malloc(): Reserva un bloque no inicializado del tamaño en bytes solicitado y devuelve un puntero vacío, o NULL cuando la memoria es insuficiente.
  • 🔢 calloc (): Asigna múltiples bloques para matrices, establece cada byte a cero y devuelve un puntero al primer bloque.
  • 🔄 realloc(): Cambia el tamaño de un bloque existente, ampliándolo o reduciéndolo, y conservando el contenido original en una ubicación posiblemente nueva.
  • 🧹 libre(): Devuelve la memoria al montón; cada malloc() o calloc() necesita un free() correspondiente para evitar fugas.
  • 🤖 Ayuda de IA: Los asistentes de IA y GitHub Copilot elaboran código de asignación y detectan llamadas a free() faltantes y fugas de memoria.

Asignación de memoria dinámica en C

¿Cómo funciona la gestión de memoria en C?

Cuando se declara una variable utilizando un tipo de dato básico, el compilador de C asigna automáticamente espacio de memoria para la variable en un grupo de memoria llamado pila.

Por ejemplo, una variable de tipo float suele ocupar 4 bytes (según la plataforma) al declararse. Podemos verificar esta información utilizando el operador sizeof, como se muestra en el siguiente ejemplo.

#include <stdio.h>
int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0;}

La salida será:

 The size of float is 4 bytes

Además, una matriz con un tamaño específico se asigna en bloques contiguos de memoria, cada bloque tiene el tamaño de un elemento:

#include <stdio.h>
int main() { float arr[10];
printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}

El resultado es:

 The size of the float array with 10 element is 40

Como ya hemos visto, al declarar un tipo de dato básico o un array, la memoria se gestiona automáticamente. Sin embargo, en C existe un proceso para asignar memoria que permite implementar un programa cuyo tamaño no se define hasta la ejecución (tiempo de ejecución). Este proceso se denomina "asignación dinámica de memoria".

Asignación de memoria dinámica en C

La asignación dinámica de memoria (DMA) consiste en la asignación y liberación manual de memoria según las necesidades de programación. La memoria dinámica se gestiona y se sirve mediante punteros que apuntan al espacio de memoria recién asignado en un área que denominamos montón (heap).

Ahora puedes crear y destruir una serie de elementos dinámicamente en tiempo de ejecución sin ningún problema. En resumen, la administración automática de memoria usa la pila y la asignación de memoria dinámica C usa el montón.

La biblioteca tiene funciones responsables de la gestión dinámica de la memoria.

Función Propósito
malloc () Asigna la memoria del tamaño solicitado y devuelve el puntero al primer byte de
espacio asignado.
calloc () Asigna el espacio para los elementos de una matriz. Inicializa los elementos a cero y devuelve un puntero a la memoria.
realloc () Se utiliza para modificar el tamaño del espacio de memoria previamente asignado.
Gratis() Libera o vacía el espacio de memoria previamente asignado.

Analicemos las funciones anteriores con su aplicación.

función malloc() en C

La función C malloc() significa asignación de memoria. Es una función que se utiliza para asignar un bloque de memoria de forma dinámica. Reserva espacio de memoria de un tamaño específico y devuelve el puntero nulo que apunta a la ubicación de la memoria. El puntero devuelto suele ser de tipo nulo. Significa que podemos asignar la función C malloc() a cualquier puntero.

Sintaxis de malloc() Función:

ptr = (cast_type *) malloc (byte_size);

Aquí,

  • ptr es un puntero de cast_type.
  • La función C malloc() devuelve un puntero a la memoria asignada de byte_size.

Ejemplo de malloc():

Example: ptr = (int *) malloc (50)

Cuando esta declaración se ejecuta con éxito, se reserva un espacio de memoria de 50 bytes. La dirección del primer byte del espacio reservado se asigna al puntero ptr de tipo int.

Considere otro ejemplo:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

Salida:

Value of the 6th integer is 480

Función C malloc()

  1. Observe que se utilizó sizeof(*ptr) en lugar de sizeof(int) para que el código sea más robusto cuando la declaración *ptr se convierta a un tipo de datos diferente más adelante.
  2. La asignación puede fallar si la memoria no es suficiente. En este caso, devuelve un puntero NULL. Por lo tanto, debe incluir código para verificar si hay un puntero NULL.
  3. Tenga en cuenta que la memoria asignada es contigua y se puede tratar como una matriz. Podemos utilizar la aritmética de punteros para acceder a los elementos de la matriz en lugar de utilizar corchetes [ ]. Recomendamos utilizar + para hacer referencia a los elementos de la matriz porque el uso de incrementos ++ o += cambia la dirección almacenada por los elementos de la matriz. puntero.

La función Malloc() también se puede utilizar con el tipo de datos de carácter, así como con tipos de datos complejos como estructuras.

función gratuita () en C

El recuerdo para las variables se desasigna automáticamente en el momento de la compilación. En la asignación de memoria dinámica, debe desasignar la memoria explícitamente. Si no lo hace, es posible que encuentre un error de falta de memoria.

La función free() se utiliza para liberar memoria en C. Al liberar memoria en tu programa, dejas más memoria disponible para su uso posterior.

Por ejemplo:

#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
  *(ptr + 2) = 50;
  printf("Value of the 2nd integer is %d",*(ptr + 2));
}
free(ptr);
}

Salida:

 Value of the 2nd integer is 50

función calloc() en C

La función calloc() de C significa asignación contigua. Esta función se utiliza para asignar múltiples bloques de memoria. Es una función de asignación de memoria dinámica que se utiliza para asignar memoria a estructuras de datos complejas, como matrices y estructuras.

La función Malloc() se usa para asignar un solo bloque de espacio de memoria, mientras que calloc() en C se usa para asignar múltiples bloques de espacio de memoria. Cada bloque asignado por la función calloc() es del mismo tamaño.

Sintaxis de calloc() Función:

ptr = (cast_type *) calloc (n, size);

La declaración anterior se utiliza para asignar n bloques de memoria del mismo tamaño.

Una vez asignado el espacio de memoria, todos los bytes se inicializan a cero.

Se devuelve el puntero que se encuentra actualmente en el primer byte del espacio de memoria asignado.

Siempre que hay un error al asignar espacio de memoria, como por ejemplo falta de memoria, se devuelve un puntero nulo.

Ejemplo de calloc():

El siguiente programa calcula la suma de una secuencia aritmética.

#include <stdio.h>
    int main() {
        int i, * ptr, sum = 0;
        ptr = calloc(10, sizeof(int));
        if (ptr == NULL) {
            printf("Error! memory not allocated.");
            exit(0);
        }
        printf("Building and calculating the sequence sum of the first 10 terms \ n ");
        for (i = 0; i < 10; ++i) { * (ptr + i) = i;
            sum += * (ptr + i);
        }
        printf("Sum = %d", sum);
        free(ptr);
        return 0;
    }

Resultado:

Building and calculating the sequence sum of the first 10 terms
Sum = 45

calloc() vs malloc(): diferencias clave

A continuación se muestra la diferencia clave entre malloc() Vs calloc() C ª:

La función calloc() es generalmente más adecuada y eficiente que la función malloc(). Si bien ambas funciones se utilizan para asignar espacio de memoria, calloc() puede asignar múltiples bloques a la vez. No es necesario solicitar un bloque de memoria cada vez. La función calloc() se utiliza en estructuras de datos complejas que requieren mayor espacio de memoria.

El bloque de memoria asignado por calloc() en C siempre se inicializa a cero, mientras que en la función malloc() en C, siempre contiene un valor basura.

función realloc() en C

Mediante la función realloc() de C, puedes añadir más memoria a una memoria ya asignada. Esta función expande el bloque actual sin modificar el contenido original. En C, realloc() significa reasignación de memoria.

realloc() también se puede utilizar para reducir el tamaño de la memoria previamente asignada.

Sintaxis de la función realloc():

ptr = realloc (ptr,newsize);

La declaración anterior asigna un nuevo espacio de memoria con un tamaño específico en la variable newsize. Después de ejecutar la función, el puntero volverá al primer byte del bloque de memoria. El nuevo tamaño puede ser mayor o menor que la memoria anterior. No podemos estar seguros de que el bloque recién asignado apunte a la misma ubicación que el bloque de memoria anterior. Esta función copiará todos los datos anteriores en la nueva región. Se asegura de que los datos permanezcan seguros.

Ejemplo de reasignación():

#include <stdio.h>
int main () {
   char *ptr;
   ptr = (char *) malloc(10);
   strcpy(ptr, "Programming");
   printf(" %s,  Address = %u\n", ptr, ptr);

   ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size
   strcat(ptr, " In 'C'");
   printf(" %s,  Address = %u\n", ptr, ptr);
   free(ptr);
   return 0;
}

Siempre que la función realloc() en C da como resultado una operación fallida, devuelve un puntero nulo y también se liberan los datos anteriores.

Matrices dinámicas en C

Una matriz dinámica en C permite que la cantidad de elementos crezca según sea necesario. Las matrices dinámicas de C se utilizan ampliamente en algoritmos de ciencias de la computación.

En el siguiente programa, hemos creado y redimensionado una matriz dinámica en C

#include <stdio.h>
    int main() {
        int * arr_dynamic = NULL;
        int elements = 2, i;
        arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks
        for (i = 0; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        elements = 4;
        arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); //reallocate 4 elements
        printf("After realloc\n");
        for (i = 2; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        free(arr_dynamic);
    }

Resultado del programa C Dynamic Array en la pantalla:

 
arr_dynamic[0]=0
arr_dynamic[1]=1
After realloc
arr_dynamic[0]=0
arr_dynamic[1]=1
arr_dynamic[2]=2
arr_dynamic[3]=3

Preguntas Frecuentes

Se produce una fuga de memoria cuando la memoria del montón ocupada por malloc() o calloc() nunca se libera. Para evitarlo, acompañe cada asignación con una llamada a free() correspondiente una vez que el bloque ya no sea necesario.

Un puntero colgante aún contiene la dirección de memoria que free() ya ha liberado. Desreferenciarlo provoca un comportamiento indefinido, por lo que se debe asignar NULL al puntero inmediatamente después de liberarlo para evitar problemas.

No. C no tiene recolector de basura, por lo que la memoria del montón nunca se recupera automáticamente. El programador debe liberar cada bloque explícitamente con free(); de lo contrario, la asignación persiste hasta que finaliza el programa.

No. Llamar a free() dos veces en una misma dirección es una doble liberación de memoria y provoca un comportamiento indefinido o fallos del sistema. Establecer el puntero a NULL después de la primera llamada a free() hace que las llamadas posteriores a free() sean inofensivas.

realloc(NULL, size) funciona exactamente igual que malloc(size) y asigna un nuevo bloque. realloc(ptr, 0) libera el bloque, por lo que siempre se captura el puntero devuelto en lugar de sobrescribir el original.

Herramientas como Valgrind, AddressSanitizer y Dr. Memory track cada asignación y bloques de informe que nunca se liberaron, junto con la línea exacta, helping Localizas las fugas antes del lanzamiento.

Sí. Un asistente de codificación con IA genera secuencias de malloc(), calloc() y free() a partir de una solicitud, explica los errores de puntero e indica las llamadas a free() que faltan. Siempre compile y pruebe el código generado antes de confiar en él.

Copiloto de GitHub Sugiere bloques de asignación, comprobaciones de NULL y llamadas free() coincidentes a partir de un comentario; revise cada autocompletado para detectar fugas y tamaños correctos antes de enviarlo.

Resumir este post con: