¿Cómo crear una matriz sin declarar el tamaño en C?

6 minutos de lectura

Estoy tratando de crear una matriz int y float sin un tamaño (puede ser 0 o puede incrementarse mientras el usuario usa el programa).

Estaba tratando de hacer lo siguiente:

int bills[];

float totalAmount[];

No puedo asignar un tamaño máximo porque estoy imprimiendo cada matriz con un bucle for (si asigno un tamaño de 99, imprimiré 99 líneas y no quiero eso).

  • Debe asignar memoria dinámicamente si no sabe cuánto almacenamiento necesitará. Examinar malloc() y free() documentación.

    – Tanveer Badar

    29 de abril de 2018 a las 5:45

  • Simplemente no puede hacer eso en C, sin embargo, hay muchas soluciones alternativas, pero no creo que podamos ayudarlo más que un buen libro de C. Como una solución simple para principiantes, eche un vistazo a malloc() y realloc()

    – Stargateur

    29 de abril de 2018 a las 5:45

  • Si se conoce el tamaño máximo (y es pequeño), podría usar int bills[99]; y luego realizar un seguimiento de la cantidad de elementos usados ​​por separado. Tú voluntad tiene que llevar la cuenta del número de facturas de todos modos.

    – Bo Person

    29 de abril de 2018 a las 11:53


avatar de usuario de chqrlie
chqrlie

C no admite arreglos con un número dinámico de elementos. El número de elementos de una matriz debe determinarse en el momento de la compilación o dado que C99 puede evaluarse en tiempo de ejecución en el momento de la creación. Una vez que se crea la matriz, su tamaño es fijo y no se puede cambiar. Hay algunos casos en los que el tamaño no se especifica explícitamente entre el []ya sea en definiciones de matriz o en declaraciones de matriz.

Puede definir una matriz sin un tamaño explícito para la dimensión más a la izquierda si proporciona un inicializador. El compilador deducirá el tamaño del inicializador:

int a[] = { 1, 2, 3 };              // equivalent to int a[3] = { 1, 2, 3 };
int m[][2] = {{ 1, 2 }, { 3, 4 }};  // equivalent to int m[2][2] = {{ 1, 2 }, { 3, 4 }};
char s[] = "Hello world\n";         // equivalent to char s[13] = "Hello world\n";

Observe cómo el compilador agrega el terminador nulo implícito en el caso de la cadena.

Puede declarar una matriz sin un especificador de tamaño para la dimensión más a la izquierda en múltiples casos:

  • como una variable global con extern almacenamiento de clase (la matriz se define en otro lugar),
  • como parámetro de función: int main(int argc, char *argv[]). En este caso, el tamaño especificado para la dimensión más a la izquierda se ignora de todos modos.
  • como el último miembro de un struct con más de un miembro nombrado. Esta es una extensión C99 llamada matriz flexible.

El compilador no tiene información sobre el tamaño real de estas matrices. El programador usará alguna otra información para determinar la longitud, ya sea de una variable separada o del contenido de la matriz.

En el caso de un argumento de función, la matriz se pasa como un puntero e incluso si se especifica el número de elementos, sizeof(argv) se evalúa al tamaño de un puntero.

  • ¿Sabe si los casos en los que puede declarar una matriz sin un especificador de tamaño para la dimensión más a la izquierda son los mismos en C++ (obviamente “struct“probablemente tendría que ser cambiado a”struct o class” )? Probé el caso del parámetro de función; parece que la sintaxis es válida pero la variable se convierte en un puntero (según typeid(the_variable).name).

    – Hola Adios

    18 oct 2020 a las 20:11

  • Además, se podría mencionar que los arreglos flexibles C99 solo están permitidos en structs con al menos dos miembros designados.

    – Hola Adios

    18 oct 2020 a las 20:34

  • @HelloGoodbye: buen punto sobre más de un miembro nombrado… Respuesta modificada.

    – chqrlie

    19 de enero de 2021 a las 1:49


  • @HelloGoodbye: las matrices siempre se pasan como un puntero a su primer elemento.

    – chqrlie

    19 de enero de 2021 a las 1:50

  • “las matrices siempre se pasan como un puntero a su primer elemento”, en C pero no en C++ en ese caso, ¿verdad? Creo que una matriz con un especificador de tamaño en C++ es su propio tipo de datos. ¿O quiere decir que el tipo de datos se cambia a un puntero cuando lo usa como parámetro de función?

    – Hola Adios

    20 de enero de 2021 a las 2:07

