Asignación de memoria estática y dinámica en C

La memoria se divide en unidades direccionables más pequeñas llamadas bytes . Supongamos que se trata de pequeñas cajas como bytes . Cada byte tiene su propia dirección según la siguiente tabla. Por ejemplo: 0, 1, 2, 3, 4, 5, 6, etc.

Memory

¿Cómo utiliza el programa la memoria?

La Memoria se divide en tres secciones. 

  • Memoria Heap : Es una parte de la memoria principal . No está organizado y se trata como un recurso cuando requiere su uso si no se libera. La memoria del montón no se puede usar directamente con la ayuda de un puntero .
  • Stack Memory : Almacena variables temporales creadas por una función . En stack , las variables se declaran, almacenan e inicializan durante el tiempo de ejecución. Sigue el método Primero en entrar, último en salir, lo que significa que cualquier elemento que se almacenará en último lugar se eliminará primero cuando no esté en uso.
  • Sección de código : Cada vez que se ejecuta el programa, se llevará a la memoria principal. Este programa se almacenará en la sección de código. Según el programa, decidirá si utilizar las secciones de pila o montón.

A continuación se muestra la imagen para ilustrar cómo el programa utiliza la memoria:

How program uses memory

Asignación de memoria estática

En la asignación de memoria estática, cada vez que se ejecuta el programa, fija el tamaño que tomará el programa y no se puede cambiar más. Por lo tanto, los requisitos de memoria exactos deben conocerse antes. El compilador realizará automáticamente la asignación y desasignación de memoria . Cuando todo se hace en tiempo de compilación (o) antes del tiempo de ejecución, se denomina asignación de memoria estática.

Características clave:

  • La asignación y la desasignación las realiza el compilador.
  • Utiliza una pila de estructuras de datos para la asignación de memoria estática.
  • Las variables se asignan de forma permanente.
  • Sin reutilización.
  • La ejecución es más rápida que la asignación de memoria dinámica.
  • La memoria se asigna antes del tiempo de ejecución.
  • Es menos eficiente.

Por ejemplo:

C++

// C++ program to illustrate the
// concept of memory allocation
#include <iostream>
using namespace std;
  
// Driver Code
void main()
{
    int a; // 2 bytes
    long b; // 4 bytes
}

Explicación:

  • El fragmento de código anterior declaró 2 variables. Aquí la suposición es que int toma 2 bytes y long toma 4 bytes de memoria. La cantidad de memoria que toman las variables depende nuevamente del compilador.
  • Estas variables se almacenarán en la sección de pila. Para cada función en el programa, tomará una parte de la sección de la pila, se conoce como registro de activación (o) marco de la pila y el compilador lo eliminará cuando no esté en uso.
  • A continuación se muestra la imagen para ilustrar lo mismo:

Static memory allocation

A continuación se muestra el programa C para ilustrar la asignación de memoria estática:

C

// C program to implement
// static memory allocation
#include <stdio.h>
#include <stdlib.h>
  
// Driver code
int main()
{
    int size;
    printf("Enter limit of the text: \n");
    scanf("%d", &size);
    char str[size];
    printf("Enter some text: \n");
    scanf(" ");
    gets(str);
    printf("Inputted text is: %s\n", str);
    return 0;
}

Aporte:

Output#1

Producción:

Output#2

ventajas:

  • Uso sencillo.
  • La asignación y la desasignación las realiza el compilador.
  • Tiempo de ejecución eficiente.
  • Utiliza estructuras de datos de pila .

Desventajas:

  • Problema de pérdida de memoria.
  • Se deben conocer los requisitos de memoria exactos.
  • La memoria no se puede cambiar de tamaño una vez después de la inicialización.

Asignación de memoria dinámica

En la asignación de memoria dinámica, el programador realiza la inicialización y la asignación del tamaño. Se administra y sirve con punteros que apuntan al espacio de memoria recién asignado en un área que llamamos montón. La memoria del montón no está organizada y se trata como un recurso cuando necesita su uso si no lo libera. Cuando todo se hace durante el tiempo de ejecución o el tiempo de ejecución, se conoce como asignación de memoria dinámica.

Características clave:

  • Dinámico asignado en tiempo de ejecución
  • También podemos reasignar el tamaño de la memoria si es necesario.
  • La asignación dinámica se realiza en tiempo de ejecución.
  • Sin desperdicio de memoria

Hay algunas funciones disponibles en el encabezado stdlib.h que ayudarán a asignar memoria dinámicamente .

  • malloc() : La función más simple que asigna memoria en tiempo de ejecución se llama malloc(). Es necesario especificar la cantidad de bytes de memoria que se requieren asignar, ya que el argumento devuelve la dirección del primer byte de memoria que se asigna porque obtiene una dirección devuelta, un puntero es el único lugar para colocarlo.

Sintaxis:

