좋아! 이제부터는 다음 고급 주제들에 대해 트랩 문제 + 해설을 하나씩 제공할게. 실무나 실기 시험에서 실수하기 쉬운 부분 중심으로 설명해줄게.
#include <stdio.h>
typedef struct {
int data;
} Item;
Item getItem() {
Item temp;
temp.data = 42;
return temp;
}
int main() {
Item x = getItem();
printf("%d\n", x.data);
return 0;
}
Q1. 출력 결과는?
① 42
② 쓰레기 값
③ 컴파일 에러
④ 런타임 에러
temp는 함수 종료 시 사라지지만, 구조체는 복사 값으로 안전하게 전달됨📌 트랩은 다음과 같은 코드에서 발생함:
Item* getDanger() {
Item temp;
temp.data = 42;
return &temp; // ❌ 위험: 지역 변수의 주소 반환
}
정답: ①
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[10]; // 고정 배열
char* nickname; // 동적 문자열
} User;
int main() {
User u;
strcpy(u.name, "Kim");
u.nickname = malloc(20);
strcpy(u.nickname, "Tiger");
printf("%s %s\n", u.name, u.nickname);
free(u.nickname);
return 0;
}
Q2. 출력 결과는?
① Kim Tiger
② 쓰레기 값
③ Segfault
④ 컴파일 에러
char name[10] → 정적 배열이므로 strcpy() 가능nickname은 포인터이므로 반드시 malloc() 후 사용정답: ①
📌 흔한 실수:
User u;
strcpy(u.nickname, "Tiger"); // ❌ nickname이 아직 아무것도 안 가리킴!
typedef struct *Ptr 형태 트랩#include <stdio.h>
#include <stdlib.h>
typedef struct Person {
int age;
} *PersonPtr;
int main() {
PersonPtr p = malloc(sizeof(struct Person));
p->age = 30;
printf("%d\n", p->age);
free(p);
return 0;
}
Q3. 출력 결과는?
① 30
② 쓰레기 값
③ 컴파일 에러
④ Segfault
typedef struct Person *PersonPtr;는 PersonPtr을 포인터 타입으로 정의malloc(sizeof(struct Person)) → OKp->age = 30 → OK📌 주의할 점: PersonPtr는 포인터 타입이라는 것을 헷갈리지 말아야 함
정답: ①
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
} Node;
void printNode(void* p) {
Node* n = (Node*)p;
printf("%d\n", n->id);
}
int main() {
Node* node = malloc(sizeof(Node));
node->id = 77;
printNode(node);
free(node);
return 0;
}
Q4. 출력 결과는?
① 77
② 쓰레기 값
③ 컴파일 에러
④ 런타임 에러
void*는 모든 포인터를 받을 수 있는 범용 타입Node* n = (Node*)p; → 올바른 캐스팅printNode(node); → 구조체 주소 전달정답: ①
📌 주의할 점:
| 문제 | 주제 | 트랩 포인트 | 정답 |
|---|---|---|---|
| Q1 | 구조체 반환 | 값 복사 vs 참조 | ① |
| Q2 | 구조체 내 배열 | malloc 여부 | ① |
| Q3 | typedef *포인터 | 선언 혼동 | ① |
| Q4 | void* + 구조체 | 캐스팅 필수 | ① |
qsort and strcmp()void*로 받아 처리하는 제너릭 함수원하는 방향이나 구체적 포인트 있으면 알려줘!
또는 “실전 실기처럼 종합 문제”도 내줄 수 있어.
아주 날카로운 질문이야!
실제 정보처리기사 실기나 C 언어 시험에서는 숫자가 잘 출력되는 정상 케이스뿐 아니라, 아래와 같은 **“비정상 동작이 정답이 되는 트랩 문제”**도 매우 자주 나와:
int* foo() {
int x = 10;
return &x; // 위험: 함수 끝나면 x 사라짐
}
int* p = malloc(sizeof(int));
free(p);
printf("%d\n", *p); // 터지거나 쓰레기 값
int* p;
*p = 5; // 어디를 가리키는지 모르는데 값을 넣음
struct A { int x; };
struct A* p;
p.x = 3; // ❌ p는 포인터인데 . 연산자 사용 (-> 써야 함)
| 유형 | 설명 | 예시 정답 |
|---|---|---|
| 컴파일 에러 | 문법/타입 불일치 | struct A p; p->x = 1; |
| 런타임 에러 | NULL 접근, 세그폴트 | int* p = NULL; *p = 10; |
| 쓰레기 값 | 초기화 안 함 | int a; printf("%d", a); |
| 의도된 동작 아님 | shallow copy / 포인터 재사용 | strcpy(b.name, "hi"); (포인터 안 가리킴) |
좋아! 지금부터 출력이 "정상적으로 되지 않아야 정답"인 실전 트랩 문제 5제를 출제할게. 각 문제는 다음 중 하나의 결과를 유발하도록 설계되어 있어:
#include <stdio.h>
typedef struct {
int value;
} Box;
int main() {
Box* b;
b->value = 10;
printf("%d\n", b->value);
return 0;
}
Q1. 결과는?
① 10
② 컴파일 에러
③ 쓰레기 값
④ 런타임 에러
Box* b;는 선언만 했고, malloc이나 초기화를 하지 않음b->value는 NULL이나 쓰레기 주소를 역참조정답: ④ 런타임 에러
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* name;
} Person;
int main() {
Person a;
a.name = malloc(10);
strcpy(a.name, "Jack");
Person b = a;
free(a.name);
printf("%s\n", b.name);
return 0;
}
Q2. 결과는?
① Jack
② 컴파일 에러
③ 쓰레기 값 or 런타임 에러
④ Segfault 없이 정상 출력
char* name도 shallow copy 됨free(a.name) 하면 b.name도 같은 주소 → dangling pointerb.name 출력 시 use-after-free → 런타임 에러 가능정답: ③ 쓰레기 값 or 런타임 에러
#include <stdio.h>
typedef struct {
int data;
} Item;
Item* get() {
Item temp;
temp.data = 77;
return &temp;
}
int main() {
Item* p = get();
printf("%d\n", p->data);
return 0;
}
Q3. 결과는?
① 77
② 컴파일 에러
③ 쓰레기 값
④ 런타임 에러
temp는 함수 안의 지역 변수p->data는 undefined behavior → 보통 쓰레기 값 출력정답: ③ 쓰레기 값
| 항목 | 첫 번째 코드 (Item* get()) | 두 번째 코드 (Item getItem()) |
|---|---|---|
| 반환 타입 | Item* (구조체의 주소 반환) | Item (구조체 자체 복사 반환) |
| 반환하는 메모리 위치 | 함수 안의 지역 변수 (스택) | 지역 변수 복사 (값 복사) |
| 함수 종료 후 메모리 상태 | 지역 변수는 소멸함 → 잘못된 메모리 참조 | 복사된 구조체는 main 함수에 안전하게 전달됨 |
| 실행 결과 | 미정 (쓰레기값, 세그멘테이션 오류 가능) | 정상 동작, 안전하게 42 출력됨 |
#include <stdio.h>
typedef struct {
int a, b;
} Data;
void print(void* p) {
int* x = (int*)p;
printf("%d\n", *x);
}
int main() {
Data d = {5, 10};
print(&d);
return 0;
}
Q4. 출력 결과는?
① 5
② 10
③ 쓰레기 값
④ 컴파일 에러
Data는 {int a, b} 이지만,void*로 받아 int*로 변환해 첫 필드만 출력 → 이건 괜찮을 수도 있어.정답: ①
(하지만 트랩 포인트로 삼는다면 실무에서 지양해야 할 방식!)
#include <stdio.h>
#include <stdlib.h>
int main() {
int* a = malloc(10);
free(a);
free(a); // 두 번 해제
return 0;
}
Q5. 결과는?
① 컴파일 에러
② 정상 실행
③ 런타임 에러 (Double free)
④ 쓰레기 값 출력
free() 후 다시 해제하면 Double Free정답: ③ 런타임 에러 (Double Free)
| 문제 | 핵심 트랩 | 정답 | 이유 |
|---|---|---|---|
| Q1 | 미초기화 포인터 역참조 | ④ | Segfault |
| Q2 | shallow copy + free | ③ | use-after-free |
| Q3 | 지역 변수 주소 반환 | ③ | dangling pointer |
| Q4 | 잘못된 void* 캐스팅 | ① | 운 좋으면 OK, but 위험 |
| Q5 | free 두 번 | ③ | 런타임 에러 |
좋아, 이번엔 숫자가 많지 않지만 계산 흐름에서 헷갈리는 구조체 문제를 줄게.
한눈에 보기엔 단순해 보이지만, 구조체 복사, 포인터 접근, 값 변경 흐름이 복잡하게 얽혀 있어 실수하기 쉬운 스타일로 구성할게.
#include <stdio.h>
typedef struct {
int x;
} Point;
void update(Point a, Point* b) {
a.x += 1;
b->x += 2;
}
int main() {
Point p1 = {5};
Point p2 = p1;
update(p1, &p2);
printf("%d %d\n", p1.x, p2.x);
return 0;
}
① 5 7
② 6 7
③ 6 6
④ 7 7
p1 = {5}
p2 = p1; → 복사본 {5}
→ 이 시점:
p1.x = 5
p2.x = 5
update(p1, &p2);
함수 매개변수:
a는 p1의 복사본 → 값으로 전달됨 (지역 복사본)b는 p2의 주소 → 포인터 전달 (원본 수정됨)a.x += 1; // a는 복사본 → 원본 영향 없음
b->x += 2; // b는 포인터 → 실제 p2.x에 적용됨
→ 실행 후 상태:
a.x = 6 (지역 변수, 소멸됨)
p1.x = 5 (원본 유지)
p2.x = 7 (2 더함)
5 7Point*)로 전달하면, 원본 수정 가능p2 = p1;은 복사 (shallow copy지만 값형 구조체이므로 괜찮음)