Array dinámico vs estático en c [closed]

12 minutos de lectura

El siguiente código crea una matriz con la función malloc. Pero sé que esto se puede hacer mucho más simple con solo una matriz int[size]. Creo que esto es una matriz estática. Pero con la función malloc, ¿es una matriz dinámica? Encontré este código en la red… Qué está sucediendo realmente y cuál es la diferencia entre una matriz estática y una matriz dinámica (y la memoria estática entre la memoria del montón). ¿Se puede cambiar el tamaño de la matriz dinámica durante el tiempo de ejecución? o… lo que no sé exactamente… Si alguien pudiera explicarlo, se lo agradecería 🙂

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    int size;
    int i;
    printf("Choose size of array: ");
    scanf("%d",&size);

    /*---MALLOC/FREE---*/
    int *m_array = (int *)malloc((size+1)*sizeof(int));
    memset(m_array,'\0',size+1);

    for(i=0; i<size ; i++)
    { 
        m_array[i]=i;
        printf("%d ",m_array[i]);
    }
    printf("\n");
    free(m_array);

    return 0;
}

  • int *m_array es un Pointer no un Array.

    – Michi

    16 de febrero de 2016 a las 20:43

  • int array[size] es un matriz de longitud variable. Además, te puede interesar la realloc función.

    – usuario3386109

    16 de febrero de 2016 a las 20:43

  • The following code creates an array with the malloc function No, no es. Con malloc usted solicita una cantidad de memoria de su OS y si lo consigues pones tu pointer a puntos allí.

    – Michi

    16 de febrero de 2016 a las 20:44


  • @Michi the C Standard dice que malloc crea una matriz

    –MM

    16 de febrero de 2016 a las 21:17

  • @Michi iment usando el malloc…

    – caché

    17/02/2016 a las 14:35

Hay varios tipos de arreglos, dependiendo de cómo y dónde se declaren.

Matrices de longitud fija

Los arreglos de longitud fija deben tener su tamaño determinado en tiempo de compilación. No puede cambiar el tamaño de una matriz de longitud fija después de haberla definido.

Los arreglos de longitud fija se declaran de una de las siguientes maneras:

T a[N];
T a[N] = { /* initializer list */ };
char_type a[N] = "string literal";
T a[]  = { /* initializer list */ };
char_type a[]  = "string literal";

En los tres primeros casos, N debe ser un expresión constante cuyo valor debe conocerse en tiempo de compilación. En los primeros tres casos, el tamaño de la matriz se toma de N; en los dos últimos casos, se toma del número de elementos en la lista de inicializadores o del tamaño de la cadena literal.

El contenido inicial de un arreglo de longitud fija depende de su duración del almacenamiento y si se ha suministrado un inicializador.

Si la matriz tiene static duración del almacenamiento (lo que significa que se declaró en el ámbito del archivo fuera de cualquier cuerpo de función, o se declaró con el static palabra clave) y no está presente ningún inicializador, entonces todos los elementos de la matriz se inicializan para 0 (para escalares) o NULL (para punteros). Si T es un tipo de agregado como un struct o un tipo de matriz, entonces cada miembro del agregado se inicializa con un 0 o NULL. union los tipos se ponen a cero de manera similar.

Si la matriz tiene auto duración del almacenamiento (lo que significa que se declaró dentro de una función o bloque sin la static palabra clave) y no hay inicializador presente, entonces el contenido de la matriz es indeterminado – Básicamente, basura.

Si la matriz se declara con una lista de inicializadores (independientemente de la duración del almacenamiento), los valores iniciales de los elementos de la matriz corresponden al inicializador. Si hay menos elementos en el inicializador que en la matriz (por ejemplo, N es 10 pero solo inicializa los primeros 5 elementos), luego se inicializan los elementos restantes como si la matriz tenia static duración del almacenamiento. OIA, dada la declaración

int a[10] = {0, 1, 2};

entonces los contenidos iniciales de la matriz son {0, 1, 2, 0, 0, 0, 0, 0, 0, 0}.

Las matrices de longitud fija que contienen valores de cadena se pueden inicializar mediante un literal de cadena. C permite cadenas de caracteres “anchas”, por lo que char_type podría ser cualquiera char o wchar_t. Las reglas son las mismas para las listas de inicializadores regulares, excepto que N (si se especifica) debe ser al menos 1 más que la longitud de la cadena para tener en cuenta el terminador de cadena.

Esto significa que

