[C] LE TRI, L'ÉCHANGE ET LES POINTEURS

cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007 - 22 mai 2004 à 18:22
cs_Morgan2 Messages postés 1 Date d'inscription dimanche 1 juillet 2012 Statut Membre Dernière intervention 14 juillet 2012 - 14 juil. 2012 à 19:39
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/23062-c-le-tri-l-echange-et-les-pointeurs

cs_Morgan2 Messages postés 1 Date d'inscription dimanche 1 juillet 2012 Statut Membre Dernière intervention 14 juillet 2012
14 juil. 2012 à 19:39
Aide svp!
une fonction sommet qui retourne le sommet de la pile passée en paramètre
StanOfSky Messages postés 43 Date d'inscription mardi 30 mars 2004 Statut Membre Dernière intervention 7 octobre 2006
4 juin 2004 à 00:08
djl >> " int char_superieur_ou_egal(char *a, char *b)
{
return (strcmp(a, b) >= 0);
} // mais ou est l'interet ? "

l'interet est tout simplement de faire une fonction pour classer des chaines de caracteres dans l'odre alphabétique, mais c'est juste un exemple. apres c vrai que tu peux refaire ta fonction de comparaison de chaine de caracteres mais autant utiliser ce qui existe et fonctionne... (je precise que si tu veux classer des mots dans l'ordre alphabétique il faut aupravant mettre les lettres de chaque mot au meme format cad: soit majuscule soit minuscule)
bool n'est pas ansi c vrai, mais tu peux faire typedef char bool .... mais bon la plus part des compilateurs le reconnaissent ainsi...
c juste que niveau comprehension (et pas compression faute de frappe) c qd meme préférable (a noter que toute librairie , api etc qui se respecte defini un type booléen)

et j'avais ecrit :

int char_superieur_ou_egal(void *a, void *b)
{
return (strcmp((char*)a, (char*)b) >= 0);
}

parce que son compilateur provoque une erreur de cast si c pas de format int(*)(void*,void*)

dri >> "return (strcmp(a, b) >= 0
Il me semble que faire ca n'est justement pas bon. Je vérifirai mais il me semble qu'en le faisant on ne donne pas l'adresse des chaines à comparer mais l'adresse de leurs poibteurs respectifs... C'est pour ca que je voulais passer cette adresse à d'autres variables et que je suis passé par des memcpy, ne sachant faire autrement
"
et ben justement ca c bon puisque qu'une chaine de caractere c un tableau de taille FIXE dont le pointeur sur le premier caractere est le nom de ta variable sachant que ta chaine de caractere se finit des l'apparition du premier caractere nul '\0'
tu peux refaire ta fonction de comparaison si tu le veux mais strcmp te permet de savoir facilement(et de facon portable et optimisée) si les chaines sont identiques, inferieures ou supérieures...
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
30 mai 2004 à 11:17
Nan justement, je l'ai peut être mal expliqué, quand le compilo me balance cette erreur, c'est qu'il y en a une autre ailleurs (c'est ce que j'ai constaté) et du coup je réglai le problème de cette maniere alors qu'avant il l'acceptait... Et là bah ca génere aucune erreur... Parce qu'il n'y en a pas ailleurs.

Dri
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
29 mai 2004 à 17:58
et si tu fais

temp = malloc(size);

il te balance une erreur?
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
29 mai 2004 à 17:41
Bah je l'ai dit je le fais en C... Donc forcément j'ai fait gaffe à l'enregistrer en C

Dri
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
28 mai 2004 à 22:34
devc++ donc la collection gcc, tu compile un .cpp ou un .c ?
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
28 mai 2004 à 22:28
J'utilise DevC++ donc mingw
Quand j'utilise cette fonction le tri est faussé

Dri
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
28 mai 2004 à 19:41
"return (strcmp(a, b) >= 0
Il me semble que faire ca n'est justement pas bon. Je vérifirai mais il me semble qu'en le faisant on ne donne pas l'adresse des chaines à comparer mais l'adresse de leurs poibteurs respectifs... C'est pour ca que je voulais passer cette adresse à d'autres variables et que je suis passé par des memcpy, ne sachant faire autrement"

tu fais bien d'avoir dit le fond de tes pensée car c'est ce qui explique ce que tu avait ecris precedement
aparament tu n'a pas trop compris c'est histoire de pointeurs et de chaine de caracteres, je t'invite a voir ca dans un livre (k&r) ou un bon cour online
http://cowww.epfl.ch/infgmel/doc/coursCpp/book1.html

int char_superieur_ou_egal(char *a, char *b)
{
return (strcmp(a, b) >= 0);
} //

mis a part que ca n'a aucun interet, c'est tout ce qu'il y a de plus juste

