Menu
Coddy logo textTech

Generyczna zamiana

Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 51 z 61.

Jedną z częstych operacji w programowaniu jest zamiana miejscami dwóch wartości. Zwykle trzeba napisać osobną funkcję zamiany dla każdego typu: jedną dla int, kolejną dla double i tak dalej. Jednak dzięki void* i memcpy możemy napisać jedną funkcję, która zamieni miejscami dowolne dwie zmienne.

Kluczowy wniosek jest taki, że zamiana to po prostu przenoszenie bajtów. Jeśli znasz rozmiar danych, możesz kopiować bajty bez znajomości ich rzeczywistego typu. Sygnatura funkcji wygląda tak:

void generic_swap(void* a, void* b, size_t size);

Parametr size informuje funkcję, ile bajtów przenieść. Wewnątrz używamy bufora tymczasowego i funkcji memcpy z <string.h>, aby zamienić bajty miejscami:

void generic_swap(void* a, void* b, size_t size) {
    char temp[size];      // bufor tymczasowy
    memcpy(temp, a, size);  // temp = a
    memcpy(a, b, size);     // a = b
    memcpy(b, temp, size);  // b = temp
}

Teraz ta pojedyncza funkcja działa dla każdego typu:

int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x ma teraz wartość 10, y ma teraz wartość 5
double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p ma teraz wartość 2.71, q ma teraz wartość 3.14

Ten wzorzec, wykorzystujący void* wraz z size_t, jest sposobem, w jaki biblioteka standardowa języka C implementuje funkcje generyczne, takie jak qsort i bsearch.

challenge icon

Wyzwanie

Łatwy

Stwórzmy uniwersalną funkcję pomocniczą do zamiany wartości dowolnych dwóch zmiennych, niezależnie od ich typu, wykorzystując możliwości wskaźników void* i funkcji memcpy.

Rozmieścisz swój kod w trzech plikach:

  • swap.h: Zadeklaruj funkcję generic_swap, która przyjmuje dwa wskaźniki void* oraz parametr size_t określający rozmiar zamienianych danych. Nie zapomnij o strażnikach nagłówka!
  • swap.c: Zaimplementuj funkcję generic_swap. Użyj tymczasowego bufora i funkcji memcpy, aby przenosić bajty między dwoma obszarami pamięci. Pamiętaj o trzyetapowym schemacie zamiany: skopiuj pierwszą wartość do zmiennej tymczasowej, drugą do pierwszej, a zmienną tymczasową do drugiej.
  • main.c: Pokaż działanie uniwersalnej funkcji zamiany dla różnych typów danych. Odczytaj oznaczenie typu (i dla liczb całkowitych, d dla liczb typu double), a następnie dwie wartości. Utwórz dwie zmienne odpowiedniego typu, zamień je za pomocą funkcji generic_swap, a następnie wyświetl obie wartości po zamianie.

Twój program otrzyma trzy dane wejściowe:

  1. Oznaczenie typu: i dla liczby całkowitej lub d dla liczby typu double
  2. Pierwsza wartość
  3. Druga wartość

Po zamianie wyświetl obie wartości w osobnych wierszach. W przypadku liczb typu double użyj 2 miejsc po przecinku.

Przykładowe wyjście dla danych wejściowych i, 5 i 10:

10
5

Przykładowe wyjście dla danych wejściowych d, 3.14 i 2.71:

2.71
3.14

Przykładowe wyjście dla danych wejściowych i, -7 i 42:

42
-7

Przykładowe wyjście dla danych wejściowych d, 99.99 i 0.01:

0.01
99.99

Zaletą tego podejścia jest to, że funkcja generic_swap nie wie, jakie typy zamienia. Po prostu przenosi bajty. Ta sama funkcja działa dla liczb całkowitych, wartości typu double, struktur i dowolnych innych typów danych. Musisz dołączyć <string.h>, aby użyć funkcji memcpy, oraz <stddef.h> lub <stdlib.h>, aby użyć typu size_t.

Spróbuj swoich sił

#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: Wywołaj generic_swap, aby zamienić wartości a i b
        // Wskazówka: Użyj &a, &b oraz sizeof(int)
        
        printf("%d\n", a);
        printf("%d\n", b);
    } else if (type == 'd') {
        double a, b;
        scanf("%lf", &a);
        scanf("%lf", &b);
        
        // TODO: Wywołaj generic_swap, aby zamienić wartości a i b
        // Wskazówka: Użyj &a, &b oraz sizeof(double)
        
        printf("%.2f\n", a);
        printf("%.2f\n", b);
    }
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C online