Une solution simple consiste à mmap
. C'est très bien si vous pouvez tolérer une solution POSIX. Il suffit de mapper une page entière et de se prémunir contre les débordements, puisque realloc
échouerait de toute façon pour de telles valeurs. Les systèmes d'exploitation modernes ne s'engagent pas sur l'ensemble du lot tant que vous ne l'utilisez pas, et vous pouvez tronquer les fichiers si vous le souhaitez.
Sinon, il y a realloc
. Comme pour tout ce qui semble plus effrayant au début que par la suite, la meilleure façon de surmonter la peur initiale est de s'immerger dans l'inconfort de l'inconnu ! C'est dans ces moments-là qu'on apprend le plus, après tout.
Malheureusement, il y a des limites. Pendant que vous apprenez à utiliser une fonction, vous ne devez pas assumer le rôle de professeur, par exemple. Je lis souvent les réponses de ceux qui ne savent apparemment pas comment utiliser les fonctions realloc
(c'est-à-dire la réponse actuellement acceptée ! ) qui expliquent aux autres comment l'utiliser de manière incorrecte, parfois sous prétexte qu'ils ont traitement des erreurs omis même s'il s'agit d'un piège courant qu'il convient de mentionner. Voici une réponse expliquant comment utiliser realloc
correctement . Notez que la réponse consiste à stocker la valeur de retour dans un fichier de type différents afin d'effectuer une vérification des erreurs.
Chaque fois que vous appelez une fonction, et chaque fois que vous utilisez un tableau, vous utilisez un pointeur. Les conversions se font implicitement, ce qui devrait être encore plus effrayant, car ce sont les choses que nous ne voyons pas qui causent souvent le plus de problèmes. Par exemple, les fuites de mémoire...
Les opérateurs de tableau sont des opérateurs de pointeur. array[x]
est en fait un raccourci pour *(array + x)
qui peut être décomposé en : *
y (array + x)
. Il est fort probable que le *
est ce qui vous perturbe. Nous pouvons encore éliminer l'addition du problème en supposant que x
à être 0
donc, array[0]
devient *array
parce qu'en ajoutant 0
ne changera pas la valeur...
... et ainsi nous pouvons voir que *array
est équivalent à array[0]
. Vous pouvez utiliser l'un d'eux là où vous voulez utiliser l'autre, et vice versa. Les opérateurs de tableau sont des opérateurs de pointeur.
malloc
, realloc
et les amis ne le font pas inventer le concept de pointeur que vous utilisez depuis le début ; ils se contentent de utiliser ceci pour mettre en œuvre une autre fonctionnalité, qui est une forme différente de durée de stockage, plus adaptée lorsque vous souhaitez des changements radicaux et dynamiques de taille .
C'est une honte que la réponse actuellement acceptée également va à l'encontre des principes de d'autres conseils très bien fondés sur StackOverflow Mais en même temps, il rate l'occasion d'introduire une fonctionnalité peu connue qui se prête parfaitement à ce cas d'utilisation : les membres de tableau flexibles ! C'est en fait une plutôt cassé réponse... :(
Lorsque vous définissez votre struct
déclarez votre tableau à la fin de la structure, sans aucune limite supérieure. Par exemple :
struct int_list {
size_t size;
int value[];
};
Cela vous permettra d'unir votre réseau de int
dans la même allocation que votre count
et les faire relier comme ça peut être très pratique !
sizeof (struct int_list)
agira comme si value
a une taille de 0, donc il vous dira la taille de la structure avec une liste vide . Vous devez encore ajouter à la taille transmise à realloc
pour spécifier la taille de votre liste.
Un autre conseil pratique est de se rappeler que realloc(NULL, x)
est équivalent à malloc(x)
et nous pouvons l'utiliser pour simplifier notre code. Par exemple :
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 raison pour laquelle j'ai choisi d'utiliser struct int_list **
en tant que premier argument peut ne pas sembler immédiatement évident, mais si vous pensez au second argument, toute modification apportée à l'option value
de l'intérieur push_back
ne serait pas visible pour la fonction que nous appelons, n'est-ce pas ? Il en va de même pour le premier argument, et nous devons être en mesure de modifier notre code d'accès. array
pas seulement aquí mais éventuellement aussi dans toute autre fonction à laquelle nous le passons ...
array
ne pointe sur rien ; c'est une liste vide. Initialisation de c'est la même chose que de l'ajouter. Par exemple :
struct int_list *array = NULL;
if (!push_back(&array, 42)) {
// success!
}
P.S. N'oubliez pas de free(array);
quand vous en aurez fini avec elle !
1 votes
Il s'agit d'un (très, très petit) problème en C, mais comment avez-vous manqué toutes les solutions en C++ et C# pour cela ?
18 votes
"Si les pointeurs sont la seule solution, comment puis-je en garder la trace pour éviter les fuites ?". Attention, attention, et valgrind. C'est exactement la raison pour laquelle les gens ont si peur du C en premier lieu.
46 votes
Vous ne pouvez pas utiliser efficacement le C sans utiliser les pointeurs. N'ayez pas peur.
0 votes
Sans grandes librairies, une seule fonction pour tous, même pour les structures, par exemple : stackoverflow.com/questions/3456446/
14 votes
Utiliser le langage C sans pointeurs, c'est comme utiliser une voiture sans carburant.
2 votes
C est une tronçonneuse avec toutes les sécurités enlevées. Mais ne vous inquiétez pas, si vous perdez un doigt ou une main, C vous en donnera un autre. (Une autre tronçonneuse, bien sûr.)