et tu compile avec quoi pour avoir une erreur sur un mallloc sans cast ? car la on parle bien de C ?
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
28 mai 2004 à 08:54
Dsl mais cette fois je l'ai codée à la volée au bureau... Et j'ai pas pris le temps de "bien" faire les choses... Et je l'ai dit... Je maitrise pas tout ca... C'est même le but de maitriser en m'exercant... Sinon désolé de donner l'impression de faire parler dans le vide...
Pour le temp, en fait je l'avais fait comme ca des le début et je ne l'ai jamais corrigé... Donc tant que je ne la voyais pas je pouvais pas la corriger...

Aussi je répete que quand je cast un malloc c'est que j'ai un message d'erreur dessus et que souvent l'erreur est aiilleurs mais que le compilo me sort celle là...

return (strcmp(a, b) >= 0
Il me semble que faire ca n'est justement pas bon. Je vérifirai mais il me semble qu'en le faisant on ne donne pas l'adresse des chaines à comparer mais l'adresse de leurs poibteurs respectifs... C'est pour ca que je voulais passer cette adresse à d'autres variables et que je suis passé par des memcpy, ne sachant faire autrement

En tout cas merci de vos remarques

Dri
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
27 mai 2004 à 22:13
ou tous simplement

int char_superieur_ou_egal(char *a, char *b)
{
return (strcmp(a, b) >= 0);
} // mais ou est l'interet ?

et pas la peine de faire un cast void* -> char*

malheuresement ya pas de type bool en c ansi
StanOfSky Messages postés 43 Date d'inscription mardi 30 mars 2004 Statut Membre Dernière intervention 7 octobre 2006
27 mai 2004 à 22:06
si tu veux faire une fonctions qui compares des chaines de caracteres suffit de faire ca :
int char_superieur_ou_egal(void *a, void *b)
{
return (strcmp((char*)a, (char*)b) >= 0);
}

ca sert a rien de recopier avant de faire le test....

j'avais bien compris que ta fonction de tri se voulait générique
d'ailleurs c pourquoi faut faire une fonction de comparaison que tu passes en parametre dans ta fonction de tri pour chaque type a trier : int (*compare)(void*, void*) qui perso j'aurai faire renvoyer un bool (meme si c pareil mais je prefere pour la compression)

mais c vrai que j'avais po fait gaffe a comment tu l'utilises dans ta fonction sort et c vrai qu'il faut que ce soit du int(*)(void*,void*) en parametre
c pour quoi vive les classes et les templates!!! ;)

sinon a part ca d'un point de vue algorithmique ta fonction sort n'est pas tres efficace puisqu'elle te fait faire n² comparaisons et dans le pire des cas n² swap...
mate des fonctions comme le tri fusion ou tri rapide qui sont des fonctions récursives faciles a comprendre et tres efficaces
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
27 mai 2004 à 19:55
mais pourquoi tu cast le malloc ??
temp = (void*) malloc(size);
je parle dans le vide ?

mais surtout, tu pourrais m'expliquer ca ?

int string_inferieur_ou_egal(void *a, void *b)
{
char *c, *d;
memcpy(&c, a, sizeof(char*));
memcpy(&d, b, sizeof(char*));
return (strcmp(c, d)<=0);
}

int string_superieur_ou_egal(void *a, void *b)
{
char *c, *d;
memcpy(&c, a, sizeof(char*));
memcpy(&d, b, sizeof(char*));
return (strcmp(c, d)>=0);
}

vois pas l'utilité et en plus c'est faut
tu aurais peu faire

c=a;
d=b;

au lieu de

memcpy(&c, a, sizeof(char*));
memcpy(&d, b, sizeof(char*)); // surtout que l'utilisation de memcpy est incorrecte et inutile ???
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
27 mai 2004 à 15:39
Voila un exemple de tri de chaine de caractere... Je répete bien le but de la fonction... C'est de pas etre un simple sort... Mais bien de trier un peu n'importe quoi... Ca s'adresse en particulier aux types qui ne sont pas ceux de base mais pour l'exemple c'est eux que j'ai pris. BruNews l'a bien souligné ^^).
Je maitrise pas trop le C... Mais par exemple si on travaille avec un type comme :
structure
chaine nom
chaine prenom
finstructure
et qu'on désire trier un tableau de ces structures... Il faut bien soit se faire sa propre fonction de tri, soit uiliser une fonction qui en serait capable... C'est pour ca que j'ai codé cette fonction... Par exemple là on pourrai d'abord trier par nom, puis en cas de nom identique par prénom... Si ca intéresse je peux aussi coder un exemple d'utilisation avec cette structure...

