좋습니다!
정보처리기사 실기에서 자주 나오는 헷갈리는 문제 유형은 다음과 같습니다:
이런 요소들을 섞어서 기초가 부족하면 틀리는 문제 하나 출제하고, 예제도 포함해서 풀이해볼게요.
다음 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;
}
x = 3, y = 4, result = 10x = 7, y = 11, result = 7x = 3, y = 4, result = 7x = 7, y = 4, result = 7int update(int a, int b) {
update는 두 개의 정수 a, b를 매개변수로 받음x, y의 값만 복사되어 a, b에 전달됨x, y는 절대 바뀌지 않음 a += b;
a = a + ba = 3 + 4 = 7 b += a;
b = b + a → 지금 b는 4, a는 7이므로b = 4 + 7 = 11 return a;
a = 7이므로 return 값은 7int main() {
int x = 3, y = 4;
int result = update(x, y);
x=3, y=4가 update 함수로 복사되어 들어감a=7, b=11이 되었지만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)
[10, 20, 100, 200][1, 2, 3, 200][10, 20, 100][10, 20][10, 20, 100]data = [10, 20]
data는 리스트 객체 [10, 20]를 가리키는 변수modify_list(data)
data라는 리스트 객체의 참조(reference) 가 lst라는 매개변수로 넘어감lst와 data는 동일한 리스트를 가리킴lst is data == Truelst.append(100)
lst는 [10, 20][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]이 됨print(data)
data는 여전히 [10, 20, 100]임lst가 다른 걸 가리켰을 뿐, 원래의 리스트 객체는 한 번만 수정됐음| 구문 | 설명 |
|---|---|
lst.append(100) | 원본 리스트(data)에 100을 추가 → 반영됨 |
lst = [1, 2, 3] | lst가 새 리스트를 가리키게 됨 → 원본과 분리 |
lst.append(200) | 새로운 리스트만 수정됨 → 원본에 영향 없음 |
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]Nonedef reset_list(lst):
lst.clear()
lst += [1, 2, 3]
data = [10, 20, 30]
reset_list(data)
print(data)
보기 없이 출력값을 직접 맞춰야 하는 문제라고 가정할게.
[1, 2, 3]data = [10, 20, 30]
data는 리스트 객체 [10, 20, 30]를 가리킴data → [10, 20, 30]
reset_list(data)
data가 lst로 전달됨lst is data == Truelst.clear()
.clear()는 리스트를 비움[10, 20, 30] → [] 로 바뀜data도 같이 바뀜메모리 상태:
data → []
lst → (같은 리스트를 가리킴)
lst += [1, 2, 3]
+= 연산은 리스트에서는 in-place (제자리에서) 추가를 의미함그래서:
[] → [1, 2, 3]지금 lst와 data가 같은 객체이므로, data도 변함
메모리 상태:
data → [1, 2, 3]
lst → (같은 리스트)
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]아무 일도 안 일어난 것처럼 보이지만, 내부에서는 꽤 많은 일이 벌어졌어.
왜 이렇게 되는지 디버깅 해보자!
data = [1, 2]
data는 리스트 객체 [1, 2]를 가리킴data → [1, 2]
tricky(data)
data 리스트가 lst 매개변수로 전달됨lst는 data와 같은 리스트를 가리키고 있음lst is data == Truelst = []
[]를 생성해서 lst가 그것을 가리키게 함lst는 이제 data와 연결이 끊김!Before:
lst → [1, 2] (같은 객체)
After:
lst → [] (새로운 객체)
data → [1, 2] (그대로 있음)
lst += [100]
lst가 가리키고 있는 새로운 빈 리스트 []에 100을 추가함
→ 결과적으로 lst == [100]
그러나 이 lst는 이제 data와 전혀 관계없는 리스트
함수가 끝나면 이 리스트는 가비지 컬렉션 대상이 됨
lst → [100] (새 객체)
data → [1, 2] (변함 없음)
lst는 사라짐data는 원래대로 [1, 2] 유지됨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]
data = [1]
data는 리스트 객체 [1]을 가리킴data → [1]
confuse(data)
data의 참조가 lst에 전달됨 → lst와 data는 같은 리스트를 가리킴lst is data == Truelst = data → [1]
lst += [10]
+= 연산은 in-place 연산이다 → 같은 객체의 내용을 수정함lst가 가리키는 리스트(= data)에 10을 추가함[1] → [1, 10]
data 도 [1, 10] 이 됨data → [1, 10]
lst → (같은 객체)
lst = lst + [20]
⚠️ 아주 중요한 포인트 나옴!
lst + [20] 은 새로운 리스트 객체를 생성함 → 결과는 [1, 10, 20]lst에 대입함이제 lst는 새 리스트 [1, 10, 20]를 가리킴
그러나 data는 여전히 [1, 10] 을 가리킴
data → [1, 10] (원래 리스트, 바뀌지 않음)
lst → [1, 10, 20] (새로운 리스트)
lst.append(30)
lst는 [1, 10, 20]이므로lst → [1, 10, 20, 30]하지만 이 리스트는 data와 전혀 관련 없음!!
lst는 사라지고, data만 남는다data는 여전히 [1, 10]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]