7
votes

Array Dynamic en C - Realloc

Je sais comment construire des tableaux alloués dynamiquement, mais pas comment les développer.

Par exemple, j'ai l'interface suivante .. p> xxx pré>

Cette méthode prend un sommet et le stocke dans la matrice OUT. Après avoir stocké le sommet, j'augmente le nombre de longueurs pour les appels futurs. P>

P1 - est le sommet que je vais ajouter. P>

Out [] - est le tableau que j'ai besoin de stockez-le dans (qui est toujours plein) p>

longueur - la longueur du courant p>

vertex est définie comme .. / p> xxx pré>

ceci est ce que j'utilise dans java .. p> xxx pré>

C'est ce que je croyais que je pourrais utiliser dans c .. p> xxx pré> p> Cependant, je continue à recevoir un message d'erreur que l'objet n'a pas été attribué de manière dynamique. P>

J'ai trouvé une solution qui résoudra cela .. Au lieu d'utiliser Vertex * J'allais passer au sommet ** et stocker des pointeurs contre le sommet. Cependant, après avoir tout écrit sur tout ce que j'ai découvert que j'ai examiné le fait que le test de l'unité me fournisse un sommet sur [] que tout doit être stocké. P>

J'ai aussi essayé ce qui suit Pas de chance. p> xxx pré>

Cependant, quoi que je fais que je fais lorsque je teste après que ces deux, le tableau renvoyé n'a pas changé. P>

Mise à jour - Informations demandées forte> p>

Out - est définie comme une matrice de sommet (Vertex Out Out []) P>

Il est initialement construit avec le nombre de sommets dans mon polygone. Par exemple. P>

out = (sommet *) malloc (Vertexinpolygon * Tailleof (sommet)) p>

où Vertexinpolygon est un entier du nombre de sommets du sommet dans le polygone. P>

La longueur était une faute de frappe qui aurait dû être la taille. p>

Taille est un pointeur entier p> xxx pré>

chaque fois qu'un sommet est dans l'avion de coupure que nous ajoutez-le au tableau de sommet et augmentez la taille par une. p>

strong> p>

Pour mieux m'expliquer, je suis arrivé à un court programme pour montrer quoi J'essaie de faire. P>

#include <stdio.h>
#include <stdlib.h>

typedef struct Vertex {
    int x, y;
} Vertex;

void addPointerToArray(Vertex v1, Vertex out[], int *size);

void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
    int newSize = *size;
    newSize++;
    
    out = realloc(out, newSize * sizeof(Vertex));
    out[(*size)] = v1;
    
    //  Update Size
    *size = newSize;
}

int main (int argc, const char * argv[])
{
    //  This would normally be provided by the polygon
    int *size = malloc(sizeof(int)); *size = 3;
    
    //  Build and add initial vertex
    Vertex *out = (Vertex *)malloc((*size) * sizeof(Vertex));
    Vertex v1; v1.x = 1; v1.y =1;
    Vertex v2; v2.x = 2; v2.y =2;
    Vertex v3; v3.x = 3; v3.y =3;
    
    out[0] = v1;
    out[1] = v2;
    out[2] = v3;
    
    //  Add vertex
    //  This should add the vertex to the last position of out
    //  Should also increase the size by 1;
    Vertex vertexToAdd; vertexToAdd.x = 9; vertexToAdd.y = 9;
    addPointerToArray(vertexToAdd, out, size);
    
    for(int i =0; i < (*size); i++)
    {
        printf("Vertx: (%i, %i) Location: %i\n", out[i].x, out[i].y, i);
    }
   
}

c

9 commentaires

Qu'est-ce que out défini comme? Quelles sont les longueur et taille ?


Vous avez dit realloc s'est plaint de ne pas être alloué de manière dynamique. Alors ... était-ce? Vous devez utiliser MALLOC d'abord afin de pouvoir utiliser realloc plus tard.


Pouvez-vous également montrer la définition de longueur ou Taille avant qu'elle soit transmise à insertex ()


EvGeny Out est défini comme ... Vertex * Out = (Vertex *) MALLOC (Tailleof (Vertex) * NUMPOFVERINPOLYGON) Où NUMPOFVERINPOLYGONGONGONGONGONGONGE est le nombre de sommets dans le polygone. Daniel Brockman Oui, il est défini avec Malloc. Avant qu'il est passé, il est défini comme suit. VERTEX * OUT = (sommet *) MALLOC (Tailleof (Vertex) * NUMPOFVERINPOLYGON) Timothyjones Désolé, la longueur et la taille sont la même chose. J'ai mis à jour le poteau afin que tout utilise la taille. La taille commence comme zéro: int * taille = 0; Au fur et à mesure que nous passons à chaque sommet si c'est dans la clipsure de la taille, la taille est augmentée d'une après ajoutée au [] (sommet)


int * Taille = 0 initialiserait la taille avec NULL, et le pointe de rien - ne vous donne pas un pointeur à un int défini sur 0. Sauf si vous le signalez Sur un INT plus tard, cela peut être votre problème.


@Chrislutz Devrait-il être sous une autre balise? J'ai pensé que ma principale question était basée sur REALLOC * MALLOC que c était la bonne balise. Si ce n'est pas ce qu'est-ce que c'est?


Cela compilait bien sur GCC, mais votre compilateur peut voir le [] comme un pointeur de tableau. Essayez de remplacer VOID AddpointERToarray (Vertex V1, Vertex Out [], int * Taille) avec Void AddpointERToarray (Vertex V1, Vertex * Out, int * Taille)


@Aslai merci! Lorsque j'ai déplacé le code sur l'une de nos machines Linux, elle compilait et couru sans aucun problème.


@Chrislutz Chris Vous devez avoir manqué la ligne au-dessus de cet exemple qui se lit "C'est ce que j'utilise dans Java ..."


4 Réponses :


0
votes

Votre exemple de programme fonctionne bien pour moi. J'utilise GCC 4.1.1 sur Linux.

Toutefois, si votre programme réel ressemble à votre exemple de programme, c'est plutôt inefficace!

Par exemple, votre programme copie une mémoire beaucoup: Copies de structure - Initialisation Out , passant des sommets à AddpointERTOARRAY () , Memory Copies via Realloc () < / code>.

Passez des structures via un pointeur plutôt que par copie.