char a[10] = "test"; 

se inicializará como {'t', 'e', 's', 't', 0, 0, 0, 0, 0, 0} y

char a[] = "test";

se inicializará como {'t', 'e', 's', 't', 0}.

arreglos con static la duración del almacenamiento se almacenan de manera que estén disponibles tan pronto como se carga el programa y no se liberan hasta que el programa finaliza. Esto generalmente significa que están almacenados en un segmento de memoria como .data o .bss (o el equivalente para cualquier formato ejecutable que use su sistema).

arreglos con auto la duración del almacenamiento se almacena de tal manera que se asignan al ingreso del bloque o de la función y se liberan al salir del bloque o de la función (en la práctica, probablemente se asignarán al ingresar a la función, independientemente de si están limitados a un alcance más pequeño dentro de la función) – esto normalmente se traduce en la pila, aunque no tener para.

Matrices de longitud variable

Se agregaron matrices de longitud variable en C99: se comportan principalmente como matrices de longitud fija, excepto que su tamaño se establece en tiempo de ejecución; N no tiene que ser una expresión constante en tiempo de compilación:

int n;
printf( "gimme the array size: ");
scanf( "%d", &n );
T a[n]; // for any type T

Al contrario de lo que implica su nombre, no puede cambiar el tamaño de una matriz de longitud variable después de haberla definido. “Longitud variable” simplemente significa que el tamaño no se fija en el momento de la compilación y puede cambiar de una definición a otra.

Dado que su tamaño no se establece hasta el tiempo de ejecución, es posible que las matrices de longitud variable no se declaren en el ámbito del archivo o con el static palabra clave, ni se pueden declarar con una lista de inicializadores. Exactamente cómo se gestiona el espacio para los VLA depende de la implementación; puede ser (y generalmente es) tomado de la pila, pero AFAIK puede ser tomado de otro lugar.

Matrices dinámicas

Los arreglos dinámicos no son realmente “arreglos” como tales, al menos en términos de los tipos de datos de los objetos que usamos para administrarlos. Los arreglos dinámicos se asignan en tiempo de ejecución usando uno de malloc, calloco reallocy ese almacenamiento se mantiene hasta que se libera con una llamada a free.

T *p = malloc( sizeof *p * N ); // where N may be either a compile-time or
                                // run-time expression
...
free( p );

Se puede cambiar el tamaño de un arreglo dinámico usando el realloc función de biblioteca, así:

/**
 * If realloc fails, it will return NULL and leave the original array in 
 * place.  We assign the result to a temporary variable so we don't risk
 * losing our only reference to that memory. 
 */
T *tmp = realloc( p, sizeof *p * new_size );  
if ( tmp )                                    
  p = tmp;                                    

Mientras que la memoria para los elementos de la matriz en sí se toma del montón (o de cualquier grupo de memoria dinámica), la memoria para el variable puntero p se asignará desde un .bss o .data segmento o de la pila, según pla duración del almacenamiento (static o auto).

Memoria asignada con malloc o realloc no está inicializado; el contenido de esa memoria será indeterminado. Memoria asignada con calloc se inicializará con ceros.

Matrices frente a punteros

En algún momento, alguien te dirá que “una matriz es solo un puntero”. Esa persona no es correcta.

Cuando declara una matriz (ya sea de longitud fija o variable), se reserva suficiente espacio de almacenamiento para los elementos de esa matriz y nada más; no se reserva almacenamiento para ningún metadato, como la longitud de la matriz o un puntero al primer elemento. Dada la declaración

T a[N];

entonces el almacenamiento se verá así:

    +---+
 a: |   | a[0]
    +---+
    |   | a[1]
    +---+
    |   | a[2]
    +---+
     ...
    +---+ 
    |   | a[N-1]
    +---+

no hay objeto a aparte de los propios elementos de la matriz (o, más correctamente, el objeto a es los elementos de la matriz), y la expresión a no puede ser el objetivo de una asignación.

Pero…

La expresion a[i] es definido como *(a + i); es decir, dado un valor de puntero acompensar i elementos (no bytes!) de esa dirección y desreferenciar el resultado. Pero si a no es un puntero, ¿cómo puede funcionar eso?

Así – excepto cuando es el operando del sizeof o unario & operadores, o es un literal de cadena utilizado como un inicializador de matriz en una declaración, un expresión de tipo “N-arreglo de elementos de T” sera convertido (“decay”) a una expresión de tipo “puntero a T“, y el valor de la expresión será la dirección del primer elemento de la matriz.

