Menu
Coddy logo textTech

제네릭 스왑

Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 51번째.

프로그래밍에서 흔한 작업 중 하나는 두 값을 서로 바꾸는 것입니다. 보통은 각 타입마다 별도의 swap 함수를 작성해야 합니다 — int를 위한 것, double을 위한 것 등과 같이 말이죠. 하지만 void*memcpy를 사용하면, 어떤 두 변수든 바꿀 수 있는 단일 함수를 작성할 수 있습니다.

핵심적인 통찰은 스와핑(swapping)이 단지 바이트를 이동시키는 것이라는 점입니다. 데이터의 크기를 알고 있다면, 실제 타입을 모르더라도 바이트를 복사할 수 있습니다. 함수 시그니처는 다음과 같습니다:

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

size 매개변수는 함수에게 이동할 바이트 수를 알려줍니다. 내부적으로는 임시 버퍼를 사용하고 <string.h>memcpy를 사용하여 바이트를 섞습니다:

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

이제 이 단일 함수는 모든 타입에 대해 작동합니다:

int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// 이제 x는 10, y는 5입니다
double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p는 이제 2.71, q는 이제 3.14입니다

이 패턴 — void*size_t를 사용하는 것 — 은 C 표준 라이브러리가 qsortbsearch와 같은 제네릭 함수를 구현하는 방식입니다.

challenge icon

챌린지

쉬움

void* 포인터와 memcpy의 강력한 기능을 사용하여 데이터 타입에 관계없이 두 변수의 값을 교환할 수 있는 제네릭 swap 유틸리티를 만들어 보겠습니다.

코드는 세 개의 파일로 구성됩니다:

  • swap.h: 두 개의 void* 포인터와 교환할 데이터의 크기를 나타내는 size_t 매개변수를 받는 generic_swap 함수를 선언하세요. 인클루드 가드(include guards)를 잊지 마세요!
  • swap.c: generic_swap 함수를 구현하세요. 임시 버퍼와 memcpy를 사용하여 두 메모리 위치 간에 바이트를 이동합니다. 3단계 스왑 패턴을 기억하세요: 첫 번째 값을 임시 버퍼에 복사, 두 번째 값을 첫 번째 위치에 복사, 임시 버퍼의 값을 두 번째 위치에 복사.
  • main.c: 다양한 데이터 타입에서 작동하는 제네릭 swap을 시연하세요. 타입 표시자(정수의 경우 i, 실수의 경우 d)와 두 개의 값을 읽습니다. 적절한 타입의 변수 두 개를 생성하고, generic_swap 함수를 사용하여 값을 교환한 다음, 교환된 두 값을 출력합니다.

프로그램은 세 개의 입력을 받습니다:

  1. 타입 표시자: 정수의 경우 i 또는 실수의 경우 d
  2. 첫 번째 값
  3. 두 번째 값

교환 후, 두 값을 각각 별도의 줄에 출력하세요. 실수의 경우 소수점 둘째 자리까지 출력합니다.

입력이 i, 5, 10일 때의 출력 예시:

10
5

입력이 d, 3.14, 2.71일 때의 출력 예시:

2.71
3.14

입력이 i, -7, 42일 때의 출력 예시:

42
-7

입력이 d, 99.99, 0.01일 때의 출력 예시:

0.01
99.99

이 방식의 장점은 generic_swap 함수가 어떤 타입을 교환하는지 알 필요 없이 단순히 바이트를 이동시킨다는 점입니다. 동일한 함수가 정수, 실수, 구조체 또는 기타 모든 데이터 타입에 대해 작동합니다. memcpy를 위해 <string.h>를, size_t를 위해 <stddef.h> 또는 <stdlib.h>를 포함해야 합니다.

치트 시트

제네릭 swap 함수는 실제 타입을 알지 못해도 바이트를 이동시켜 모든 타입의 값을 교환하기 위해 void* 포인터와 memcpy를 사용합니다.

함수 시그니처:

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

임시 버퍼와 memcpy를 사용한 구현:

void generic_swap(void* a, void* b, size_t size) {
    char temp[size];      // 임시 버퍼
    memcpy(temp, a, size);  // temp = a
    memcpy(a, b, size);     // a = b
    memcpy(b, temp, size);  // b = temp
}

다양한 타입에서의 사용 예시:

int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x는 이제 10, y는 이제 5입니다

double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p는 이제 2.71, q는 이제 3.14입니다

필요한 헤더: memcpy를 위한 <string.h>size_t를 위한 <stddef.h> 또는 <stdlib.h>.

직접 해보기

#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: a와 b를 교환하기 위해 generic_swap을 호출하세요
        // 힌트: &a, &b, 그리고 sizeof(int)를 사용하세요
        
        printf("%d\n", a);
        printf("%d\n", b);
    } else if (type == 'd') {
        double a, b;
        scanf("%lf", &a);
        scanf("%lf", &b);
        
        // TODO: a와 b를 교환하기 위해 generic_swap을 호출하세요
        // 힌트: &a, &b, 그리고 sizeof(double)를 사용하세요
        
        printf("%.2f\n", a);
        printf("%.2f\n", b);
    }
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