Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 27/08/2019, à 10:19

DonutMan75

[RESOLU] Langage C : utilisation de lfind()

Bonjour à tous,
dans le chapitre 17 de Développement système sous linux est introduite la fonction lfind() permettant de chercher une entrée dans un tableau de N éléments à l'aide d'une fonction de comparaison personnalisée.

J'ai essayé de l'intégrer dans le cadre d'un (très sommaire) outil de gestion de personnel mais il y a un soucis avec mes pointeurs...
Avez-vous une idée de ce qui cloche ??

Points de compréhension :
- les membres du personnel sont définis par une structure personne qui contient un nom et un âge
- les pointeurs vers chaque membre du personnel sont stockés dans un tableau de 10 éléments nommé "personnel"
- la fonction creer_personne prend en argument un nom et un âge et va créer une structure dynamique. L'adresse de cette structure sera stockée dans le premier emplacement disponible du tableau "personnel"
- la fonction compare_identite sert de comparateur : si les noms et l'âge correspondent ALORS c'est la même personne (je l'ai testée avec succès sur quelques cas)
- par soucis de lisibilité, je n'ai pas fait figurer les vérifications de cas limites (notamment si il y a plus de 10 membres)

Le prototype de la fonction lfind est le suivant :

man lfind a écrit :

void *lfind(const void *key, const void *base, size_t *nmemb,
                size_t size, int(*compar)(const void *, const void *));

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

#define	TAILLE	10

// Ce programme simule un gestionnaire de personnel...
typedef struct personne personne;
struct personne
{
	char* nom;
	int age;
};

size_t nb_personne = 0;

personne * personnel[TAILLE] = {NULL};

void print_personne(personne p, int rang)
{
fprintf(stdout, "PERSONNE %03d\n  - Nom : %s\n  - Age : %d\n", rang, p.nom, p.age);
}

void print_personnel(personne *personnel[])
{
int k=0;
while (!(personnel[k]==NULL))
	{
	fprintf(stdout, "[%p]\n", personnel[k]);
	print_personne(*(personnel[k]), k+1);
	k++;
	}
}

void creer_personne(char *nom, int age, personne *personnel[])
{

personne *newp = malloc(sizeof(personne));
newp->nom = strdup(nom);
newp->age = age;
personnel[nb_personne] = newp;
nb_personne++;
}



int compare_identite(const void *p1, const void *p2)
{
personne *pers1 = (personne*) p1;
personne *pers2 = (personne*) p2;

int s = strcasecmp(pers1->nom, pers2->nom);

if (s==0)// meme nom
{
	fprintf(stdout, "DEBUG : same name !\n");
	return pers2->age-pers1->age;
}
else
{
	fprintf(stdout, "DEBUG :[%p, %p] -> strcasecmp(%s, %s) = %d --> NOT same name !\n", p1, p2, pers1->nom, pers2->nom, s);
	return s;
}

}

void main()
{

	creer_personne("Richard", 15, personnel);
	creer_personne("Thomas", 27, personnel);
	creer_personne("Jacques", 42, personnel);
	creer_personne("Emmanuelle", 45, personnel);
	creer_personne("Aude", 43, personnel);
	print_personnel(personnel);

	fprintf(stdout, "\n-----------------------------\n");
	// Cherchons Emmanuelle ?
	personne *manue = malloc(sizeof(personne));
	manue->nom = strdup("Emmanuelle");
	manue->age = 45;
	print_personne(*manue, 1);

	personne *retour = (personne *) lfind((void *) manue, (void *) personnel, &nb_personne, sizeof(personne*), compare_identite);
	if (retour==NULL)
	{fprintf(stdout, "Manue n'a pas ete trouvee...\n");}
	else
	{print_personne(*retour, 1);}

	for (int k=0; k<5; k++)                                                                                                                       
		printf(stdout, "-> COMPARAISON MANUELLE MANUE/%s : %d\n", personnel[k]->nom, compare_identite(manue, personnel[k])); 
}

Voici ce que j'obtiens à l’exécution :

$ ./biblio 
[0x55cdafa07010]
PERSONNE 001
  - Nom : Richard
  - Age : 15
[0x55cdafa07050]
PERSONNE 002
  - Nom : Thomas
  - Age : 27
[0x55cdafa07090]
PERSONNE 003
  - Nom : Jacques
  - Age : 42
[0x55cdafa070d0]
PERSONNE 004
  - Nom : Emmanuelle
  - Age : 45
[0x55cdafa07110]
PERSONNE 005
  - Nom : Aude
  - Age : 43

-----------------------------
PERSONNE 001
  - Nom : Emmanuelle
  - Age : 45
DEBUG :[0x55cdafa07560, 0x55cdadbd90a0] -> strcasecmp(Emmanuelle, 0pU) = 53 --> NOT same name !
DEBUG :[0x55cdafa07560, 0x55cdadbd90a8] -> strcasecmp(Emmanuelle, ppU) = -11 --> NOT same name !
DEBUG :[0x55cdafa07560, 0x55cdadbd90b0] -> strcasecmp(Emmanuelle, pU) = -75 --> NOT same name !
DEBUG :[0x55cdafa07560, 0x55cdadbd90b8] -> strcasecmp(Emmanuelle, pU) = -139 --> NOT same name !
DEBUG :[0x55cdafa07560, 0x55cdadbd90c0] -> strcasecmp(Emmanuelle, 0qU) = 53 --> NOT same name !
Manue n'a pas ete trouvee...
DEBUG :[0x56414d3b1560, 0x56414d3b1010] -> strcasecmp(Emmanuelle, Richard) = -13 --> NOT same name !
-> COMPARAISON MANUELLE MANUE/Richard : -13
DEBUG :[0x56414d3b1560, 0x56414d3b1050] -> strcasecmp(Emmanuelle, Thomas) = -15 --> NOT same name !
-> COMPARAISON MANUELLE MANUE/Thomas : -15
DEBUG :[0x56414d3b1560, 0x56414d3b1090] -> strcasecmp(Emmanuelle, Jacques) = -5 --> NOT same name !
-> COMPARAISON MANUELLE MANUE/Jacques : -5
DEBUG : same name !
-> COMPARAISON MANUELLE MANUE/Emmanuelle : 0
DEBUG :[0x56414d3b1560, 0x56414d3b1110] -> strcasecmp(Emmanuelle, Aude) = 4 --> NOT same name !
-> COMPARAISON MANUELLE MANUE/Aude : 4

Merci d'avance pour vos idées, je sèche un peu... hmm

Donut.

Dernière modification par DonutMan75 (Le 27/08/2019, à 12:57)

Hors ligne

#2 Le 27/08/2019, à 10:53

DonutMan75

Re : [RESOLU] Langage C : utilisation de lfind()

Re-bonjour,
je me réponds à moi-même après quelques tests...
Comme quoi, le fait d'écrire son problème permet souvent de le résoudre...

La variable personnel contient des pointeurs vers des structures personne et non pas des pointeurs vers ces structures elles-mêmes !

Ainsi :
personnel = [a0, a1, a2, etc...]
ak = adresse de la structure de la keme personne

Les ak n'ont AUCUNE RAISON d'être consécutif...

Dans l'appel :

personne *retour = (personne *) lfind((void *) manue, (void *) personnel, &nb_personne, sizeof(personne*), compare_identite);

(void *) manue est un pointeur (casté en pointeur générique) vers la structure personne manue
MAIS
(void *) personnel est un pointeur (casté en pointeur générique) vers le premier élément du tableau personnel... qui contient des pointeurs vers des structures.

Bref on compare des choses qui ne sont pas comparables... et on ne pouvait pas s'en apercevoir puisque tout était casté en void*....

Deux solutions possibles :
- soit ne choisir de ne travailler qu'avec des pointeurs sur pointeurs sur structutre (auquel cas, on appelle lfind avec &manue et on modifie la fonction de comparaison)
- soit travailler directement avec des tableaux de structure plutôt que des tableaux de pointeurs vers structure...

Hors ligne