본문 바로가기

C

[C언어] 포인터(pointer) 개념 완벽이해하기(ft. 미션맨과 스파이의 임무)

반응형

 

 

 

토글

 

 

 


Scene 1: 포인터의 개념과 미션맨의 임무

철수, 영희, 민수라는 주민들이 살고 있는 아파트가 있습니다. 각 주민들은 자신의 방에 들어가기 위해 암호가 필요한데요, 이 암호를 미션맨이 찾아내야 합니다. C 프로그래밍에서 포인터는 미션맨과 같은 역할을 하며, 메모리 주소를 저장하고 다른 변수들의 값을 찾아냅니다. 이러한 개념을 코드로 구현해봅시다.

- 철수, 영희, 민수의 암호와 주소를 변수로 설정합니다.

int 철수 = 1; // 암호
int 영희 = 2;
int 민수 = 3;


- 주민들의 주소와 암호를 출력합니다.

printf("철수네 주소 : %p, 암호 : %d\n", &철수, 철수);
printf("영희네 주소 : %p, 암호 : %d\n", &영희, 영희);
printf("민수네 주소 : %p, 암호 : %d\n", &민수, 민수);



- 미션맨이 각 주민의 방을 방문하면서 암호를 확인합니다.

int *미션맨; // 포인터 변수
미션맨 = &철수;
printf("미션맨이 방문하는 곳의 주소 : %p, 암호 : %d\n", 미션맨, *미션맨);

미션맨 = &영희;
printf("미션맨이 방문하는 곳의 주소 : %p, 암호 : %d\n", 미션맨, *미션맨);

미션맨 = &민수;
printf("미션맨이 방문하는 곳의 주소 : %p, 암호 : %d\n", 미션맨, *미션맨);

 

 



Scene 2: 스파이의 도착과 암호 변경

미션맨이 모든 주민들의 암호를 확인하던 중, 스파이가 미션맨의 발자취를 따라옵니다. 이제 스파이가 방문한 곳에서 암호를 수정해야 합니다. 이때 포인터를 사용하여 메모리 주소에 직접 접근하고 데이터를 변경할 수 있습니다.

- 미션맨의 미션: 각 암호에 3을 곱해 변경하라!

미션맨 = &철수;
*미션맨 = *미션맨 * 3;
printf("미션맨이 암호를 바꾼 곳의 주소: %p, 암호 : %d\n", 미션맨, *미션맨);

미션맨 = &영희;
*미션맨 = *미션맨 * 3;
printf("미션맨이 암호를 바꾼 곳의 주소: %p, 암호 : %d\n", 미션맨, *미션맨);

미션맨 = &민수;
*미션맨 = *미션맨 * 3;
printf("미션맨이 암호를 바꾼 곳의 주소: %p, 암호 : %d\n", 미션맨, *미션맨);

 

- 스파이의 히든 미션: 미션맨이 바꾼 암호에서 2를 빼라!

int *스파이 = 미션맨;
printf("\n ... 스파이가 미션을 수행하는 중 ...\n\n");

스파이 = &철수;
*스파이 = *스파이 - 2; // 철수=철수-2;
printf("스파이가 방문하는 곳의 주소 : %d, 암호 : %d\n", 스파이, *스파이);

 

 

 




Scene 3: 배열과 포인터의 상호작용

미션맨과 스파이가 아파트를 돌아다니며 암호를 발견하는 것처럼, 배열은 메모리 상에 연속적으로 저장된 데이터의 집합입니다. 이때 포인터는 배열의 요소들에 접근하고 값을 변경하는 데에도 사용됩니다. 

반응형


- 배열과 포인터의 관계

int arr[3] = {5, 10, 15};
int *ptr = arr; // 포인터 변수가 arr의 값을 가리킵니다.

// 배열 arr의 값과 포인터 ptr의 값 출력
for (int i = 0; i < 3; i++)
{
    printf("배열 arr[%d]의 값 : %d\n", i, arr[i]);
}
for (int i = 0; i < 3; i++)
{
    printf("포인터 ptr[%d]의 값 : %d\n", i, ptr[i]);
}



- 포인터를 통해 배열의 요소를 변경

ptr[0] = 100;
ptr[1] = 200;
ptr[2] = 300;



- 변경된 배열 arr의 값과 포인터 ptr의 값 출력

for (int i = 0; i < 3; i++)
{
    printf("배열 arr[%d]의 값 : %d\n", i, *(arr + i));
}
for (int i = 0; i < 3; i++)
{
    printf("포인터 ptr[%d]의 값 : %d\n", i, *(ptr + i));
}

 

 

 



Scene 4: 포인터의 특징과 주의사항

포인터를 사용할 때 주의해야 할 점과 흔히 발생하는 함정들에 대해 알아보겠습니다. 포인터의 사용에 있어서 실수를 줄이기 위해 유의해야 할 사항들을 알아봅시다.

- arr 자체와 arr[0]의 주소값과 값 출력

printf("arr 자체의 값 : %p\n", arr);
printf("arr[0]의 주소 값 : %p\n", &arr[0]);


- arr 자체의 주소값이 가지는 실제 값과 arr[0]의 실제 값 출력

printf("arr 자체의 값이 가지는 주소의 실제 값 : %p\n", *arr);
printf("arr[0]의 실제 값 : %d\n", *(&arr[0]));

 

 

 


 

Scene 5: 함수의 인자로 포인터 사용

함수에 포인터를 인자로 전달하여 데이터를 변경하는 방법에 대해 살펴보겠습니다. 함수에 인자로 포인터를 전달하면, 해당 포인터를 통해 메모리 주소에 직접 접근할 수 있어 값의 변경이 가능합니다.

 

- 두 변수의 값을 바꾸는 swap 함수

void swap(int a, int b)
{
    printf("Swap 함수 내 a의 주소: %p\n", &a);
    printf("Swap 함수 내 b의 주소: %p\n", &b);

    int temp = a;
    a = b;
    b = temp;
    printf("Swap 함수 내 => a: %d, b: %d\n", a, b); // Swap 함수 내 => a: 20, b: 10
}

 

- 두 변수의 값을 바꾸는 swap_addr 함수 (포인터를 사용하여 값 변경)

void swap_addr(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
    printf("(주소값 전달) Swap 함수 내 => a: %d, b: %d\n", *a, *b);
}

 

- 배열의 요소를 변경하는 changeArray 함수

void changeArray(int *ptr)
{
    ptr[2] = 50;
}

 

- 값에 의한 복사와 주소에 의한 복사

int main_swap(void)
{
    int a = 10;
    int b = 20;

    // 값에 의한 복사(call by value)로 인해 a와 b의 값은 변경되지 않습니다.
    printf("Swap 함수 전 => a: %d, b: %d\n", a, b);
    swap(a, b);
    printf("Swap 함수 후 => a: %d, b: %d\n", a, b);

    // 주소값을 넘기면? 메모리공간에 있는 주소값 자체를 넘기면... 철수네처럼
    // 포인터를 사용하여 값의 변경이 가능합니다.
    printf("(주소값 전달) Swap 함수 전 => a: %d, b: %d\n", a, b);
    swap_addr(&a, &b);
    printf("(주소값 전달) Swap 함수 후 => a: %d, b: %d\n", a, b);

    // 배열일 때, 포인터를 사용하여 배열의 요소를 변경합니다.
    int arr2[3] = {10, 20, 30};
    changeArray(arr2);
    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", arr2[i]);
    }

    return 0;
}

 

 

 

 

 

 

반응형