Voila l'exemple pour les chaines :

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

void sort(void*, size_t, size_t, int (*)(void*, void*));

int string_inferieur_ou_egal(void *a, void *b)
{
char *c, *d;
memcpy(&c, a, sizeof(char*));
memcpy(&d, b, sizeof(char*));
return (strcmp(c, d)<=0);
}

int string_superieur_ou_egal(void *a, void *b)
{
char *c, *d;
memcpy(&c, a, sizeof(char*));
memcpy(&d, b, sizeof(char*));
return (strcmp(c, d)>=0);
}

void sort(void *buffer, size_t size, size_t count, int (*compare)(void*, void*))
{
size_t left, right, i;
void *temp;

temp = (void*) malloc(size);

for(right=0; right<count; right++)
{
memcpy(temp, buffer+size*right, size);
for(left=0; left<right; left++)
if(compare(buffer+size*right, buffer+size*left)==1) break;
if(left<right)
{
for(i=right; i>left; i--)
memcpy(buffer+size*i, buffer+size*(i-1), size);
memcpy(buffer+size*left, temp, size);
}
}

free(temp);

}

#define TAB_COUNT 5


main()
{
char *str[TAB_COUNT] = {
"chaine",
"caractere",
"mot",
"phrase",
"comparaison"
};
int i, (*compare)(void*, void*);;

for(i=0; i<TAB_COUNT; i++)
printf("%s\n", str[i]);

printf("\n");
//on trie dans un ordre
sort(str, sizeof(char*), TAB_COUNT, &string_superieur_ou_egal);
for(i=0; i<TAB_COUNT; i++)
printf("%s\n", str[i]);

printf("\n");
//puis dans l'autre
sort(str, sizeof(char*), TAB_COUNT, &string_inferieur_ou_egal);
for(i=0; i<TAB_COUNT; i++)
printf("%s\n", str[i]);

getch();
}

Dri
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
27 mai 2004 à 14:45
qsort de la CRT travaille de maniere identique. Les params void* permettent de trier de tout apres le cast.
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
27 mai 2004 à 14:36
void sort(void *buffer, size_t size, size_t count, int (*compare)(void*, void*))

La fonction trie une zone continue de mémoire de n'importe quel type
Le type à une taille
On trie un tableau de count éléments
On les trie selon une fonction de comparaison qui accepte donc forcément n'importe quel type.

J'ai voulu faire une simple fonction
int char_superieur_ou_egal(char*, char*);
mais le seul problème c'est qu'à la compilation c'était refusé...

Donc la fonction doit accepter un type void et pas char. Regarde l'exemple de swap sur la structure bidon que j'ai mis dans un de mes commentaires... Elle fonctionne aussi bien sur du char que sur la structure bidon... Bah pareil avec ma fonction de tri... Elle est suppossée pouvoir trier ce qu'on lui donne et pas spécialement du char... Donc les fonctions utilisées pour la comparaison doivent s'harmoniser avec... Et utiliser du void... Enfin c'est le problème que j'ai rencontré...

Dri
StanOfSky Messages postés 43 Date d'inscription mardi 30 mars 2004 Statut Membre Dernière intervention 7 octobre 2006
26 mai 2004 à 23:24
en fait moi je vois pas trop pk tu fais ca :
int char_superieur_ou_egal(void *a, void *b)
{
return *((char*)a)>=*((char*)b);
}

void *a et void*b, pk tu mets pas des char* ??

tes fonctions de comparaisons doivent prendre en parametre des élts du meme type que ce que tu mets dans ton tableau...

si tu veux comparer des chaines de caracteres par exemple tu fais :
int char_superieur_ou_egal(char *a, char *b)
{
return (strcmp(a, b) >= 0);
}
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
23 mai 2004 à 12:26
oui long = 32bits sur une architecture 32bits

JCDjcd > en c, regarde du coté de la promotion de type losr du passage en parametre

char, short > int
unsigned char, unsigned short > unsigned
float > double

