Partage
  • Partager sur Facebook
  • Partager sur Twitter

Insérer et afficher une valeur

a travers un pointeur de fonction

Sujet résolu
12 février 2022 à 23:55:50

.

-
Edité par janaise 20 février 2022 à 19:12:55

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2022 à 0:34:09

Je n'ai pas regardé ton code en détail, j'ai tenté une compilation et j'ai 11 Warnings. Il faut donc commencer par les corriger !

janaise a écrit:

De plus je ne sais pas quel spécificateur je doit mettre pour afficher la valeur (de tout type de variable) avec le printf.

Alors là c'est même pas la peine d'y penser, printf ne sait pas afficher une variable dont il ne connait pas le type ?

janaise a écrit:

je ne sais pas comment afficher la valeur qui est pointé par un void.

Il faut faire un transtypage vers le type d'origine. tu n'as pas le choix.



  • Partager sur Facebook
  • Partager sur Twitter
...
13 février 2022 à 2:08:47

J'ai également regardé ton code en diagonale.
Ce qui est mélangeant est que tu définis tes types comme des pointeurs. Définis les sans cela et mentionnes-le dans tes déclarations à la place.
La meilleure façon de t'en sortir est de dire à toutes tes fonctions que le type des éléments est de type void.
Et tu fais du transtypage dans le main. Seul le main devrait connaitre le vrai type.
Tu devras définir les objets dans le main et passer aux fonctions le pointeur et la longueur des objets.
Je n'ai pas compris pour l'insertion. Est-ce que tu décales la fin pour insérer un nouvel élément?
Tu pourrais utiliser memcpy en lui donnant la longueur de ce qui doit être recopié.
On le fait un élément à la fois en partant de la fin vers le point d'insertion.
Sinon tu vas écraser les éléments suivants et ils seront tous égaux au premier décalé.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

13 février 2022 à 9:23:30

> afficher la valeur pointée par un void*

En utilisant un pointeur vers une fonction qui sait le faire.

---

Comme c'est un problème rigolo, j'ai développé l'idée sur un exemple du même genre (parce que je ne fais pas les exercices, etc).

Pb: faire un conteneur d'objets de type inconnu (mais le même), dans lequel on peut ajouter des éléments à la fin, qu'on peut trier, et faire afficher.

Je fais l'impasse sur l'extensibilité, et les autres opérations utiles - dont la libération, sinon ça va faire des kilomètres de code.

Idée de base : une structure de données tableau

struct Array {
    struct DTD *dtd;
    size_t size;
    void *data[10];   // not extensible
};


qui contient des pointeurs génériques vers les données effectives. Le type des données est décrit par une structure "DTD"

struct DTD { // data type description
    void* (*clone)(void *src);
    void (*print)(void *thing);
    int (*compare)(void *first, void *second);
};

qui, dans la plus pure tradition, définit un type abstrait en indiquant les opérations qu'on peut faire dessus.

Pour  les entiers , on aura

  struct DTD int_dtd = {
        .clone = int_clone,
        .print = int_print,
	.compare = int_compare
    };

avec les fonctions

void * int_clone(void *src)
{
    int *s = src;
    int *r = malloc(sizeof(int));
    *r = *s;
    return r;
}

void int_print(void *thing)
{
    int *t = thing;
    printf("%d", *t);
}

int int_compare(void * first, void *second)
{
    int *f = first, *s = second;
    return *f - *s;
}

