J'ai un programme qui lit une liste "brute" d'entités dans le jeu, et j'ai l'intention de créer un tableau contenant un numéro d'index (int) d'un nombre indéterminé d'entités, pour le traitement de diverses choses. Je voudrais éviter d'utiliser trop de mémoire ou de processeur pour conserver de tels index ...
Une solution simple et rapide que j’utilise jusqu’à présent consiste à déclarer, dans la fonction de traitement principale (focus local), le tableau avec la taille maximale du nombre d’entités de jeu et un autre entier pour en suivre le nombre Ce n'est pas satisfaisant, car chaque liste contient plus de 3000 tableaux, ce qui n'est pas beaucoup, mais donne l'impression d'être un gaspillage, car je pourrai utiliser la solution pour 6-7 listes pour différentes fonctions.
Je n'ai trouvé aucune solution spécifique C (pas C++ ou C #) pour y parvenir. Je peux utiliser des pointeurs, mais j'ai un peu peur de les utiliser (à moins que ce soit la seule façon possible).
Les tableaux ne quittent pas la portée de la fonction locale (ils doivent être transmis à une fonction, puis supprimés), au cas où cela changerait les choses.
Si les pointeurs sont la seule solution, comment puis-je les garder pour éviter les fuites?
Je peux utiliser des pointeurs, mais j'ai un peu peur de les utiliser.
Si vous avez besoin d'un tableau dynamique, vous ne pouvez pas échapper aux pointeurs. Pourquoi as-tu peur cependant? Ils ne mordront pas (pourvu que vous fassiez attention). Il n'y a pas de tableau dynamique intégré en C, vous devrez simplement en écrire un vous-même. En C++, vous pouvez utiliser le std::vector
class intégré. C # et presque tous les autres langages de haut niveau ont également une classe similaire qui gère les tableaux dynamiques pour vous.
Si vous envisagez d’écrire le vôtre, voici quelque chose qui vous aidera à démarrer: la plupart des implémentations de tableaux dynamiques fonctionnent avec un tableau de taille (petite) par défaut, puis, chaque fois que vous manquez d’espace lorsque vous ajoutez un nouvel élément, taille du tableau. Comme vous pouvez le voir dans l'exemple ci-dessous, ce n'est pas très difficile du tout: (j'ai omis les contrôles de sécurité par souci de brièveté)
typedef struct {
int *array;
size_t used;
size_t size;
} Array;
void initArray(Array *a, size_t initialSize) {
a->array = (int *)malloc(initialSize * sizeof(int));
a->used = 0;
a->size = initialSize;
}
void insertArray(Array *a, int element) {
// a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
// Therefore a->used can go up to a->size
if (a->used == a->size) {
a->size *= 2;
a->array = (int *)realloc(a->array, a->size * sizeof(int));
}
a->array[a->used++] = element;
}
void freeArray(Array *a) {
free(a->array);
a->array = NULL;
a->used = a->size = 0;
}
Son utilisation est aussi simple:
Array a;
int i;
initArray(&a, 5); // initially 5 elements
for (i = 0; i < 100; i++)
insertArray(&a, i); // automatically resizes as necessary
printf("%d\n", a.array[9]); // print 10th element
printf("%d\n", a.used); // print number of elements
freeArray(&a);
Je peux penser à plusieurs options.
array[100]
sans avoir à parcourir 1-99
au préalable. Et ce ne serait peut-être pas pratique pour vous d'utiliser non plus.Il est difficile de dire quelle option serait la meilleure dans votre situation. Créer simplement un grand ensemble est bien sûr l’une des solutions les plus simples et ne devrait pas vous poser beaucoup de problèmes à moins qu’il soit vraiment grand.
Quand tu dis
faire un tableau contenant un numéro d'index (int) d'un nombre indéterminé d'entités
vous dites essentiellement que vous utilisez des "pointeurs", mais l'un d'entre eux est un pointeur local étendu à un tableau au lieu d'un pointeur étendu à la mémoire. Puisque vous utilisez déjà conceptuellement des "pointeurs" (c.-à-d. Des numéros d'identification qui font référence à un élément d'un tableau), pourquoi ne pas simplement utiliser des pointeurs normaux ).
Au lieu que vos objets stockent des numéros d'identification de ressources, vous pouvez leur demander de stocker un pointeur. Fondamentalement la même chose, mais beaucoup plus efficace puisque nous évitons de transformer "tableau + index" en "pointeur".
Les pointeurs ne sont pas effrayants si vous les considérez comme des index de tableau pour toute la mémoire (ce qu’ils sont réellement)
Construire sur Matteo Furlans design, quand il a dit "la plupart des implémentations de tableaux dynamiques fonctionnent à partir d’un tableau de petite taille taille du tableau ". La différence dans le " travaux en cours " ci-dessous est que sa taille ne double pas, elle vise uniquement à utiliser ce qui est requis. J'ai aussi omis les vérifications de sécurité pour plus de simplicité ... Construisant également sur brimboriums idée, j'ai essayé d'ajouter une fonction de suppression au code ...
Le fichier storage.h ressemble à ceci ...
#ifndef STORAGE_H
#define STORAGE_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
int *array;
size_t size;
} Array;
void Array_Init(Array *array);
void Array_Add(Array *array, int item);
void Array_Delete(Array *array, int index);
void Array_Free(Array *array);
#ifdef __cplusplus
}
#endif
#endif /* STORAGE_H */
Le fichier storage.c ressemble à ceci ...
#include <stdio.h>
#include <stdlib.h>
#include "storage.h"
/* Initialise an empty array */
void Array_Init(Array *array)
{
int *int_pointer;
int_pointer = (int *)malloc(sizeof(int));
if (int_pointer == NULL)
{
printf("Unable to allocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else
{
array->array = int_pointer;
array->size = 0;
}
}
/* Dynamically add to end of an array */
void Array_Add(Array *array, int item)
{
int *int_pointer;
array->size += 1;
int_pointer = (int *)realloc(array->array, array->size * sizeof(int));
if (int_pointer == NULL)
{
printf("Unable to reallocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else
{
array->array = int_pointer;
array->array[array->size-1] = item;
}
}
/* Delete from a dynamic array */
void Array_Delete(Array *array, int index)
{
int i;
Array temp;
int *int_pointer;
Array_Init(&temp);
for(i=index; i<array->size; i++)
{
array->array[i] = array->array[i + 1];
}
array->size -= 1;
for (i = 0; i < array->size; i++)
{
Array_Add(&temp, array->array[i]);
}
int_pointer = (int *)realloc(temp.array, temp.size * sizeof(int));
if (int_pointer == NULL)
{
printf("Unable to reallocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else
{
array->array = int_pointer;
}
}
/* Free an array */
void Array_Free(Array *array)
{
free(array->array);
array->array = NULL;
array->size = 0;
}
Le main.c ressemble à ceci ...
#include <stdio.h>
#include <stdlib.h>
#include "storage.h"
int main(int argc, char** argv)
{
Array pointers;
int i;
Array_Init(&pointers);
for (i = 0; i < 60; i++)
{
Array_Add(&pointers, i);
}
Array_Delete(&pointers, 3);
Array_Delete(&pointers, 6);
Array_Delete(&pointers, 30);
for (i = 0; i < pointers.size; i++)
{
printf("Value: %d Size:%d \n", pointers.array[i], pointers.size);
}
Array_Free(&pointers);
return (EXIT_SUCCESS);
}
Attendez-vous à la critique constructive à suivre ...
Eh bien, je suppose que si vous devez supprimer un élément, vous en ferez une copie en dédaignant l'élément à exclure.
// inserting some items
void* element_2_remove = getElement2BRemove();
for (int i = 0; i < vector->size; i++){
if(vector[i]!=element_2_remove) copy2TempVector(vector[i]);
}
free(vector->items);
free(vector);
fillFromTempVector(vector);
//
Supposons que getElement2BRemove()
, copy2TempVector( void* ...)
et fillFromTempVector(...)
sont des méthodes auxiliaires permettant de gérer le vecteur temp.
Pour créer un tableau d'éléments illimités de tout type:
typedef struct STRUCT_SS_VECTOR {
size_t size;
void** items;
} ss_vector;
ss_vector* ss_init_vector(size_t item_size) {
ss_vector* vector;
vector = malloc(sizeof(ss_vector));
vector->size = 0;
vector->items = calloc(0, item_size);
return vector;
}
void ss_vector_append(ss_vector* vec, void* item) {
vec->size++;
vec->items = realloc(vec->items, vec->size * sizeof(item));
vec->items[vec->size - 1] = item;
};
void ss_vector_free(ss_vector* vec) {
for (int i = 0; i < vec->size; i++)
free(vec->items[i]);
free(vec->items);
free(vec);
}
et comment l'utiliser:
// defining some sort of struct, can be anything really
typedef struct Apple_STRUCT {
int id;
} Apple;
Apple* init_Apple(int id) {
Apple* a;
a = malloc(sizeof(Apple));
a-> id = id;
return a;
};
int main(int argc, char* argv[]) {
ss_vector* vector = ss_init_vector(sizeof(Apple));
// inserting some items
for (int i = 0; i < 10; i++)
ss_vector_append(vector, init_Apple(i));
// dont forget to free it
ss_vector_free(vector);
return 0;
}
Ce vecteur/tableau peut contenir n’importe quel type d’élément et sa taille est complètement dynamique.