Dri > si tu compile avec un compilo c doit pas y avoir d'erreur ni warning
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
23 mai 2004 à 12:18
sur processeur 32 bits, int et long devraient avoir une representation sur 32 bits.
Pour les types plus petits, le compilo devrait egalement toujours PUSHer 4 octets sur la pile pour conserver l'alignement correct des donnees, le format passe a printf lui indique comment les interpreter.
cs_JCDjcd Messages postés 1138 Date d'inscription mardi 10 juin 2003 Statut Membre Dernière intervention 25 janvier 2009 4
23 mai 2004 à 12:06
Heu une petite question pour Dri :
dans ta structure bidon tu as different type; et donc dans le printf tu mets des "%d", cela marhce pour le int (taille 4 octets passes en pile), pour le char, je crois que par convention du C, il est convertie en int et passe a printf, dont jusqu'ici pas de probleme, mais pour l'histoire des short et des long, pk ca marche ?? coup de chance ?
car si un long represente plus de 32 bits, alors le printf va prendre les 7 premiers octets de la pile, qu'il comprendera comme etant un int. C'est comme si je passait un __int64, ca ne devait pas marcher , non??
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
23 mai 2004 à 12:03
Bah j'avais une erreur de cast (Dev-C++) quand je ne le mettai pas... Alors j'ai bien été obligé de faire autrement... En fait mon erreur si situai ailleurs et quand je l'ai corrigée bah j'ai oublié de virer ca...
j'avai mal compris ^^ apparament, je vais modifier la source encore ^^

sinon pour le AFFICHER_LE_TABLEAU, c'est juste pour afficher tout ca dans la console... J'ai pas voulu me casser la tête en faisant un truc super classe alors que c'est pas l'essentiel... Donc je dépend de i mais bon c'est juste l'exemple d'utilisation... ;)

Dri
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
23 mai 2004 à 11:01
POURQUOI tu fais buffer3 = (void*) malloc(size); et pas
buffer3 = malloc(size); ??
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
23 mai 2004 à 10:55
Je vois pas pourquoi tu me parle de types de base... J'en ai utilisé un pour l'exemple mais ma fonction swap marche pour n'importe quel type (enfin j'ai l'impression de me répéter). Donc si j'utilise du char j'échange des char... je vois pas où est le prob... Voila un petit exemple.

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

void swap(void*, void*, size_t);

void swap(void *buffer1, void *buffer2, size_t size)
{
void *buffer3;

buffer3 = (void*) malloc(size);

memcpy(buffer3, buffer1, size);
memcpy(buffer1, buffer2, size);
memcpy(buffer2, buffer3, size);

free(buffer3);
}

typedef struct
{
char ch;
short sh;
int in;
long lo;
}bidon;

main()
{
bidon a={1, 2, 3, 4}, b={5, 6, 7, 8};

printf("a={%d, %d, %d, %d}\n", a.ch, a.sh, a.in, a.lo);
printf("b={%d, %d, %d, %d}\n", b.ch, b.sh, b.in, b.lo);

swap(&a, &b, sizeof(bidon)); printf("\nechange...\n\n\n");

printf("a={%d, %d, %d, %d}\n", a.ch, a.sh, a.in, a.lo);
printf("b={%d, %d, %d, %d}\n", b.ch, b.sh, b.in, b.lo);

getch();
}

Le code que j'ai mis était juste pour illustrer l'utilisation de ces fonctions...

Dri
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
23 mai 2004 à 10:54
en c99 tu peux faire

inline void AFFICHER_LE_TABLEAU()
{
for (int i=0; i<TAB_COUNT; i++)
printf("%d\n", tab[i]);
}
cs_JCDjcd Messages postés 1138 Date d'inscription mardi 10 juin 2003 Statut Membre Dernière intervention 25 janvier 2009 4
23 mai 2004 à 10:46
#define AFFICHER_LE_TABLEAU for (i=0; i<TAB_COUNT; i++) printf("%d\n", tab[i])


Il serait largement preferable de faire une fonction, ce qui serait plus simple, car la tu est dependant du nom de la variable
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
23 mai 2004 à 00:32
dans swap tu cast un void* en void*

buffer3 = (void*) malloc(size); ?? il n'y a pas de cast qui tienne avec les types de bases
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
23 mai 2004 à 00:14
C'est bon j'ai modifié la source...
Merci de la remarque :)

Dri
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
23 mai 2004 à 00:00
Pour répondre à djl, c'est un swap générique, là pour l'exemple j'utilise des char mais c'est supposer être fonctionnel pour n'importe quel type...

Sinon pour les memcpy() inutiles, comme je ne savais pas faire autrement j'ai fais comme ca... Ce serait sympa de me donner un exemple avec cette fonction là.

Dri
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
22 mai 2004 à 20:15
Dans char_superieur_ou_egal tu utilises memcpy, inutile.
Un pointeur se dereference, *((char*) a) irait bon.
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
22 mai 2004 à 19:44
la seul fois ou tu utilise swap c'est pour faire
swap(&tab[0], &tab[1], sizeof(char));
alors que swap(char,char) aurait suffit
cs_Dri Messages postés 30 Date d'inscription lundi 21 avril 2003 Statut Membre Dernière intervention 10 mars 2007
22 mai 2004 à 18:22
Voila, j'espere avoir quelques commentaires sur des erreurs éventuelles etc...

Dri
Rejoignez-nous