포인터(주의)-좀 더 공부해야 할듯

류한선·2025년 6월 24일

실기연습-2

목록 보기
36/95

좋아요! 🎯
이번에는 C언어 포인터 트릭 문제를 하나 준비해 드릴게요. 포인터가 꼬이는 문제는 정보처리기사 실기에서 단골이니, 철저히 디버깅식 풀이를 같이 보여드릴 거예요. 💡


🧩 트릭 문제 (포인터 미로 문제)(체크)

📜 문제

다음 코드를 보고 최종 출력값을 유추해 보세요.

#include <stdio.h>

int main() {
    int a = 5;
    int b = 10;
    int c = 15;

    int *p1 = &a;
    int *p2 = &b;
    int *p3 = &c;

    int **pp1 = &p1;
    int **pp2 = &p2;

    *pp1 = p3;       // 1
    *pp2 = p1;       // 2

    *p1 = 100;       // 3
    *p2 = 200;       // 4

    printf("%d %d %d\n", a, b, c);
    printf("%d %d %d\n", *p1, *p2, *p3);

    return 0;
}

🧠 디버깅식 풀이

📍 초기 상태

a = 5, b = 10, c = 15
p1 → a
p2 → b
p3 → c
pp1 → p1
pp2 → p2
메모리 상태 그림:
[ a(5) ] <- p1
[ b(10)] <- p2
[ c(15)] <- p3
pp1 -> p1(->a), pp2 -> p2(->b)

📍 *pp1 = p3; (1)

  • pp1p1의 주소를 가지고 있으므로 *pp1 = p3;p1 = p3.
  • 이제 p1 → c(15)

📍 *pp2 = p1; (2)

  • pp2p2의 주소를 가지고 있으므로 *pp2 = p1;p2 = p1.
  • 현재 p1 → c(15) 이므로 p2 → c(15)

📍 상태 정리 (중간)

p1 → c(15)
p2 → c(15)
p3 → c(15)
a(5), b(10), c(15)

→ 이제 p1, p2, p3 모두 c를 가리킴.


📍 *p1 = 100; (3)

  • p1 → c이므로 c = 100
  • 상태: a(5), b(10), c(100)

📍 *p2 = 200; (4)

  • p2 → c이므로 c = 200
  • 상태: a(5), b(10), c(200)

📍 최종 출력

printf("%d %d %d\n", a, b, c);       // a=5 b=10 c=200 출력
printf("%d %d %d\n", *p1, *p2, *p3); // p1,p2,p3 → c(200), 출력: 200 200 200

🎯 정답

5 10 200
200 200 200

🔥 트릭 정리

pp1, pp2 같이 이중 포인터가 나올 경우 포인터가 어디를 가리키고 있는지를 반드시 추적.
✅ 포인터에 포인터를 대입하면 대상의 참조가 바뀌므로 이후의 값 변경에 주의.
✅ 최종 출력 전에 메모리 상태를 한 번 그림 그리듯 정리하는 습관 들이면 트릭 문제에도 끄떡없어요.


좋아요! 🔥 이번엔 포인터 트릭 문제를 다양한 유형(포인터+배열, 구조체 포인터, 함수 포인터)으로 준비할게요. 그리고 각 문제마다 자세히 디버깅식 풀이까지 보여 드릴게요. 🎯


🧩 1️⃣ 포인터 + 2차원 배열 트릭 (체크)

📜 문제

다음 코드를 보고 출력값을 예측해보세요:

#include <stdio.h>

int main() {
    int arr[2][3] = {{1,2,3},{4,5,6}};
    int (*p)[3] = arr;
    printf("%d ", *(*(p+1) + 2));
    printf("%d ", *(*p + 1));
    return 0;
}

🧠 디버깅식 풀이

상태 정리

  • arr[2][3] 구조:
arr[0]: 1 2 3
arr[1]: 4 5 6
  • p = arr;pint[3]를 가리키는 포인터 → parr[0] 시작 주소를 참조

*(*(p+1) + 2) 부분:

  • p+1arr[1]을 가리킴
  • *(p+1) → arr[1] 자체(주소), 거기에 +2 → arr[1][2]의 주소
  • *(*(p+1)+2) → arr[1][2] 값 = 6

*(*p + 1) 부분:

  • *p → arr[0]
  • *p + 1 → arr[0][1]의 주소
  • *(*p + 1) → arr[0][1] 값 = 2

🎯 정답

6 2

🧩 2️⃣ 구조체 포인터 트릭

📜 문제

다음 코드를 보고 출력값을 유추해 보세요:

#include <stdio.h>

typedef struct {
    int x;
    int y;
} Point;

int main() {
    Point p1 = {10, 20};
    Point p2 = {30, 40};
    Point *pp = &p1;
    *pp = p2;
    pp->x = 50;
    printf("%d %d\n", p1.x, p1.y);
    return 0;
}

🧠 디버깅식 풀이

상태 정리

p1 = (10,20), p2 = (30,40), pp → p1

*pp = p2;

  • p1의 구조체 전체를 p2 값(30,40)으로 대입 → p1 = (30,40)

pp->x = 50;

  • pp → p1.x = 50 → p1 = (50,40)

출력

50 40

🧩 3️⃣ 함수 포인터 트릭

📜 문제

다음 코드를 보고 출력값을 유추해 보세요:

#include <stdio.h>

int add(int a, int b) { return a+b; }
int sub(int a, int b) { return a-b; }

int main() {
    int (*funcs[2])(int,int) = {add, sub};
    int x = funcs[0](10, 5) + funcs[1](10, 5);
    printf("%d\n", x);
    return 0;
}

🧠 디버깅식 풀이

상태 정리

funcs[0] → add, funcs[1] → sub

계산

funcs[0](10, 5) → add(10, 5) = 15
funcs[1](10, 5) → sub(10, 5) = 5
x = 15 + 5 = 20

출력

20

🎯 정답

20

✏️ 정리

✅ 포인터 + 배열 트릭: *(p+1) + n → 반드시 구조를 그림 그리며 계산
✅ 구조체 포인터 트릭: *pp = 다른 구조체 → 전체 복사, pp->멤버 → p1의 멤버 참조
✅ 함수 포인터 트릭: 함수 이름을 배열에 담아 호출 가능


좋아요! 🎯
이번에는 **double pointer(이중 포인터)**와 malloc 메모리 할당 트릭 문제를 내고, 한 줄씩 꼼꼼히 풀이해 드릴게요.
포인터와 동적 메모리 관리에서 실수하기 쉽지만, 잘 이해하면 실기 고득점 가능!


🧩 1️⃣ 이중 포인터 (double pointer) 트릭 문제

📜 문제

#include <stdio.h>

void update(int **p) {
    static int x = 10;
    *p = &x;
}

int main() {
    int a = 5;
    int *p = &a;
    update(&p);
    printf("%d\n", *p);
    return 0;
}

🧠 디버깅식 풀이

  • a = 5, pa 주소를 가리킴
  • update(&p) 호출 → p의 주소를 전달 (즉, int **pp를 가리킴)
  • 함수 내부에서 static int x = 10; 선언 → 함수가 끝나도 사라지지 않는 변수 x
  • *p = &x;p가 가리키는 변수(p 자체)가 이제 x의 주소를 가리키게 변경됨
  • 즉, mainp는 더 이상 a가 아니라 x를 가리킴
  • printf("%d\n", *p);*px 값 → 10 출력

🎯 정답

10

🧩 2️⃣ malloc 트릭 문제

📜 문제

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *p = malloc(sizeof(int) * 3);
    p[0] = 1;
    *(p + 1) = 2;
    p[2] = 3;

    int *q = p;
    free(p);

    printf("%d %d %d\n", q[0], q[1], q[2]);
    return 0;
}

🧠 디버깅식 풀이

  • malloc(sizeof(int) * 3) → 3개의 int 공간 할당 (정상적으로 할당됨)

  • p[0] = 1;, p[1] = 2;, p[2] = 3; 값 저장

  • int *q = p;q도 같은 메모리를 가리킴 (얕은 복사)

  • free(p); → 메모리 해제 (p와 q가 가리키는 메모리가 OS에 반환됨)

  • 그 뒤 printf에서 q[0] q[1] q[2]를 출력하려 하지만, 메모리는 해제됐으므로 결과는 불확실

    • 실제로는 예전 값이 출력될 수도 있고,
    • 프로그램에 따라 쓰레기 값, 심지어 크래시가 날 수도 있음.

🎯 정답 (출력 결과 예측)

  • 정확한 출력은 보장 안 됨
  • 보통은 1 2 3 또는 이상한 값이 출력됨(Undefined Behavior)
  • 따라서 free 후 포인터 사용은 절대 금지!

🔥 요점 정리

포인터 종류특징 및 주의점
이중 포인터포인터를 가리키는 포인터. 함수에서 포인터 자체를 변경할 때 유용.
malloc동적 메모리 할당. 할당 후 사용하다가 free 하면 메모리 반환됨. 반환 후 참조는 위험.

✏️ 마무리

  • update(&p) 처럼 이중 포인터를 넘겨서 함수 내에서 포인터 값 변경 가능
  • malloc 후 반드시 free 하고, free 후 메모리 참조하면 안 됨(미정의 동작)

0개의 댓글