포인터 인자와 값 전달 문서의 구현 코드다.

/* 포인터 인자와 값 전달: 값을 넘기는 swap은 못 바꾸고, 주소를 넘기는 swap은 바꾼다.
 *
 * 문서: 04.포인터 인자와 값 전달 (예시, 추적 표, 포인터를 바꾸는 함수, 카드)
 * 실행: cc -std=c11 -Wall -Wextra 04_pointer-parameters_impl.c -o ptr_params && ./ptr_params
 */
#include <stdio.h>

static int fails = 0;

#define CHECK(cond, msg)                                              \
    do {                                                              \
        if (!(cond)) {                                                \
            printf("[FAIL] %s (%d번째 줄)\n", (msg), __LINE__);        \
            fails++;                                                  \
        }                                                             \
    } while (0)

/* 값을 받는 판. x, y는 복사본이다 */
static void swap_by_value(int x, int y)
{
    int temp;
    temp = x;
    x = y;
    y = temp;
    (void)x;
    (void)y;                /* 복사본만 바뀌고 함수가 끝나면 사라진다 */
}

/* 주소를 받는 판. *px, *py는 부른 쪽의 칸이다 */
static void swap_by_pointer(int *px, int *py)
{
    int temp;
    temp = *px;
    *px = *py;
    *py = temp;
}

/* 추적 표용: 함수 안에서 본 값을 밖으로 내보내는 판 */
static void swap_by_value_traced(int x, int y, int seen[4])
{
    int temp;
    seen[0] = x; seen[1] = y;       /* 들어온 직후의 복사본 */
    temp = x;
    x = y;
    y = temp;
    seen[2] = x; seen[3] = y;       /* 바꾼 뒤의 복사본 */
}

/* 추적 표용: 주소를 받는 판을 한 줄 실행할 때마다 (temp, *px, *py)를 적는다 */
static void swap_by_pointer_traced(int *px, int *py, int rows[3][3])
{
    int temp;
    temp = *px;
    rows[0][0] = temp; rows[0][1] = *px; rows[0][2] = *py;
    *px = *py;
    rows[1][0] = temp; rows[1][1] = *px; rows[1][2] = *py;
    *py = temp;
    rows[2][0] = temp; rows[2][1] = *px; rows[2][2] = *py;
}

/* 돌려줄 값이 둘인 함수: 몫과 나머지 */
static void divide(int a, int b, int *quotient, int *remainder)
{
    *quotient = a / b;
    *remainder = a % b;
}

/* 포인터를 바꾸려는 함수 두 판 */
static void clear_wrong(int *p)
{
    p = NULL;               /* 주소의 복사본만 NULL이 된다 */
    (void)p;
}

static void clear_right(int **pp)
{
    *pp = NULL;             /* 부른 쪽 포인터 변수 자체를 고친다 */
}

static void point_to(int **pp, int *target)
{
    *pp = target;
}

/* 배열 인자: 첫 칸의 주소가 넘어온다 */
static void add_one_to_all(int a[], int n)
{
    int i;
    for (i = 0; i < n; i++)
        a[i] += 1;
}

/* 값으로 받는 판과 주소로 받는 판을 한 번 더 */
static void triple(int *p)
{
    *p = *p * 3;
}

static void triple_copy(int v)
{
    v = v * 3;
    (void)v;
}

static void rotate3(int *a, int *b, int *c)
{
    int t = *a;
    *a = *b;
    *b = *c;
    *c = t;
}

