연습5(특히 마지막)

류한선·2025년 6월 29일

실기연습-2

목록 보기
56/95

좋습니다!
정보처리기사 실기에서 자주 나오는 헷갈리는 문제 유형은 다음과 같습니다:

  • 변수의 범위(scope)
  • 매개변수 값 전달 vs 참조 전달
  • 전위/후위 연산자
  • 배열이나 포인터 값의 변경 여부
  • 논리 연산자 단축 평가
  • 조건문이나 반복문에 break/continue 트릭
  • static 변수와 인스턴스 변수의 차이
  • 같은 이름의 지역변수 vs 전역변수

이런 요소들을 섞어서 기초가 부족하면 틀리는 문제 하나 출제하고, 예제도 포함해서 풀이해볼게요.


✅ 문제

다음 C 코드의 출력 결과를 구하시오.

#include <stdio.h>

int update(int a, int b) {
    a += b;
    b += a;
    return a;
}

int main() {
    int x = 3, y = 4;
    int result = update(x, y);
    printf("x = %d, y = %d, result = %d\n", x, y, result);
    return 0;
}

❓ 예상 정답 보기 (고르라고 가정하면 다음과 같이 낼 수도 있음)

  1. x = 3, y = 4, result = 10
  2. x = 7, y = 11, result = 7
  3. x = 3, y = 4, result = 7
  4. x = 7, y = 4, result = 7

✅ 정답: 3번. x = 3, y = 4, result = 7


🔍 디버깅 해설 (한 줄씩)

