Vecteur de structures contenant des strings

a marqué ce sujet comme résolu.

Bonjour,

Je suis un peu rouillé sur la gestion de la mémoire en C visiblement, donc je viens demander votre aide.

J’ai le record suivant :

typedef struct dummy_t {
    int value;
    char * text1;
    char * text2;
} dummy_t;

J’ai créé une petite stack en C me permettant uniquement d’ajouter des éléments au dessus (pas d’en retirer) :

typedef struct stack_t {
    size_t capacity;
    size_t size;
    dummy_t * data;
} stack_t;

Trois petites fonctions lui sont associées :

void stack_initialize(stack_t * stack)
{
    stack->capacity = VALUE_FROM_DEFINE; // La valeur définie est 8, on ne traite que deux éléments pour le moment donc pas de stack dynamique
    stack->size = 0;
    stack->data = (dummy_t*)malloc(VALUE_FROM_DEFINE * sizeof(dummy_t));
}

void stack_destroy(stack_t * stack)
{
    for (size_t i = 0; i < stack->size; i++)
    {
        free(stack->data[i].text1);
        stack->data[i].text1 = NULL;

        free(stack->data[i].text2);
        stack->data[i].text2 = NULL;
    }

    free(stack->data);
    stack->data = NULL;
}

void stack_push(stack_t * stack, dummy_t * element)
{
    stack->data[stack->size] = *element;
    
    size_t length = strlen(element->text1) + 1;
    stack->data[stack->size].text1 = (char*)malloc(length);
    memcpy(&(stack->data[stack->size].text1), &element->text1, length);

    length = strlen(element->text2) + 1;
    stack->data[stack->size].text2 = (char*)malloc(length);
    memcpy(&(stack->data[stack->size].text2), &element->text2, length);

    stack->size++;
}

Je précise que ma stack est dynamique et peut donc s’agrandir, mais on ne rentre pas dans ce cas encore donc je le laisse de côté.

J’ai un objet stackt_t global, initialisé au démarrage de l’application dans lequel l’utilisateur peut pousser des éléments dummy_t quand il le souhaite :

void create_dummy(char * text1, char * text2)
{
    dummy_t d;
    d.value = 0;
    d.text1 = text1;
    d.text2 = text2;

    stack_push(__global_buffer, &d);
}

J’ai cependant une erreur lors de stack_destroy, il semblerait que je fasse un double free : double free or corruption (fasttop) o_O

Je comprend mieux ce qu’il se passe lorsque je print les adresses, mes pointeurs dans mon tableau ont des adresses… originale :

[element 0] text1: 0x2124f50, text2: 0x2124f80, data: 0x2124030
[element 1] text1: 0x2124f80, text2: 0x2124f50, data: 0x2124030

text1 et text2 ont échangés les adresses vers quoi ils pointent ?? En effet quand je print les strings, ça n’a aucun sens.

Deux questions :

  • Qu’est-ce qu’il se passe ?
  • Comment réaliser ce que je veux faire en évitant au maximum les copies ? Je pensais m’en être plutôt bien sorti.

Merci pour vos réponses.

J’ai finalement trouvé le problème qui était dans les memcpy ou je donnais les adresses des strings en références au lieu de les donner directement :

memcpy(&(stack->data[stack->size].text1), &element->text1, length);
// au lieu de 
memcpy(stack->data[stack->size].text1, element->text1, length);

Je laisse cependant ouvert pour ma seconde question :

  • Comment réaliser ce que je veux faire en évitant au maximum les copies ? Je pense m’en être plutôt bien sorti.

Salut,

Comment réaliser ce que je veux faire en évitant au maximum les copies ?

Pour commencer, qu’est-ce que tu veux faire ? Parce que si tu veux quelque chose d’équivalent à ce que tu as déjà, ça me semble compliqué de faire mieux.

+0 -0

Salut,

T’as un problème de séparation des responsabilités (c’est du C, mais quand même! :p ), la stack ne devrait pas avoir à se soucier de la structure interne de dummy_t. Tu pourrais avoir une fonction qui s’occupe de copier un dummy_t, qui serait appelée par stack_push (ça rendra aussi les choses plus claires quand tu t’occuperas des cas où la capacité doit changer). Et utilise strcpy au lieu de t’occuper du NULL final à la main.

+0 -0

Bonsoir, Merci pour vos retours.

Pour commencer, qu’est-ce que tu veux faire ? Parce que si tu veux quelque chose d’équivalent à ce que tu as déjà, ça me semble compliqué de faire mieux.

luxera

Pour un projet nous avons besoin de prendre des valeurs de plusieurs sections de code. La librarie que je propose permet de pousser des évènements avec n´importe quelle donnée dedans sur une stack, stack qui est écrite dans un xml lorsque l´on quitte le programme (que ce soit normalement ou par une interruption).

En l´état tout fonctionne. Il faut cependant que la bibliothèque ai la plus petite empreinte sur le programme auquel elle est linkée. D´où ma question de savoir si je fais des copies inutiles.

Salut,

T’as un problème de séparation des responsabilités (c’est du C, mais quand même! :p ), la stack ne devrait pas avoir à se soucier de la structure interne de dummy_t. Tu pourrais avoir une fonction qui s’occupe de copier un dummy_t, qui serait appelée par stack_push (ça rendra aussi les choses plus claires quand tu t’occuperas des cas où la capacité doit changer). Et utilise strcpy au lieu de t’occuper du NULL final à la main.

adri1

Oui en effet, j´ai écrit cette partie un peu vite quand j´ai vu qu´il fallait alouer à la main les tableaux de char lorsque l´on crée une instance du record.

Le NULL final je suis obligé de le prendre en compte pour faire le malloc avant non ? Donc que j’utilise memcpy ou strcpy, je dois quand même calculer la taille de ma string en ajoutant 1 non ?

Le NULL final je suis obligé de le prendre en compte pour faire le malloc avant non ? Donc que j’utilise memcpy ou strcpy, je dois quand même calculer la taille de ma string en ajoutant 1 non ?

Ouais, mais l’avantage de strcpy est que tu risques pas de te gourer sur la tailler à copier par rapport à memcpy et que l’intention du code est plus claire. Tu copies pas juste des bytes, tu copies des chaînes. Par ailleurs il faut vérifier la valeur de retour de malloc avant de s’en servir.

T’as aussi strdup qui fait le malloc pour toi si tu peux faire du C23 ou que tu as juste besoin d’être POSIX.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte