¿Cómo puedo crear una matriz de estructuras de tamaño dynamic?

Sé cómo crear una serie de estructuras pero con un tamaño predefinido. Sin embargo, ¿hay alguna manera de crear una matriz dinámica de estructuras para que la matriz pueda crecer?

Por ejemplo:

typedef struct { char *str; } words; main() { words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in. } 

es posible?


Investigué esto: words* array = (words*)malloc(sizeof(words) * 100);

Quiero deshacerme de los 100 y almacenar los datos a medida que entran. Por lo tanto, si entran 76 campos de datos, quiero almacenar 76 y no 100. Supongo que no sé la cantidad de datos que llegarán en mi progtwig. En la estructura que he definido anteriormente, pude crear el primer “índice” como:

  words* array = (words*)malloc(sizeof(words)); 

Sin embargo, quiero agregar dinámicamente elementos a la matriz después. Espero haber descrito el área del problema con suficiente claridad. El mayor desafío es agregar dinámicamente un segundo campo, al menos ese es el desafío por el momento.


Sin embargo, he progresado un poco:

  typedef struct { char *str; } words; // Allocate first string. words x = (words) malloc(sizeof(words)); x[0].str = "john"; // Allocate second string. x=(words*) realloc(x, sizeof(words)); x[1].FirstName = "bob"; // printf second string. printf("%s", x[1].str); --> This is working, it's printing out bob. free(x); // Free up memory. printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong? 

Hice algunas comprobaciones de error y esto es lo que encontré. Si después de liberar memoria para x agrego lo siguiente:

  x=NULL; 

entonces, si bash imprimir x obtengo un error, que es lo que quiero. Entonces, ¿la función gratuita no funciona, al menos en mi comstackdor? Estoy usando DevC?


Gracias, ahora entiendo por:

FirstName es un puntero a una matriz de char que no está siendo asignada por el malloc, solo se asigna el puntero y después de llamar gratis, no borra la memoria, solo la marca como disponible en el montón para terminar escrito más tarde. – Matt Smith

Actualizar

Estoy tratando de modularizar y poner la creación de mi matriz de estructuras en una función, pero nada parece funcionar. Estoy intentando algo muy simple y no sé qué más hacer. Está en la misma línea que antes, solo otra función, loaddata que está cargando los datos y fuera del método necesito hacer algo de impresión. ¿Cómo puedo hacer que funcione? Mi código es el siguiente:

  # include  # include  # include  # include  typedef struct { char *str1; char *str2; } words; void LoadData(words *, int *); main() { words *x; int num; LoadData(&x, &num); printf("%s %s", x[0].str1, x[0].str2); printf("%s %s", x[1].str1, x[1].str2); getch(); }// void LoadData(words *x, int * num) { x = (words*) malloc(sizeof(words)); x[0].str1 = "johnnie\0"; x[0].str2 = "krapson\0"; x = (words*) realloc(x, sizeof(words)*2); x[1].str1 = "bob\0"; x[1].str2 = "marley\0"; *num=*num+1; }// 

Este código de prueba simple se está bloqueando y no tengo idea de por qué. ¿Dónde está el error?

Has etiquetado esto como C ++ y como C.

Si usa C ++ las cosas son mucho más fáciles. La biblioteca de plantillas estándar tiene una plantilla llamada vector que le permite construir dinámicamente una lista de objetos.

 #include  #include  typedef std::vector words; int main(int argc, char** argv) { words myWords; myWords.push_back("Hello"); myWords.push_back("World"); words::iterator iter; for (iter = myWords.begin(); iter != myWords.end(); ++iter) { printf("%s ", *iter); } return 0; } 

Si usa C las cosas son mucho más difíciles, sí malloc, realloc y free son las herramientas que lo ayudarán. Es posible que desee considerar el uso de una estructura de datos de lista vinculada en su lugar. En general, son más fáciles de cultivar pero no facilitan el acceso aleatorio tan fácilmente.

 #include  #include  typedef struct s_words { char* str; struct s_words* next; } words; words* create_words(char* word) { words* newWords = malloc(sizeof(words)); if (NULL != newWords){ newWords->str = word; newWords->next = NULL; } return newWords; } void delete_words(words* oldWords) { if (NULL != oldWords->next) { delete_words(oldWords->next); } free(oldWords); } words* add_word(words* wordList, char* word) { words* newWords = create_words(word); if (NULL != newWords) { newWords->next = wordList; } return newWords; } int main(int argc, char** argv) { words* myWords = create_words("Hello"); myWords = add_word(myWords, "World"); words* iter; for (iter = myWords; NULL != iter; iter = iter->next) { printf("%s ", iter->str); } delete_words(myWords); return 0; } 

