Scambio generico
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 51 di 61.
Un'operazione comune nella programmazione consiste nello scambiare due valori. Normalmente, scriveresti una funzione di scambio separata per ogni tipo: una per int, un'altra per double e così via. Ma con void* e memcpy, possiamo scrivere un'unica funzione che scambia due variabili qualsiasi.
L’intuizione chiave è che scambiare significa semplicemente spostare byte. Se conosci la dimensione dei dati, puoi copiare i byte senza conoscere il tipo effettivo. La firma della funzione è questa:
void generic_swap(void* a, void* b, size_t size);Il parametro size indica alla funzione quanti byte spostare. All'interno, usiamo un buffer temporaneo e memcpy da <string.h> per scambiare i byte:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // buffer temporaneo
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}Ora questa singola funzione funziona con qualsiasi tipo:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x ora è 10, y ora è 5double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p ora vale 2.71, q ora vale 3.14Questo schema, che usa void* con size_t, è il modo in cui la libreria standard di C implementa funzioni generiche come qsort e bsearch.
Sfida
FacileCostruiamo un'utilità generica di scambio che possa scambiare i valori di due variabili qualsiasi, indipendentemente dal loro tipo: sfruttando la potenza dei puntatori void* e di memcpy.
Organizzerai il codice in tre file:
swap.h: dichiara la funzionegeneric_swap, che accetta due puntatorivoid*e un parametrosize_tche indica la dimensione dei dati da scambiare. Non dimenticare le include guard!swap.c: implementa la funzionegeneric_swap. Usa un buffer temporaneo ememcpyper spostare i byte tra le due posizioni di memoria. Ricorda lo schema di scambio in tre passaggi: copia il primo valore in temp, copia il secondo nel primo, copia temp nel secondo.main.c: mostra il funzionamento del tuo scambio generico con diversi tipi di dati. Leggi un indicatore di tipo (iper gli interi,dper i double) seguito da due valori. Crea due variabili del tipo appropriato, scambiale usando la funzionegeneric_swap, poi stampa entrambi i valori dopo lo scambio.
Il programma riceverà tre input:
- Un indicatore di tipo:
iper un intero odper un double - Il primo valore
- Il secondo valore
Dopo lo scambio, stampa i due valori su righe separate. Per i double, usa 2 cifre decimali.
Esempio di output quando gli input sono i, 5 e 10:
10
5Esempio di output quando gli input sono d, 3.14 e 2.71:
2.71
3.14Esempio di output quando gli input sono i, -7 e 42:
42
-7Esempio di output quando gli input sono d, 99.99 e 0.01:
0.01
99.99Il bello di questo approccio è che la funzione generic_swap non sa quali tipi sta scambiando. Sposta soltanto byte. La stessa funzione funziona per interi, double, strutture o qualsiasi altro tipo di dato. Dovrai includere <string.h> per memcpy e <stddef.h> o <stdlib.h> per size_t.
Provalo tu
#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: Llama a generic_swap para intercambiar a y b
// Pista: Usa &a, &b y sizeof(int)
printf("%d\n", a);
printf("%d\n", b);
} else if (type == 'd') {
double a, b;
scanf("%lf", &a);
scanf("%lf", &b);
// TODO: Llama a generic_swap para intercambiar a y b
// Pista: Usa &a, &b y sizeof(double)
printf("%.2f\n", a);
printf("%.2f\n", b);
}
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta7Puntatori a funzione
Dichiarare puntatori a funzioneChiamare i puntatori a funzioneTypedef per puntatori a funzionePassare funzioni come argomentiRiepilogo: dispatch della calcolatrice10Contenitori generici
Riepilogo dei puntatori voidWrapper genericoScambio genericoConfronto genericoRiepilogo: array generico2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online