int update(int a, int b) {
  • 함수 update는 두 개의 정수 a, b를 매개변수로 받음
  • 중요 포인트: C에서는 기본형(int 등)은 **값에 의한 복사(Call by Value)**가 이루어짐
    → 즉, x, y의 값만 복사되어 a, b에 전달됨
    main에서의 x, y는 절대 바뀌지 않음
    a += b;
  • a = a + b
  • 예제 기준: a = 3 + 4 = 7
    b += a;
  • b = b + a → 지금 b는 4, a는 7이므로
  • b = 4 + 7 = 11
  • 이 줄에서 b가 바뀌었지만, 이건 update 함수 안의 지역 변수일 뿐임
    return a;
  • a = 7이므로 return 값은 7
int main() {
    int x = 3, y = 4;
  • 메인 함수에서 x=3, y=4로 시작
    int result = update(x, y);
  • 여기서 x=3, y=4가 update 함수로 복사되어 들어감
  • update 함수 안에서 a=7, b=11이 되었지만
  • main 함수의 x, y는 바뀌지 않음
  • result = 7
    printf("x = %d, y = %d, result = %d\n", x, y, result);
  • x = 3, y = 4, result = 7 출력

🧠 요약 포인트 정리

요소개념핵심
함수 인자 전달값 복사 (Call by Value)원본 x, y는 절대 안 바뀜
함수 내 변수지역변수메인 함수 밖에서는 영향 없음
결과return 값만 영향result만 변경됨

✅ 추가 퀴즈 (비슷한 함정)

#include <stdio.h>

void tricky(int *a, int b) {
    *a += b;
    b += *a;
}

int main() {
    int x = 2, y = 3;
    tricky(&x, y);
    printf("x = %d, y = %d\n", x, y);
    return 0;
}

정답은?

  • x = 5, y = 3

✔ 포인터로 받은 x는 바뀌지만, y는 여전히 값으로 복사됐으므로 그대로.


좋아!
이번엔 **Python의 리스트가 mutable(가변 객체)**이라는 특징을 활용한 문제를 내볼게.
이건 초보자가 흔히 착각하는 포인트이고, 정보처리기사 실기에서도 유사 개념이 출제될 수 있어.
특히 함수에 리스트를 넘길 때 어떤 일이 일어나는지를 물을 수 있어.


✅ 문제: 다음 코드의 출력 결과를 구하시오.

def modify_list(lst):
    lst.append(100)
    lst = [1, 2, 3]
    lst.append(200)

data = [10, 20]
modify_list(data)
print(data)

❓ 선택지:

  1. [10, 20, 100, 200]
  2. [1, 2, 3, 200]
  3. [10, 20, 100]
  4. [10, 20]

✅ 정답: 3번. [10, 20, 100]


🔍 디버깅 해설: 한 줄씩 따라가기

첫 줄:

data = [10, 20]
  • data는 리스트 객체 [10, 20]를 가리키는 변수

함수 호출:

modify_list(data)
  • data라는 리스트 객체의 참조(reference)lst라는 매개변수로 넘어감
  • 여기서 lstdata동일한 리스트를 가리킴
  • 즉, lst is data == True

함수 내부:

lst.append(100)
  • 지금 lst[10, 20]
  • 여기에 100을 추가 → 리스트가 [10, 20, 100]이 됨
  • 이건 리스트의 내용 자체를 수정하는 작업이므로 data도 영향을 받음

다음 줄:

lst = [1, 2, 3]
  • 이 줄에서 중요한 일이 벌어짐!
  • lst새로운 리스트 객체 [1, 2, 3]를 가리키게 됨
  • 기존의 data 리스트와의 연결은 끊김
  • 이 이후로는 lst만 새로운 객체를 바라보고 있음

그다음:

lst.append(200)
  • lst가 지금 가리키는 건 [1, 2, 3]이므로
  • lst[1, 2, 3, 200]이 됨
  • 하지만! 이 리스트는 함수 밖에서는 아무도 모름!
  • 함수 종료되면 이 리스트는 GC(가비지 컬렉션) 대상이 됨

함수 종료 후:

print(data)
  • data는 여전히 [10, 20, 100]
  • 중간에 lst가 다른 걸 가리켰을 뿐, 원래의 리스트 객체는 한 번만 수정됐음

📌 요약 포인트 정리

구문설명
lst.append(100)원본 리스트(data)에 100을 추가 → 반영됨
lst = [1, 2, 3]lst가 새 리스트를 가리키게 됨 → 원본과 분리
lst.append(200)새로운 리스트만 수정됨 → 원본에 영향 없음

🧠 핵심 개념 암기법

  • 리스트는 mutable해서 내부를 바꾸면 바깥에서도 반영됨
  • 하지만 lst = 다른 리스트처럼 새 객체를 할당하면
    → 기존 객체와의 연결은 끊어진다!

✅ 연습용 추가 문제 (스스로 풀어보기)

def reset_list(lst):
    lst.clear()
    lst += [1, 2, 3]

data = [10, 20, 30]
reset_list(data)
print(data)

출력 결과는?

  • []
  • [1, 2, 3]
  • [10, 20, 30, 1, 2, 3]
  • None
    좋아! 방금 준 연습 문제를 아주 자세히, 한 줄 한 줄 디버깅하면서 해설해줄게.
    먼저 문제 다시 확인하고,

✅ 문제

def reset_list(lst):
    lst.clear()
    lst += [1, 2, 3]

data = [10, 20, 30]
reset_list(data)
print(data)

❓ 예상 출력 결과?

보기 없이 출력값을 직접 맞춰야 하는 문제라고 가정할게.


✅ 정답: [1, 2, 3]


🔍 한 줄씩 완전 해부 설명 (예제 포함)


1️⃣ 먼저 시작:

data = [10, 20, 30]
  • data는 리스트 객체 [10, 20, 30]를 가리킴
  • 메모리 그림으로 보면 이렇게 생겼어:
data → [10, 20, 30]

2️⃣ 함수 호출

reset_list(data)
  • datalst로 전달됨
  • 리스트는 mutable이므로 data와 lst는 같은 객체를 가리킴
  • 즉, lst is data == True

3️⃣ 함수 내부

lst.clear()
  • .clear()는 리스트를 비움
  • 즉, [10, 20, 30][] 로 바뀜
  • 이건 원본 객체를 수정하는 동작이므로 data도 같이 바뀜

메모리 상태:

data → []
lst  → (같은 리스트를 가리킴)

4️⃣ 다음 줄

lst += [1, 2, 3]
  • 여기서 중요한 포인트!
  • += 연산은 리스트에서는 in-place (제자리에서) 추가를 의미함
  • 즉, 새로운 객체를 만드는 게 아니라, 기존 객체에 바로 붙임

그래서:

  • [][1, 2, 3]

지금 lstdata가 같은 객체이므로, data도 변함

메모리 상태:

data → [1, 2, 3]
lst  → (같은 리스트)

5️⃣ 함수 종료 후

print(data)
  • 최종적으로 data[1, 2, 3]이므로

출력 결과는:

[1, 2, 3]

💡 요약: 핵심 차이점 정리

연산효과결과
lst.clear()기존 리스트의 모든 요소 제거data도 영향 받음
lst += [...]기존 리스트에 요소 추가data도 같이 바뀜
lst = [...]새로운 리스트 객체 할당data와 연결 끊김 → data는 영향 X

✅ 헷갈리게 다시 응용 문제

다음 출력 결과는?

def tricky(lst):
    lst = []
    lst += [100]

data = [1, 2]
tricky(data)
print(data)

정답은?

  • []
  • [100]
  • [1, 2]
  • [1, 2, 100]

좋아!
그럼 방금 준 이 Python 리스트 mutable 문제의 응용 버전을 완전 디버깅하듯 해설해줄게.
아래 코드 기억해두고, 한 줄씩 따라가면서 무슨 일이 벌어지는지 보자.


✅ 문제 코드

def tricky(lst):
    lst = []
    lst += [100]

data = [1, 2]
tricky(data)
print(data)

✅ 정답: [1, 2]

아무 일도 안 일어난 것처럼 보이지만, 내부에서는 꽤 많은 일이 벌어졌어.
왜 이렇게 되는지 디버깅 해보자!


🔍 한 줄씩 해설 (디버깅 설명 포함)


1️⃣ 먼저 시작:

data = [1, 2]
  • 변수 data는 리스트 객체 [1, 2]를 가리킴
  • 그림으로 표현하면:
data → [1, 2]

2️⃣ 함수 호출

tricky(data)
  • data 리스트가 lst 매개변수로 전달됨
  • Python은 함수 인자를 참조(reference) 로 전달함
    → 즉, lstdata와 같은 리스트를 가리키고 있음
    lst is data == True

3️⃣ 함수 내부 첫 줄

lst = []
  • 이 줄에서 완전 새로운 리스트 []를 생성해서 lst가 그것을 가리키게 함
  • 중요 포인트: 이 순간 lst는 이제 data와 연결이 끊김!
Before:
lst → [1, 2] (같은 객체)

After:
lst → []      (새로운 객체)
data → [1, 2] (그대로 있음)

4️⃣ 다음 줄

lst += [100]
  • lst가 가리키고 있는 새로운 빈 리스트 []에 100을 추가함
    → 결과적으로 lst == [100]

  • 그러나 이 lst는 이제 data와 전혀 관계없는 리스트

  • 함수가 끝나면 이 리스트는 가비지 컬렉션 대상이 됨

lst  → [100] (새 객체)
data → [1, 2] (변함 없음)

5️⃣ 함수 종료

  • lst는 사라짐
  • data는 원래대로 [1, 2] 유지됨

6️⃣ 출력

print(data)
[1, 2]

🧠 요약: 핵심 개념

코드의미결과
lst = []새로운 리스트 생성기존 객체와 연결 끊김
lst += [...]새 리스트에 요소 추가data에는 영향 없음
결과적으로data는 변경되지 않음출력은 [1, 2]

⚠️ 포인트 구분 (정리)

코드 형태리스트 변경 여부왜 그럴까?
lst.append(...)✅ 바뀜원래 객체를 수정
lst += [...]✅ 바뀜 (같은 객체면)in-place 연산
lst = [...]❌ 바뀌지 않음참조가 새 객체로 바뀜 (기존 객체와 무관)

✅ 연습용 마무리 문제

다음 코드는 어떤 출력 결과를 낼까?

def confuse(lst):
    lst += [10]
    lst = lst + [20]
    lst.append(30)

data = [1]
confuse(data)
print(data)
  • [1, 10, 20, 30]
  • [1, 10, 30]
  • [1, 10, 30, 20]
  • [1, 10, 30]

좋아!
그럼 이 문제도 Python 리스트의 참조와 값 복사의 혼합 트릭이 숨어 있는 코드야.
아래 코드를 완전히 디버깅 모드처럼 한 줄씩, 값 변화까지 추적하면서 해설해줄게.


✅ 문제 코드

def confuse(lst):
    lst += [10]
    lst = lst + [20]
    lst.append(30)

data = [1]
confuse(data)
print(data)

❓ 예상 출력 결과?

정답은 [1, 10, 30]


🔍 한 줄씩 완전 해부 (값 변화 추적)


1️⃣ 시작

data = [1]
  • data는 리스트 객체 [1]을 가리킴
data → [1]

2️⃣ 함수 호출

confuse(data)
  • data의 참조가 lst에 전달됨 → lstdata는 같은 리스트를 가리킴
    즉, lst is data == True
lst = data → [1]

3️⃣ 첫 줄

lst += [10]
  • 리스트의 += 연산은 in-place 연산이다 → 같은 객체의 내용을 수정함
  • lst가 가리키는 리스트(= data)에 10을 추가함
[1][1, 10]
  • 결과적으로 data[1, 10] 이 됨
data → [1, 10]
lst  → (같은 객체)

4️⃣ 두 번째 줄

lst = lst + [20]

⚠️ 아주 중요한 포인트 나옴!

  • lst + [20]새로운 리스트 객체를 생성함 → 결과는 [1, 10, 20]
  • 그리고 그 새 리스트를 lst에 대입함

이제 lst는 새 리스트 [1, 10, 20]를 가리킴
그러나 data는 여전히 [1, 10] 을 가리킴

data → [1, 10]         (원래 리스트, 바뀌지 않음)
lst  → [1, 10, 20]     (새로운 리스트)

5️⃣ 세 번째 줄

lst.append(30)
  • 이때 lst[1, 10, 20]이므로
  • lst[1, 10, 20, 30]

하지만 이 리스트는 data와 전혀 관련 없음!!


6️⃣ 함수 종료 후

  • lst는 사라지고, data만 남는다
  • data는 여전히 [1, 10]

7️⃣ 출력

print(data)

출력 결과는?
👉 [1, 10]

🤔 그런데 정답은 [1, 10, 30]이라 하지 않았어?


⚠️ 맞다! 그럼 정답은 다시 생각해서 수정해야겠네.

다시 한 번 흐름 정리하자:

동작결과 (data 기준)
lst += [10]리스트에 10 추가 (in-place)[1, 10]
lst = lst + [20]새로운 리스트 생성 → lst만 바뀜data는 여전히 [1, 10]
lst.append(30)새 리스트에 30 추가data는 영향 없음

✅ 최종 정답은: [1, 10]

내가 앞에서 [1, 10, 30]이라고 잘못 말했었네!
→ 정확히 디버깅하면 **[1, 10]**이 맞아.
착오를 줄이기 위해 헷갈리는 부분은 정리해줄게.


🔁 핵심 요약 비교: += vs +

표현동작 방식결과
lst += [x]같은 객체에 추가 (in-place)원본도 바뀜
lst = lst + [x]새 리스트를 만들어 lst에 대입원본과 분리됨

📌 메모리 흐름 시각화

처음:
data → [1]
lst  → [1]    (같은 객체)

lst += [10]
data → [1, 10]
lst  → [1, 10] (같은 객체)

lst = lst + [20]
lst  → [1, 10, 20]   (새 객체)
data → [1, 10]       (여전히 원래 객체)

lst.append(30)
lst  → [1, 10, 20, 30]
data → [1, 10]

0개의 댓글