Yikes, perdón por la respuesta más larga del mundo. Entonces WRT al “no quiero usar un comentario de la lista vinculada”:

 #include  #include  typedef struct { char** words; size_t nWords; size_t size; size_t block_size; } word_list; word_list* create_word_list(size_t block_size) { word_list* pWordList = malloc(sizeof(word_list)); if (NULL != pWordList) { pWordList->nWords = 0; pWordList->size = block_size; pWordList->block_size = block_size; pWordList->words = malloc(sizeof(char*)*block_size); if (NULL == pWordList->words) { free(pWordList); return NULL; } } return pWordList; } void delete_word_list(word_list* pWordList) { free(pWordList->words); free(pWordList); } int add_word_to_word_list(word_list* pWordList, char* word) { size_t nWords = pWordList->nWords; if (nWords >= pWordList->size) { size_t newSize = pWordList->size + pWordList->block_size; void* newWords = realloc(pWordList->words, sizeof(char*)*newSize); if (NULL == newWords) { return 0; } else { pWordList->size = newSize; pWordList->words = (char**)newWords; } } pWordList->words[nWords] = word; ++pWordList->nWords; return 1; } char** word_list_start(word_list* pWordList) { return pWordList->words; } char** word_list_end(word_list* pWordList) { return &pWordList->words[pWordList->nWords]; } int main(int argc, char** argv) { word_list* myWords = create_word_list(2); add_word_to_word_list(myWords, "Hello"); add_word_to_word_list(myWords, "World"); add_word_to_word_list(myWords, "Goodbye"); char** iter; for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) { printf("%s ", *iter); } delete_word_list(myWords); return 0; } 

Si desea asignar dinámicamente matrices, puede usar malloc de stdlib.h .

Si desea asignar una matriz de 100 elementos utilizando sus words struct, intente lo siguiente:

 words* array = (words*)malloc(sizeof(words) * 100); 

El tamaño de la memoria que desea asignar se pasa a malloc y luego devolverá un puntero de tipo void ( void* ). En la mayoría de los casos, es probable que desee convertirlo al tipo de puntero que desee, que en este caso son las words* .

La palabra clave sizeof se usa aquí para conocer el tamaño de las words struct, luego ese tamaño se multiplica por la cantidad de elementos que desea asignar.

Una vez que haya terminado, asegúrese de usar free() para liberar la memoria Heap que utilizó para evitar pérdidas de memoria :

 free(array); 

Si desea cambiar el tamaño de la matriz asignada, puede intentar usar realloc como otros lo han mencionado, pero tenga en cuenta que si realiza muchos realloc s puede terminar fragmentando la memoria . Si desea cambiar el tamaño dinámicamente de la matriz para mantener una huella de memoria baja para su progtwig, puede ser mejor no hacer demasiados realloc .

Esto parece un ejercicio académico que, lamentablemente, lo hace más difícil ya que no puede usar C ++. Básicamente, debe administrar algunos de los gastos generales para la asignación y realizar un seguimiento de la cantidad de memoria asignada si necesita cambiar el tamaño más adelante. Aquí es donde brilla la biblioteca estándar de C ++.

Para su ejemplo, el siguiente código asigna la memoria y luego la cambia de tamaño:

 // initial size int count = 100; words *testWords = (words*) malloc(count * sizeof(words)); // resize the array count = 76; testWords = (words*) realloc(testWords, count* sizeof(words)); 

Tenga en cuenta que, en su ejemplo, solo está asignando un puntero a un carácter y aún necesita asignar la cadena en sí y, lo que es más importante, liberarla al final. Por lo tanto, este código asigna 100 punteros a char y luego lo cambia a 76, pero no asigna las cadenas en sí.

Sospecho que realmente desea asignar la cantidad de caracteres en una cadena que es muy similar a la anterior, pero cambie la palabra por char.

EDITAR: También tenga en cuenta que tiene mucho sentido crear funciones para realizar tareas comunes y hacer cumplir la coherencia para que no se copie el código en todas partes. Por ejemplo, puede tener a) asignar la estructura, b) asignar valores a la estructura yc) liberar la estructura. Entonces podrías tener:

 // Allocate a words struct words* CreateWords(int size); // Assign a value void AssignWord(word* dest, char* str); // Clear a words structs (and possibly internal storage) void FreeWords(words* w); 

EDITAR: en cuanto al redimensionamiento de las estructuras, es idéntico al redimensionamiento de la matriz de caracteres. Sin embargo, la diferencia es que si hace que la matriz de estructuras sea más grande, probablemente debería inicializar los nuevos elementos de la matriz a NULL. Del mismo modo, si reduce la matriz de estructuras, debe realizar una limpieza antes de eliminar los elementos, es decir, los artículos gratuitos que se han asignado (y solo los elementos asignados) antes de cambiar el tamaño de la matriz de estructuras. Esta es la razón principal por la que sugerí crear funciones auxiliares para ayudar a administrar esto.

 // Resize words (must know original and new size if shrinking // if you need to free internal storage first) void ResizeWords(words* w, size_t oldsize, size_t newsize); 

En C ++, usa un vector . Es como una matriz pero puede agregar y eliminar elementos fácilmente y se ocupará de asignar y desasignar la memoria por usted.

Sé que el título de la pregunta dice C, pero tagste tu pregunta con C y C ++ …

Otra opción para usted es una lista vinculada . Tendrá que analizar cómo utilizará su progtwig la estructura de datos; si no necesita acceso aleatorio, podría ser más rápido que reasignarlo.

Así es como lo haría en C ++

 size_t size = 500; char* dynamicAllocatedString = new char[ size ]; 

Use el mismo principio para cualquier clase struct o c ++.

Su código en la última actualización no debería comstackrse, mucho menos ejecutarse. Estás pasando & x a LoadData. & x tiene el tipo de ** palabras, pero LoadData espera palabras *. Por supuesto, se bloquea cuando llamas a realloc en un puntero que apunta a la stack.

La forma de solucionarlo es cambiar LoadData para que acepte palabras **. Thi sway, en realidad puedes modificar el puntero en main (). Por ejemplo, la llamada realloc se vería como

 *x = (words*) realloc(*x, sizeof(words)*2); 

Es el mismo principio que en “num” ser int * en lugar de int.

Además de esto, necesitas averiguar cómo se almacenan las cadenas de palabras. Se permite asignar una cadena const a char * (como en str2 = “marley \ 0”), pero rara vez es la solución correcta, incluso en C.

Otro punto: no necesita tener “marley \ 0” a menos que realmente necesite dos ceros al final de la cadena. El comstackdor agrega 0 al final de cada literal de cadena.

Para el código de prueba: si desea modificar un puntero en una función, debe pasar un “puntero a puntero” a la función. El código corregido es el siguiente:

 #include  #include  #include  typedef struct { char *str1; char *str2; } words; void LoadData(words**, int*); main() { words **x; int num; LoadData(x, &num); printf("%s %s\n", (*x[0]).str1, (*x[0]).str2); printf("%s %s\n", (*x[1]).str1, (*x[1]).str2); } void LoadData(words **x, int *num) { *x = (words*) malloc(sizeof(words)); (*x[0]).str1 = "johnnie\0"; (*x[0]).str2 = "krapson\0"; *x = (words*) realloc(*x, sizeof(words) * 2); (*x[1]).str1 = "bob\0"; (*x[1]).str2 = "marley\0"; *num = *num + 1; } 

Si desea hacer crecer la matriz dinámicamente, debe usar malloc () para asignar dinámicamente una cantidad fija de memoria, y luego usar realloc () cada vez que se agote. Una técnica común es usar una función de crecimiento exponencial de manera que asigne una pequeña cantidad fija y luego haga crecer la matriz duplicando la cantidad asignada.

Un código de ejemplo sería:

 size = 64; i = 0; x = malloc(sizeof(words)*size); /* enough space for 64 words */ while (read_words()) { if (++i > size) { size *= 2; x = realloc(sizeof(words) * size); } } /* done with x */ free(x); 

Cada codificador necesita simplificar su código para que sea fácil de entender … incluso para principiantes.

Entonces, una serie de estructuras que usan dinámicamente es fácil, si entiendes los conceptos.

 // Dynamically sized array of structures #include  #include  struct book { char name[20]; int p; }; //Declaring book structure int main () { int n, i; struct book *b; // Initializing pointer to a structure scanf ("%d\n", &n); b = (struct book *) calloc (n, sizeof (struct book)); //Creating memory for array of structures dynamically for (i = 0; i < n; i++) { scanf ("%s %d\n", (b + i)->name, &(b + i)->p); //Getting values for array of structures (no error check) } for (i = 0; i < n; i++) { printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures } scanf ("%d\n", &n); //Get array size to re-allocate b = (struct book *) realloc (b, n * sizeof (struct book)); //change the size of an array using realloc function printf ("\n"); for (i = 0; i < n; i++) { printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures } return 0; } 

Echa un vistazo a malloc y realloc .