int main(void)
{
    /* 1. swap 두 판 */
    {
        int a = 3, b = 7;
        int seen[4];

        swap_by_value(a, b);
        CHECK(a == 3 && b == 7, "값을 넘긴 swap 뒤에도 a = 3, b = 7");

        swap_by_value_traced(a, b, seen);
        CHECK(seen[0] == 3 && seen[1] == 7 && seen[2] == 7 && seen[3] == 3, "함수 안의 복사본은 3, 7에서 7, 3으로 바뀐다");
        CHECK(a == 3 && b == 7, "그래도 부른 쪽은 그대로");

        swap_by_pointer(&a, &b);
        CHECK(a == 7 && b == 3, "주소를 넘긴 swap 뒤 a = 7, b = 3");

        swap_by_pointer(&a, &a);
        CHECK(a == 7, "같은 칸을 두 번 넘겨도 값은 그대로");

        {
            /* 문서의 추적 표: a = 3, b = 7에서 한 줄씩 */
            static const int want[3][3] = {{3, 3, 7}, {3, 7, 7}, {3, 7, 3}};
            int rows[3][3], c = 3, d = 7, i, j;
            swap_by_pointer_traced(&c, &d, rows);
            for (i = 0; i < 3; i++)
                for (j = 0; j < 3; j++)
                    CHECK(rows[i][j] == want[i][j], "추적 표: temp, a, b");
            CHECK(c == 7 && d == 3, "추적 표의 끝: a = 7, b = 3");
        }
        printf("[OK] swap: 값을 넘기면 3 7 그대로, 주소를 넘기면 7 3\n");
    }

    /* 2. 돌려줄 값이 둘 */
    {
        int q = 0, r = 0;
        divide(17, 5, &q, &r);
        CHECK(q == 3 && r == 2, "17 / 5 = 3, 17 % 5 = 2");
        printf("[OK] divide(17, 5, &q, &r): q = %d, r = %d\n", q, r);
    }

    /* 3. 포인터 자체를 바꾸려면 포인터의 주소를 넘긴다 */
    {
        int n = 5, m = 9;
        int *p = &n;

        clear_wrong(p);
        CHECK(p == &n, "카드 C3: clear_wrong(p) 뒤에도 p는 n을 가리킨다");

        point_to(&p, &m);
        CHECK(p == &m && *p == 9, "point_to(&p, &m) 뒤 p는 m을 가리킨다");

        clear_right(&p);
        CHECK(p == NULL, "카드 C3: clear_right(&p) 뒤 p는 NULL");
        CHECK(n == 5 && m == 9, "가리키던 값들은 그대로");
        printf("[OK] 포인터를 바꾸는 함수(카드 C3): int * 로 받으면 못 바꾸고, int ** 로 받으면 바꾼다\n");
    }

    /* 4. 배열 인자 */
    {
        int arr[4] = {10, 20, 30, 40};
        add_one_to_all(arr, 4);
        CHECK(arr[0] == 11 && arr[1] == 21 && arr[2] == 31 && arr[3] == 41, "배열을 넘기면 함수가 부른 쪽 배열을 고친다");
        add_one_to_all(&arr[2], 2);
        CHECK(arr[0] == 11 && arr[1] == 21 && arr[2] == 32 && arr[3] == 42, "가운데 칸의 주소를 넘기면 거기서부터 고친다");
        printf("[OK] 배열 인자: 첫 칸의 주소가 넘어가므로 원본이 바뀐다\n");
    }

    /* 5. 카드 */
    {
        int a = 1, b = 2;                 /* C1 */
        int x = 4, y = 4;
        int u = 1, v = 2, w = 3;

        swap_by_value(a, b);
        CHECK(a == 1 && b == 2, "C1: 첫 줄 출력 1 2");
        swap_by_pointer(&a, &b);
        CHECK(a == 2 && b == 1, "C1: 둘째 줄 출력 2 1");

        triple_copy(x);
        triple(&y);
        CHECK(x == 4 && y == 12, "triple_copy(x)는 x를 그대로 두고 triple(&y)는 y를 12로 만든다");

        rotate3(&u, &v, &w);
        CHECK(u == 2 && v == 3 && w == 1, "rotate3: 1 2 3 -> 2 3 1");
        printf("[OK] 카드 C1의 답 (1 2, 2 1)과 값·주소로 받는 함수의 차이\n");
    }

    if (fails) {
        printf("%d개 확인 실패\n", fails);
        return 1;
    }
    printf("ALL CHECKS PASSED\n");
    return 0;
}