Avatar de usuario de Edwin Buck
edwin dólar

No declara una matriz sin un tamaño, sino que declara un puntero a una cantidad de registros.

entonces, si quisieras hacer

int bills[];

La forma correcta de hacer esto en C es

int* bills;

Y tendrá que asignar el tamaño en algún momento e inicializar la matriz.

bills = (int*)malloc(sizeof(int)*items);

Lo mismo ocurre con las matrices de otros tipos de datos. Si no conoce el tamaño de la matriz hasta el tiempo de ejecución, debe usar punteros a la memoria que se asignan al tamaño correcto en el tiempo de ejecución.

  • ¿Lanzo la vuelta de malloc?

    – Stargateur

    29 de abril de 2018 a las 6:16

  • @EdwinBuck No entendí bien tu comentario, no soy un hablante nativo de inglés. Lo siento si sientes que te ataque personalmente. Creo que cualquier argumento sobre “el compilador antiguo podría” no tiene sentido, estamos en 2018. Creo que subestimaste el problema si lanzas un tipo de puntero incorrecto. Creo que cualquier código C moderno debería usar bills = malloc(sizeof *bills * items); y ese viejo programador debería dejar su viejo mal hábito. El C moderno quiere vivir sin el C antiguo. Es la experiencia de 30 años de programador de C la que concluye que era mejor escribirlo así.

    – Stargateur

    30 de abril de 2018 a las 13:06

Avatar de usuario de J...S
J…S

Podrías usar una combinación de malloc() (o calloc()), realloc() y free() lograr esto.

La memoria se puede asignar como bloques de un tamaño fijo en lugar de reasignar la memoria para almacenar cada número.

Definamos una macro (o una const Si te gusta) BLOCK_SIZE.

#define BLOCK_SIZE 10

Primero declare un puntero del tipo apropiado y asigne el primer bloque.

Tenga en cuenta que malloc() así como realloc() devolver NULL si ocurriera algún error debido a razones como memoria insuficiente.

int *ptr=malloc(sizeof(int)*BLOCK_SIZE);    
if(ptr==NULL)
{
    perror("some error");
    return 1;
}

Ahora declare una variable para almacenar el índice máximo posible según la memoria asignada actualmente (para evitar el acceso ilegal a la memoria).

int max_index = BLOCK_SIZE-1;

Ahora usa un bucle.

for(int i=0; ; ++i)
{
    if(i > max_index)
    {
        ptr=realloc(ptr, (max_index+1 + BLOCK_SIZE)*sizeof(int));
        if(ptr == NULL)
        {
            perror("insufficient memory!");
            break;
        }
        printf("\nRealloced!");
        max_index += BLOCK_SIZE;
    }
    scanf("%d", &ptr[i]);
    printf("\n%d: %d", i, ptr[i]);
}

En cada iteración comprobamos si i es mayor que max_index. Si es así, se asigna otro bloque usando realloc() antes de leer el valor.

No olvide desasignar la memoria una vez que haya terminado de usarla.

free(ptr);

Además, como se discutió en esta publicación, malloc() es efectivamente lo mismo que realloc() con el primer argumento de este último NULL.

Y en el código que publicaste, no es necesario emitir explícitamente el valor de retorno de calloc() como lo que se devuelve es un void puntero que se convertiría implícitamente al tipo de puntero de destino.

Ver esto y esto.

Creo que puede darle un tamaño máximo, si solo desea mostrar los primeros elementos, puede colocar un bucle for hasta ese elemento solamente, lo mismo ocurre con la entrada si desea inicializar los primeros 30 elementos, coloque un bucle for hasta 30.

¿Ha sido útil esta solución?