Corrections, amélorations code C

Bonsoir :slightly_smiling:

Est ce quelqu’un pourrait voir et me dire comment améliorer ces codes C svp ?
Je bosse un peu sur les listes chainées.

Merci :blush:

[code]#include “lc.h”

int append_f(int_element **liste, int val)
{
int_element new_element = (int_element) malloc( sizeof(int_element));
if(!new_element) exit(EXIT_FAILURE);

new_element->val = val;
new_element->suivant = *liste;

*liste = new_element;
return 1;

}

int pop_f(int_element **liste)
{
int_element *suppr = (*liste);

*liste = (*liste)->suivant;
free(suppr);
return 1;

}

void affiche_f(int_element *liste)
{
while(liste != NULL)
{
printf("%x <- Addresse : %x -> valeur : %d\n", liste->suivant, liste, liste->val);
liste = liste->suivant;
}

}

int clear_f(int_element **liste)
{
int_element *suppr = NULL;

while(*liste != NULL)
{
    *suppr = (*liste);
    *liste = (*liste)->suivant;
    free(suppr);
}
return 1;

}
[/code]

[code]#ifndef LC_H
#define LC_H

/**

  • \file lc.h
  • \version 0.1
  • \date 01/03/2015
    */

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

/* le type int_element */
typedef struct int_element
{
//struct int_element *precedent;
int val;
struct int_element *suivant;
} int_element;

int append_f(int_element **liste, int val);
void affiche_f(int_element *liste);
int pop_f(int_element **liste);

#endif
[/code]

Coucou,

Pour le moment, ta liste ne peut stocker que des int. Je dirais qu’on peut améliorer ton code de ce point de vue, et le rendre plus générique, avec la structure suivante :

typedef struct   list
{
    void         *content;
    size_t       size;
    struct list  *next;
}                list;

Ou tu remplaces le content par ce que tu veux : un pointeur sur une structure, une chaîne de caractère, etc… Le champ size est alors utile pour savoir la taille de ce qui est stocké en mémoire pour en faire une copie, etc…

Ce code, plus générique, nécessite d’autres fonctions plus souples pour travailler avec, et ce avec des pointeurs sur fonction pour une véritable modularité. Par exemple, ton code d’affichage deviendrait :

void   lst_print(list *lst, void (*f)(list *))
{
    while(lst != NULL)
    {
        f(lst);
        lst = lst->next;
    }

}

Si tu stockes des chaînes de caractère dans tes maillons (par exemple), ça donnera :

void   print_string(list *lst)
{
    printf("Contenu: [%.*s]\n", lst->size, (char *)(lst->content));
}

/* on l'utilise ainsi dans le code : */
lst_print(ma_liste_de_strings, &print_string);

Ce code te permet de faire une bibliothèque vraiment modulable que tu n’auras pas besoin de retoucher par la suite. Il y aurait d’autres choses à faire, mais partir sur un code plus modulable est déjà un bon début, je crois. C’est là qu’on voit que les pointeurs sur fonction, c’est la vie. (Je me suis fait une bibliothèque personnelle pour utiliser les listes chaînées, je peux te l’envoyer si tu veux).

Ce sujet date un peu, mais j’ai à nouveau du temps pour bosser tout ça.

Je veux bien ta bibliothèque si tu le permets pour l’étudier un peu.

Merci :slight_smile:

Tiens https://github.com/Morovaille/libcfdv/

Je l’ai faite hier et ce matin à partir d’une autre que j’avais déjà faite. Je pense qu’elle est fonctionnelle, avec toutes les fonctionnalités couramment utiles. Si tu trouves un beug, je veux bien que tu le signales.

Merci :slight_smile:

Au fait, j’ai eu un blocage en voyant le nom libcfdv, pourquoi fdv ?

C’est un manque total d’imagination de ma part : ce sont mes initiales. Et j’ai l’habitude de tout préfixer pour éviter de tomber sur des noms de fonction / macros déjà existants. Une des fonctionnalités introduites par le C++ qui me “manque” le plus en C est les namespaces :stuck_out_tongue:

Ok, parce que ce sont aussi mes initiales, et du coup, j’étais intrigué :smiley:

Ah oui, quand même… c’était assez improbable.

T’as vu, le code n’est pas trop compliqué ? Et on peut l’utiliser avec n’importe quoi. D’ailleurs, je pense faire la même chose, mais avec un arbre binaire balancé ; ou encore un tableau dynamique qui se redimensionne automatiquement quand on ajoute des éléments. Je pourrais en faire une version avec la contiguïté en mémoire, et une autre sans. Enfin je verrai quand je m’ennuierai.

Je pense que c’est abordable pour moi, il va me falloir un peu de temps pour décortiquer tout ça et bien comprendre comme ça marche.

Tu dis faire une version avec un tableau dynamique qui se redimensionne, mais j’ai toujours lu que cette méthode coutait énormément en ressources ?

Quel pourrait être l’avantage d’une version avec des données contigües ou non ?

Eh bien ça dépend : si c’est non contigu, ça ne coûte pas grand’ chose, c’est un simple tableau de pointeurs qu’on redimensionne de temps en temps quand on ajoute des éléments.

L’avantage de ressources contiguës, c’est qu’on peut se déplacer avec le pointeur, genre :

// declaration du pointeur begin sur le premier element
for (size_t i = 0 ; i < len ; ++i)
{
    // on utilise begin + i
}

Ici, ça ne sert à rien, mais quand par exemple on le passe en paramètre à une fonction, on peut écrire pointeur + 1 sans risque puisque les données sont contiguës.

Je ne sais pas si j’ai bien expliqué.