Al igual que con todo lo que parece más aterrador al principio que después, ¡la mejor manera de superar el miedo inicial es sumergirse en la incomodidad de lo desconocido ! A veces es lo que más aprendemos, después de todo.
Lamentablemente, hay limitaciones. Mientras todavía está aprendiendo a usar una función, no debe asumir el papel de un maestro, por ejemplo. A menudo leo las respuestas de aquellos que aparentemente no saben cómo usarlos realloc
(es decir, ¡ la respuesta actualmente aceptada! ) Y les digo a los demás cómo usarlos incorrectamente, ocasionalmente con el pretexto de que han omitido el manejo de errores , a pesar de que este es un error común. que necesita mención Aquí hay una respuesta que explica cómo usar realloc
correctamente . Tenga en cuenta que la respuesta es almacenar el valor de retorno en una variable diferente para realizar la comprobación de errores.
Cada vez que llama a una función, y cada vez que usa una matriz, está usando un puntero. Las conversiones están ocurriendo implícitamente, lo que si algo debería ser aún más aterrador, ya que son las cosas que no vemos que a menudo causan la mayoría de los problemas. Por ejemplo, pérdidas de memoria ...
Los operadores de matriz son operadores de puntero. array[x]
es realmente un atajo para *(array + x)
, que se puede dividir en: *
y (array + x)
. Es muy probable que eso *
sea lo que te confunda. Podemos eliminar aún más la suma del problema suponiendo x
que se convierte 0
, por lo tanto, array[0]
en *array
que la suma 0
no cambiará el valor ...
... y así podemos ver que *array
es equivalente a array[0]
. Puede usar uno donde quiera usar el otro, y viceversa. Los operadores de matriz son operadores de puntero.
malloc
, realloc
y los amigos no inventan el concepto de puntero que has estado usando todo el tiempo; simplemente usan esto para implementar alguna otra característica, que es una forma diferente de duración de almacenamiento, más adecuada cuando desea cambios drásticos y dinámicos en el tamaño .
Es una pena que la respuesta actualmente aceptada también vaya en contra de otros consejos muy bien fundados sobre StackOverflow y, al mismo tiempo, pierda la oportunidad de introducir una característica poco conocida que brilla exactamente para este caso de uso: matriz flexible miembros! Esa es en realidad una respuesta bastante rota ... :(
Cuando defina su struct
, declare su matriz al final de la estructura, sin ningún límite superior. Por ejemplo:
struct int_list {
size_t size;
int value[];
};
¡Esto le permitirá unir su matriz int
en la misma asignación que la suya count
, y hacer que se unan así puede ser muy útil !
sizeof (struct int_list)
actuará como si value
tuviera un tamaño de 0, por lo que le dirá el tamaño de la estructura con una lista vacía . Aún necesita agregar al tamaño pasado realloc
para especificar el tamaño de su lista.
Otro consejo útil es recordar que realloc(NULL, x)
es equivalente a malloc(x)
, y podemos usar esto para simplificar nuestro código. Por ejemplo:
int push_back(struct int_list **fubar, int value) {
size_t x = *fubar ? fubar[0]->size : 0
, y = x + 1;
if ((x & y) == 0) {
void *temp = realloc(*fubar, sizeof **fubar
+ (x + y) * sizeof fubar[0]->value[0]);
if (!temp) { return 1; }
*fubar = temp; // or, if you like, `fubar[0] = temp;`
}
fubar[0]->value[x] = value;
fubar[0]->size = y;
return 0;
}
struct int_list *array = NULL;
La razón que elegí para usar struct int_list **
como primer argumento puede no parecer obvia de inmediato, pero si piensas en el segundo argumento, cualquier cambio realizado value
desde adentro push_back
no sería visible para la función desde la que estamos llamando, ¿verdad? Lo mismo ocurre con el primer argumento, y debemos ser capaces de modificar nuestro array
, no solo aquí, sino posiblemente también en cualquier otra función que lo pasamos a ...
array
comienza apuntando a la nada; Es una lista vacía. Inicializarlo es lo mismo que agregarle. Por ejemplo:
struct int_list *array = NULL;
if (!push_back(&array, 42)) {
// success!
}
PD: ¡ Recuerdafree(array);
cuando hayas terminado con eso!