Échange générique
Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 51 sur 61.
Une opération courante en programmation consiste à échanger deux valeurs. Normalement, tu écrirais une fonction swap distincte pour chaque type : une pour int, une autre pour double, et ainsi de suite. Mais avec void* et memcpy, nous pouvons écrire une seule fonction qui échange deux variables quelconques.
L’idée essentielle est que l’échange consiste simplement à déplacer des octets. Si vous connaissez la taille des données, vous pouvez copier des octets sans connaître le type réel. La signature de la fonction se présente ainsi :
void generic_swap(void* a, void* b, size_t size);Le paramètre size indique à la fonction combien d’octets déplacer. À l’intérieur, nous utilisons un tampon temporaire et memcpy de <string.h> pour permuter les octets :
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // tampon temporaire
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}Maintenant, cette fonction unique fonctionne pour n’importe quel type :
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x est maintenant 10, y est maintenant 5double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p est maintenant 2.71, q est maintenant 3.14Ce modèle, qui utilise void* avec size_t, est la manière dont la bibliothèque standard de C implémente des fonctions génériques comme qsort et bsearch.
Défi
FacileConstruisons un utilitaire générique d’échange capable d’échanger les valeurs de deux variables quelconques, quel que soit leur type : en utilisant la puissance des pointeurs void* et de memcpy.
Vous organiserez votre code sur trois fichiers :
swap.h: déclarez votre fonctiongeneric_swap, qui accepte deux pointeursvoid*et un paramètresize_tindiquant la taille des données à échanger. N’oubliez pas les gardes d’inclusion !swap.c: implémentez la fonctiongeneric_swap. Utilisez un tampon temporaire etmemcpypour déplacer les octets entre les deux emplacements mémoire. Souvenez-vous du modèle d’échange en trois étapes : copier la première valeur dans le tampon temporaire, copier la deuxième dans la première, puis copier le contenu du tampon temporaire dans la deuxième.main.c: démontrez le fonctionnement de votre échange générique avec différents types de données. Lisez un indicateur de type (ipour les entiers,dpour les nombres réels en double précision), suivi de deux valeurs. Créez deux variables du type approprié, échangez-les à l’aide de votre fonctiongeneric_swap, puis affichez les deux valeurs après l’échange.
Votre programme recevra trois entrées :
- Un indicateur de type :
ipour un entier oudpour un nombre réel en double précision - La première valeur
- La deuxième valeur
Après l’échange, affichez les deux valeurs sur des lignes distinctes. Pour les nombres réels en double précision, utilisez 2 décimales.
Exemple de sortie lorsque les entrées sont i, 5 et 10 :
10
5Exemple de sortie lorsque les entrées sont d, 3.14 et 2.71 :
2.71
3.14Exemple de sortie lorsque les entrées sont i, -7 et 42 :
42
-7Exemple de sortie lorsque les entrées sont d, 99.99 et 0.01 :
0.01
99.99La beauté de cette approche réside dans le fait que votre fonction generic_swap ne sait pas quels types elle échange. Elle ne fait que déplacer des octets. La même fonction fonctionne pour les entiers, les nombres réels en double précision, les structures ou tout autre type de données. Vous devrez inclure <string.h> pour memcpy et <stddef.h> ou <stdlib.h> pour size_t.
Essayez vous-même
#include <stdio.h>
#include "swap.h"
int main() {
char type;
scanf("%c", &type);
if (type == 'i') {
int a, b;
scanf("%d", &a);
scanf("%d", &b);
// TODO: Appelez generic_swap pour échanger a et b
// Indice : Utilisez &a, &b et sizeof(int)
printf("%d\n", a);
printf("%d\n", b);
} else if (type == 'd') {
double a, b;
scanf("%lf", &a);
scanf("%lf", &b);
// TODO: Appelez generic_swap pour échanger a et b
// Indice : Utilisez &a, &b et sizeof(double)
printf("%.2f\n", a);
printf("%.2f\n", b);
}
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète7Pointeurs sur fonctions
Déclaration de pointeurs sur fonctionsAppel de pointeurs sur fonctionsTypedef pour les pointeurs sur fonctionsPassage de fonctions en argumentsRécapitulatif : Dispatcher de calculatrice10Conteneurs génériques
Rappel sur les pointeurs voidWrapper génériqueÉchange génériqueComparaison génériqueRappel : tableaux génériques2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercleImplémentation du rectangleUtilisation polymorpheConteneur de formesEntraînez-vous par vous-même : Compilateur C en ligne