Esto tiene varias implicaciones:

  • Las expresiones a, &ay &a[0] todos darán lo mismo valor (la dirección del primer elemento de la matriz), pero el tipos de las expresiones serán diferentes (T *, T (*)[N]y T *respectivamente);
  • El operador subíndice [] funciona igual de bien tanto con expresiones de matriz como con expresiones de puntero (de hecho, es definido para trabajar en expresiones de puntero);
  • Cuando pasa una expresión de matriz a una función, lo que está Realmente pasar es un valor de puntero, no la matriz completa;

Para arreglos dinámicos, la situación es diferente. Dada la línea

T *p = malloc( sizeof *p * N );

entonces su almacenamiento se verá así:

   +---+
p: |   | ---+
   +---+    |
    ...     |
     +------+
     |
     V
   +---+
   |   | p[0]
   +---+
   |   | p[1]
   +---+
    ...   
   +---+
   |   | p[N-1]
   +---+

En este caso, p es un objeto separado de la matriz. Por lo tanto, &p no lo haré darle el mismo valor que p y &p[0]y su tipo será T ** Opuesto a T (*)[N]. También, desde p es solo una variable de puntero, puede asignarle un nuevo valor (aunque si lo hace sin freeSi escribe primero la memoria a la que apunta, creará una fuga de memoria).

Similar, sizeof p no lo haré comportarse como sizeof a; simplemente devolverá el tamaño de la variable del puntero, no el tamaño de la memoria asignada a la que apunta el puntero para.

  • ¡Respuesta asombrosa! Pero un detalle sobre la declaración “excepto que N (si se especifica) debe ser al menos 1 más que la longitud de la cadena para tener en cuenta el terminador de cadena”. Eso no es técnicamente correcto. Si se especifica N, debe ser mayor que o igual a la longitud de la cuerda. Si N es igual a la longitud de la cadena, el resultado es una matriz de caracteres sin un terminador NUL. Por ejemplo, a[4] = "test"; está permitido por la especificación C, consulte el párrafo 6.7.9/14

    – usuario3386109

    17 de febrero de 2016 a las 1:52

A las matrices estáticas se les asigna memoria en tiempo de compilación y la memoria se asigna en la pila. Mientras que a las matrices dinámicas se les asigna memoria en tiempo de ejecución y la memoria se asigna desde el montón.

Esta es una matriz de enteros estática, es decir, memoria fija asignada antes del tiempo de ejecución

int arr[] = { 1, 3, 4 };

Esta es una matriz dinámica de enteros, es decir, memoria asignada en tiempo de ejecución

int* arr = new int[3]; 

  • Int *arr no es una matriz, es un puntero

    – Michi

    16/02/2016 a las 20:57

  • Sé. La memoria dinámica se asigna en forma de puntero. Tiene nombre de arr, no es un arreglo

    – Muhammad Noman

    16/02/2016 a las 21:00

  • La memoria no se asignó en Pointer. El puntero apunta allí.

    – Michi

    16 de febrero de 2016 a las 21:02

  • Yo digo lo mismo compañero. La memoria dinámica se asigna en forma de puntero y los puntos de puntero en esa ubicación donde se encuentran los datos, ya sea en forma distribuida o secuencial.

    – Muhammad Noman

    16/02/2016 a las 21:05

  • las matrices estáticas no usan la pila… es decir, las matrices automáticas.

    –MM

    16 de febrero de 2016 a las 21:18

Array dinamico vs estatico en c closed
Pouria

Está utilizando matrices dinámicas de tamaño + 1 y agregando elementos (de 0 a tamaño) y liberando el espacio al final antes de devolver 0. Entonces, en su caso, int * m_array es un puntero a un int. Lo que estás haciendo en la línea 13 es una declaración:

(int *m_array) =...

y asignación:

...(int *)malloc((size+1)*sizeof(int));

Dado que es una matriz dinámica, está asignando en el montón y se mantiene hasta que se libera (es por eso que tiene libre (m_array) al final). Si fuera estático, podría haber inicializado la matriz de esta manera:

int m_array[size];

Y se habría asignado en el área de almacenamiento estático (a menos que sea automático) y se desasignaría tan pronto como finalice el programa. No puede cambiar el tamaño de una matriz estática en C, por lo que debe usar una matriz dinámica. Tu usas reasignar cuando desee cambiar el tamaño de una matriz dinámica.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad