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).
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
oclass
” )? 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úntypeid(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
struct
s 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
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
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.
Debe asignar memoria dinámicamente si no sabe cuánto almacenamiento necesitará. Examinar
malloc()
yfree()
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()
yrealloc()
– 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