(oui, j'ai la manie de transtyper les paramètres void* dès la première déclaration !)


Elles sont utilisées par ses fonctions sur les tableaux, qui à part ça n'ont rien d'étonnant :

// add a copy
void array_append(struct Array * array, void *thing)
{
    array->data[array->size++] = array->dtd->clone(thing);
}

void array_print(struct Array *array )
{
    printf("[");
    char * separator = "";
    for (size_t i = 0; i < array->size; i++) {
        printf("%s", separator);
        separator = ",";
        array->dtd->print(array->data[i]);
    }
    printf("]");
}

void array_sort(struct Array *array)
{
    // selection
    for (size_t i = 0; i < array->size; i++) {
        int m = i;  // index of minimum
        for (size_t j = i+1; j < array->size; j++) {
            if (array->dtd->compare(array->data[j], array->data[m]) < 0) {
                m = j;
            }
        }
        void *tmp = array->data[m];
        array->data[m] = array->data[i];
        array->data[i] = tmp;
    }
}

Bref, pour un main qui initialise un tableau, y fourre quelques valeurs, les fait afficher avant et après le tri :

int main(int argc, char *argv[])
{
    struct DTD int_dtd = {
        .clone = int_clone,
        .print = int_print,
		.compare = int_compare
    };

    struct Array a = {
        .dtd = & int_dtd,
        .size = 0
    };

    array_append(&a, int_constant(26));
    array_append(&a, int_constant(14));
    array_append(&a, int_constant(3));
    array_append(&a, int_constant(16));
    array_append(&a, int_constant(35));


    printf("Avant = ");
    array_print(&a);
    printf("\n");

    array_sort(&a);
    printf("Après = ");
    array_print(&a);
    printf("\n");

    return EXIT_SUCCESS;
}

La fonction int_constant fournit un pointeur (éphémère) vers un entier

void* int_constant(int n)   // Hack - not reentrant
{
    static int number;
    number = n;
    return &number;
}


Résultat de l'exécution

Avant = [26,14,3,16,35]
Après = [3,14,16,26,35]

PS: une autre histoire serait de stocker toutes les données du tableau dans une zone (contigue) allouée dynamiquement. Dans ce cas il faut avoir aussi la taille des éléments dans la description du type - en supposant que ça soit une taille fixe.



-
Edité par michelbillaud 13 février 2022 à 10:23:11

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2022 à 10:13:03

C'est quoi l'intitulé exact de l'exercice ?
  • Partager sur Facebook
  • Partager sur Twitter
...
13 février 2022 à 11:21:00

> PS: une autre histoire serait de stocker toutes les données du tableau dans une zone (contigue) allouée dynamiquement. Dans ce cas il faut avoir aussi la taille des éléments dans la description du type - en supposant que ça soit une taille fixe.

Bon, ça ne change pas énormément de choses

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>

struct DTD { // data type description
    size_t size;
    void (*print)(void *thing);
    int (*compare)(void *first, void *second);
};

struct Array {
    struct DTD *dtd;
    size_t size;       // number of elements
    char data[1024];   // not extensible
};

// address of an element
void * array_address(struct Array* array, int index)
{
    return array->data + index * array->dtd->size;
}

// add a copy of data
void array_append(struct Array * array, void *thing)
{
    memcpy(array_address(array, array->size ++),
           thing,
           array->dtd->size);
}

void array_print(struct Array *array )
{
    printf("[");
    char * separator = "";
    for (size_t i = 0; i < array->size; i++) {
        printf("%s", separator);
        separator = ",";
        array->dtd->print(array_address(array, i));
    }
    printf("]");
}

void array_sort(struct Array *array)
{
    // selection
    for (size_t i = 0; i < array->size; i++) {
        int m = i;  // index of minimum
        for (size_t j = i+1; j < array->size; j++) {
            if (array->dtd->compare(array_address(array, j),
                                    array_address(array, m))
                    < 0) {
                m = j;
            }
        }
        void *a = array_address(array, m);
        void *b = array_address(array, i);

        char tmp[array->dtd->size];
        memcpy(tmp, a, array->dtd->size);
        memcpy(a, b, array->dtd->size);
        memcpy(b, tmp, array->dtd->size);
    }
}

// -- for ints

void int_print(void *thing)
{
    int *t = thing;
    printf("%d", *t);
}

int int_compare(void * first, void *second)
{
    int *f = first, *s = second;
    return *f - *s;
}

void* int_constant(int n)   // Hack - not reentrant
{
    static int number;
    number = n;
    return &number;
}

int main(int argc, char *argv[])
{
    struct DTD int_dtd = {
        .size = sizeof(int),           // NEW
        .print = int_print,
        .compare = int_compare
    };

    struct Array a = {
        .dtd = & int_dtd,
        .size = 0
    };

    array_append(&a, int_constant(26));
    array_append(&a, int_constant(14));
    array_append(&a, int_constant(3));
    array_append(&a, int_constant(16));
    array_append(&a, int_constant(35));


    printf("Avant = ");
    array_print(&a);
    printf("\n");

    array_sort(&a);
    printf("Après = ");
    array_print(&a);
    printf("\n");

    return EXIT_SUCCESS;
}

PS:

  • on utilise des adresses de char (octets) parce qu'on peut faire de l'arithmétique dessus. Et qu'on en a besoin.
  • il y a peut être des emmerdements à prévoir avec l'alignement des données.



-
Edité par michelbillaud 13 février 2022 à 11:23:16

  • Partager sur Facebook
  • Partager sur Twitter
13 février 2022 à 22:13:38

Merci beaucoup pour vos réponse. Je vais essayer d'implémenter sa. En ce qui concerne la consigne, il s'agit d'un TP assez long avec plusieurs consigne. ou il faut ajouter des valeur dans un tableau et les afficher en passant uniquement par des void*
  • Partager sur Facebook
  • Partager sur Twitter
13 février 2022 à 22:27:37

Afficher une variable void  (éventuellement *) avec printf() c'est impossible, à moins de caster le void (éventuellement *). printf() a besoin de savoir quel type de variable il (elle ?) doit afficher.

-
Edité par edgarjacobs 13 février 2022 à 22:28:36

  • Partager sur Facebook
  • Partager sur Twitter

On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

14 février 2022 à 2:20:15

Je te suggère de considérer la suggestion de michelbillaud où tu places la fonction d'affichage appropriée dans ta structure.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.