int *p = (int*)malloc(No de valores*tamaño(int));

El argumento de malloc() anterior indica claramente que deben estar disponibles suficientes bytes para acomodar el número de valores de tipo int. Observe también la conversión (int*), que convierte la dirección devuelta por la función al puntero de tipo a int. La función malloc() devuelve un puntero con el valor NULL .

  • calloc() : La función calloc() ofrece un par de ventajas sobre malloc() . Asigna memoria como un número de elementos de un tamaño dado. Inicializa la memoria que se asigna para que todos los bytes sean cero. La función calloc() requiere dos valores de argumento: 
    • El número de elementos de datos para los que se requiere espacio.
    • Tamaño de cada elemento de datos.

Es muy similar a usar malloc() pero la gran ventaja es que sabe que el área de memoria se inicializará a cero.

Sintaxis: 

int *p = (int*)calloc(Número de elementos de datos, tamaño de(int));

  • realloc() : la función realloc() le permite reutilizar o ampliar la memoria que asignó previamente mediante malloc() o calloc(). Un puntero que contiene una dirección que fue previamente devuelta por una llamada a malloc(), calloc(). El tamaño en bytes de la nueva memoria que debe asignarse. Asigna la memoria especificada por el segundo argumento y transfiere el contenido de la memoria previamente asignada a la que hace referencia el puntero pasado como primer argumento a la memoria recién asignada.

Sintaxis:

int *np = (type cast) realloc (tipo de puntero anterior, nuevo número de elementos * sizeof(int));

  • . free() : cuando la memoria se asigna dinámicamente, siempre debe liberarse cuando ya no se necesite. La memoria asignada en el montón se liberará automáticamente cuando finalice el programa, pero siempre es mejor liberar explícitamente la memoria cuando termine, incluso si es justo antes de salir del programa. Se produce una fuga de memoria. La memoria se asigna dinámicamente y no se conserva la referencia a ella, por lo que no se puede liberar la memoria.

Sintaxis:

libre (puntero);

Por ejemplo:

C

// C program to illustrate the concept
// of memory allocation
#include <iostream>
using namespace std;
  
// Driver Code
void main()
{
    int* p; // 2 bytes
    P = (int*)malloc(5 * sizeof(int));
}

Ejemplos: 

  • En el fragmento de código anterior, se declara un puntero p. Suponga que el puntero p ocupará 2 bytes de memoria y nuevamente depende del compilador.
  • Este puntero se almacenará en la sección de la pila y apuntará a la dirección de array del primer índice que se asigna en el montón. La memoria del montón no se puede usar directamente, pero con la ayuda del puntero, se puede acceder a ella.

Free

  • Cuando el programa no está en uso, la memoria debe desasignarse. De lo contrario, provocará una pérdida de memoria.

Memory leak

  • Después de desasignar la memoria asignada en el montón. A continuación se muestra la imagen para ilustrar la memoria principal después de la desasignación.

Deallocating heap memory

A continuación se muestra el programa C para ilustrar la asignación de memoria dinámica:

C

// C program to illustrate the above
// concepts of memory allocation
#include <stdio.h>
#include <stdlib.h>
  
// Driver Code
int main()
{
    int size, resize;
    char* str = NULL;
    printf("Enter limit of the "
           "text: \n");
    scanf("%d", &size);
  
    str = (char*)malloc(size * sizeof(char));
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by allocating"
               "memory using malloc() is: "
               "%s\n",
               str);
    }
  
    // Free the memory
    free(str);
    str = (char*)calloc(50, sizeof(char));
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by allocating "
               "memory using calloc() is: "
               "%s\n",
               str);
    }
  
    printf("Enter the new size: \n");
    scanf("%d", &resize);
    str = (char*)realloc(str, resize * sizeof(char));
  
    printf("Memory is successfully "
           "reallocated by using "
           "realloc() \n");
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by reallocating"
               " memory using realloc()is: "
               "%s\n",
               str);
    }
  
    // Free the memory
    free(str);
    str = NULL;
  
    return 0;
}

Aporte:

Output#1

Producción:

Output#2

ventajas:

  • La asignación dinámica se realiza en tiempo de ejecución.
  • Podemos asignar (crear) almacenamiento adicional siempre que lo necesitemos.
  • La memoria se puede desasignar (liberar/eliminar) espacio dinámico cada vez que terminemos con ellos.
  • Por lo tanto, uno siempre puede tener exactamente la cantidad de espacio requerida, ni más ni menos.
  • El tamaño de la memoria se puede reasignar si es necesario.

Desventajas:

  • Como la memoria se asigna durante el tiempo de ejecución, requiere más tiempo.
  • El usuario debe liberar la memoria cuando haya terminado. Esto es importante ya que es más probable que se convierta en errores que son difíciles de encontrar.

Publicación traducida automáticamente

Artículo escrito por annamsaimanohar y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *