Utilisation de l’allocation de mémoire dynamic pour les tableaux

Comment suis-je censé utiliser les allocations de mémoire dynamics pour les tableaux?

Par exemple, voici le tableau suivant dans lequel je lis des mots individuels à partir d’un fichier .txt et les enregistre mot à mot dans le tableau:

Code:

char words[1000][15]; 

Ici, 1000 définit le nombre de mots que le tableau peut sauvegarder et chaque mot peut comporter 15 caractères maximum.

Maintenant, je veux que ce programme alloue dynamicment la mémoire pour le nombre de mots qu’il compte. Par exemple, un fichier .txt peut contenir des mots supérieurs à 1000. Maintenant, je souhaite que le programme compte le nombre de mots et alloue la mémoire en conséquence.

Comme nous ne pouvons pas utiliser une variable à la place de [1000], je ne sais pas comment implémenter ma logique. S’il vous plaît aidez-moi à cet égard.

Vous utilisez des pointeurs.

Plus précisément, vous utilisez un pointeur sur une adresse et, à l’aide d’appels d’une fonction standard de la bibliothèque c, vous demandez au système d’exploitation d’étendre le segment de mémoire pour vous permettre de stocker ce dont vous avez besoin.

Maintenant, il peut refuser, ce que vous devrez gérer.

La question suivante est la suivante: comment demander un tableau 2D? Eh bien, vous demandez un tableau de pointeurs, puis développez chaque pointeur.

A titre d’exemple, considérons ceci:

 int i = 0; char** words; words = malloc((num_words)*sizeof(char*)); if ( words == NULL ) { /* we have a problem */ printf("Error: out of memory.\n"); return; } for ( i=0; i 

Cela vous donne un tableau à deux dimensions, où chaque élément de words[i] peut avoir une taille différente, déterminable au moment de l'exécution, tout comme le nombre de mots.

Vous aurez besoin de free() toute la mémoire résultante en bouclant sur le tableau lorsque vous en aurez fini:

 for ( i = 0; i < num_words; i++ ) { free(words[i]); } free(words); 

Si vous ne le faites pas, vous allez créer une fuite de mémoire.

Vous pouvez également utiliser calloc . La différence réside dans l'appel des conventions et des effets - calloc initialise toute la mémoire à 0 contrairement à malloc .

Si vous devez redimensionner au moment de l'exécution, utilisez realloc .

  • Malloc
  • Calloc
  • Realloc
  • Libre

Aussi, faites attention au word_size + 1 que j'ai utilisé. Les chaînes en C sont terminées à zéro et cela prend un caractère supplémentaire que vous devez prendre en compte. Pour être word_size de m'en souvenir, je règle généralement la taille de la variable word_size sur la taille du mot (la longueur de la chaîne comme je le souhaite) et laisse explicitement le +1 dans le malloc pour le zéro. Ensuite, je sais que le tampon alloué peut prendre une chaîne de caractères word_size . Ne pas le faire est également acceptable - je le fais simplement parce que j'aime rendre compte explicitement du zéro de manière évidente.

Il y a aussi un inconvénient à cette approche - j'ai explicitement vu cela comme un bogue expédié récemment. Remarquez que j’ai écrit (word_size+1)*sizeof(type) - imaginez cependant que j’ai écrit word_size*sizeof(type)+1 . Pour sizeof(type)=1 il s'agit de la même chose, mais Windows utilise très fréquemment wchar_t . Dans ce cas, vous réserverez un octet pour votre dernier zéro au lieu de deux. zéro octet. Cela signifie que vous allez déborder en lecture et en écriture.

Addendum: faites-le comme bon vous semble, faites attention aux zéro terminateurs si vous voulez passer le tampon à quelque chose qui en dépend.

Bien que Ninefingers ait fourni une réponse à l’aide d’un tableau de pointeurs , vous pouvez également utiliser un tableau de tableaux à condition que la taille du tableau intérieur soit une expression constante. Le code pour cela est plus simple.

 char (*words)[15]; // 'words' is pointer to char[15] words = malloc (num_words * sizeof(char[15]); // to access character i of word w words[w][i]; free(words); 

Si vous avez l’intention de passer au C ++, STL est très utile pour une allocation dynamic et très simple. Vous pouvez utiliser std :: vector ..

Si le 15 dans votre exemple est variable, utilisez l’une des réponses disponibles (de Ninefingers ou John Boker ou Muggen). Si le 1000 est variable, utilisez realloc :

 words = malloc(1000 * sizeof(char*)); // ... read 1000 words if (++num_words > 1000) { char** more_words = realloc(words, 2000 * sizeof(char*)); if (more_words) {printf("Too bad");} else {words = more_words;} } 

Dans mon code ci-dessus, la constante 2000 est une simplification; vous devez append une autre capacity variable pour prendre en charge plus de 2000 mots:

 if (++num_words > capacity) { // ... realloc ++capacity; // will reallocate 1000+ words each time; will be very slow // capacity += 1000; // less reallocations, some memory wasted // capacity *= 2; // less reallocations but more memory wasted } 

Si vous travaillez en C:

 #include  #include  #include  #define WORD_LEN 15 int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent) { int result = 1; char (*tmp)[WORD_LEN] = realloc(*wordList, (*currentSize + extent) * sizeof **wordList); if (tmp) { *currentSize += extent; *wordList = tmp; } else result = 0; return result; } int main(void) { char *data[] = {"This", "is", "a", "test", "of", "the", "Emergency", "Broadcast", "System", NULL}; size_t i = 0, j; char (*words)[WORD_LEN] = NULL; size_t currentSize = 0; for (i = 0; data[i] != NULL; i++) { if (currentSize <= i) { if (!resizeArray(&words, &currentSize, 5)) { fprintf(stderr, "Could not resize words\n"); break; } } strcpy(words[i], data[i]); } printf("current array size: %lu\n", (unsigned long) currentSize); printf("copied %lu words\n", (unsigned long) i); for (j = 0; j < i; j++) { printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]); } free(words); return 0; } 

Voici quelques informations sur l’allocation dynamic de tableaux 2D:

http://www.eskimo.com/~scs/cclass/int/sx9b.html

 char ** words = malloc( 1000 * sizeof(char *)); int i; for( i = 0 ; i < 1000 ; i++) *(words+i) = malloc(sizeof(char) * 15); //.... for( i = 0 ; i < 1000 ; i++) free(*(words+i)); free(words); 

En C moderne (C99), vous avez un choix supplémentaire, des tableaux de longueur variable, VLA, tels que:

 char myWord[N]; 

En principe, une telle chose peut également être réalisée en deux dimensions, mais si votre taille devient trop grande, vous risquez un dépassement de capacité . Dans votre cas, le plus simple serait d’utiliser un pointeur sur un tel tableau et d’utiliser malloc / realloc pour les redimensionner:

 typedef char Word[wordlen]; size_t m = 100000; Word* words = malloc(m * sizeof(Word)); /* initialize words[0]... words[m-1] here */ for (size_t i = 0; i < m; ++i) words[i][0] = '\0'; /* array is too small? */ m *= 2; void *p = realloc(words, m*sizeof(Word)); if (p) words = p; else { /* error handling */ } . free(words); 

Ce code devrait fonctionner (typos modulo) si wordlen est une constante ou une variable, tant que vous conservez tout dans une fonction. Si vous voulez le placer dans une fonction, vous devez déclarer votre fonction comme ceci:

 void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]); 

c'est-à-dire que les parameters de longueur doivent d'abord être connus pour la déclaration de words .