Si vous devez augmenter la taille de votre type de liste, vous pouvez mieux vous éteindre à utiliser une liste liée, un arborescence ou une autre structure (en fonction du type d'accès que vous souhaitez plus tard).

Si vous devez simplement avoir un type de vecteur, une méthode standard de mise en œuvre de vecteurs de taille dynamique consiste à attribuer un bloc de mémoire (par exemple, de la place pour 16 sommets) et de doubler sa taille à chaque fois que vous manquez d'espace. Cela limitera le nombre de réallocs requis.


0 commentaires

1
votes

J'ai quelques suggestions pour votre considération:
1. N'utilisez pas le même paramètre d'entrée et de sortie tout en utilisant realloc code> strong> car il peut renvoyer null code> dans la mémoire de la mémoire échoue et la mémoire pointée précédemment est divulguée. Realloc Code> peut renvoyer un nouveau bloc de mémoire (grâce à @jonathan Leffler pour avoir souligné cela, j'avais manqué cela). Vous pouvez modifier votre code à quelque chose sur ces lignes:

Vertex * new_out = realloc(out,  newSize * sizeof(Vertex));
if( NULL != new_out )
{    
    out = new_out;
    out[(*size)] = v1;
}
else
{
 //Error handling & freeing memory
}


2 commentaires

+0.5: Vous avez fait de bons points - notamment sur l'utilisation abusive de out = realloc (Out, Newsize * Tailleof (sommet)); . Cependant, vous n'avez pas mentionné le point crucial que realloc () peut renvoyer un pointeur différent de celui fourni - les données peuvent bouger. Ce fait exige une stratégie différente; voir ma réponse.


@Jonathan Leffler: Merci beaucoup! Je l'avais manqué ... Réponse éditée.



5
votes

Un problème à long terme est que vous ne retournez pas le pointeur de tableau mis à jour à partir du AddpointERTOARRAY () code> Fonction: xxx pré>

lorsque vous réaffectant l'espace, il peut Déplacez-vous vers un nouvel emplacement, la valeur de retour de realloc () code> n'a pas besoin d'être identique au pointeur d'entrée. Cela pourrait fonctionner lorsqu'il n'y a pas d'autre allocation de mémoire ne se passe pendant que vous ajoutez au tableau car realloc () code> prolongera une allocation existante alors qu'il y a de la place pour le faire, mais cela échouera horriblement une fois que vous commencez attribuer d'autres données tout en lisant les sommets. Il y a quelques façons de résoudre ce problème: p> xxx pré>

et invocation: p> xxx pré>

alternativement, vous pouvez passer dans un Pointeur sur le tableau: P>

int main(void)
{
    VertexList array;
    initVertexList(&array);
    addPointerToArray((Vertex){ 1, 1 }, &array);  // C99 compound literal
    addPointerToArray((Vertex){ 2, 2 }, &array);
    addPointerToArray((Vertex){ 3, 3 }, &array);
    addPointerToArray((Vertex){ 9, 9 }, &array);

    for (int i = 0; i < array->num_inuse; i++)
        printf("Vertex %d: (%d, %d)\n", i, array->list[i].x, array->list[i].y, i);

    return 0;
}


3 commentaires

Leffier merci. Vous et Santoj me et Santoj m'a vraiment aidé. J'ai mis à jour ma méthode et je voulais savoir si cela irait bien. «Void Addpointertopointerarray (Vertex V1, Vertex ** Out, int * Taille) {INT Newsizize = * Taille; Newsize ++; Sommet * tempout = (sommet *) MALLOC (Tailleof (Vertex) * Commentaires); si (tempout! = 0) {int i = 0; tandis que (i <* taille) {tempout [i] = (* out) [i]; i ++; } libre (* out); * OUT = TEMPOUT; } (* out) [(* taille)] = v1; * Taille = se positionnement; } '


Oui - avec des réserves. Le pendant que doit probablement être un pour boucle ou remplacé par un Memmove () ou memcpy () . Utilisation de realloc () signifie que vous ne feriez pas la copie vous-même et que vous n'avez pas besoin de tout copier. L'incrémentation de la taille par une chaque fois devient un problème lorsque vous utilisez la fonction plus, en particulier dans le mode "Toujours copier". La première fois que vous en ajoutez une, vous copiez 3 éléments; le prochain, vous copiez 4; La prochaine, vous copiez 5, etc. Mais ce que vous avez l'air de faire le travail. (Je me suis reformaté au globe oculaire. Je n'ai pas exécuté après un compilateur, beaucoup moins Valgrind .)


Grande explication. Merci.



0
votes

Essayez ces modifications, cela devrait fonctionner.

addPointerToArray(vertexToAdd, &out, size);
  • Il existe un moyen simple de résoudre ce type de problème (vous pourriez le savoir déjà). Lorsque vous passez une dispute à une fonction, pensez à ce que ce qui passe exactement à la pile, puis combine le fait que ce que les changements jamais que vous apportez aux variables présentes sur la pile disparaissent lors de la sortie de la fonction. Cette pensée devrait résoudre la plupart des problèmes liés aux arguments de passage. P> li>

  • Venir à la partie d'optimisation, la sélection de la bonne structure de données est essentielle au succès de tout projet. Comme quelqu'un souligné ci-dessus, la liste de liaisons est une meilleure structure de données pour vous que le tableau. P> li> ul> p>


0 commentaires