좋아! C언어에서 -> 연산자는 구조체 포인터가 가리키는 멤버에 접근할 때 사용하는 연산자야. 이걸 헷갈리게 하는 문제들도 정보처리기사 실기나 C언어 시험에서 자주 나오는 트랩 포인트야.
-> 와 . 차이| 표현 | 사용 조건 | 의미 |
|---|---|---|
a.b | 구조체 변수 | 구조체의 멤버 접근 |
a->b | 구조체 포인터 | 포인터가 가리키는 구조체의 멤버 접근 |
즉, .는 변수일 때, ->는 포인터일 때 써야 함.
#include <stdio.h>
typedef struct {
int id;
char name[10];
} Person;
int main() {
Person p = {1, "Alice"};
Person* ptr = &p;
printf("%d\n", ptr.id);
return 0;
}
Q1. 출력 결과는?
① 1
② 컴파일 에러
③ 쓰레기 값
④ 0
printf("%d\n", ptr.id); // ❌ 틀림
ptr는 포인터인데, . 연산자를 사용했기 때문에 에러!-> 써야 함✅ 수정 예시:
printf("%d\n", ptr->id); // OK
정답: ② 컴파일 에러
#include <stdio.h>
typedef struct {
int age;
} Student;
int main() {
Student arr[2] = {{20}, {25}};
Student* ptr = arr;
printf("%d\n", ptr->age);
printf("%d\n", (ptr + 1)->age);
return 0;
}
Q2. 출력 결과는?
①
20
25
②
25
20
③ 컴파일 에러
④ 쓰레기 값 출력
arr는 구조체 배열Student* ptr = arr; → 배열의 첫 번째 요소 주소ptr->age → arr[0].age = 20(ptr + 1)->age → arr[1].age = 25정답: ①
#include <stdio.h>
typedef struct {
int val;
} Node;
int main() {
Node* n = NULL;
printf("%d\n", n->val);
return 0;
}
Q3. 결과는?
① 0
② 컴파일 에러
③ 런타임 에러 (Segmentation fault)
④ -1
n은 NULL 포인터인데 n->val로 접근하면 Segmentation fault-> 사용하면 터짐정답: ③
#include <stdio.h>
typedef struct {
int x;
} Inner;
typedef struct {
Inner in;
} Outer;
int main() {
Outer o = {{100}};
Outer* p = &o;
printf("%d\n", p->in.x);
return 0;
}
Q4. 출력 결과는?
① 100
② 컴파일 에러
③ 쓰레기 값
④ 구조체는 중첩 사용 불가
p->in는 구조체. 사용 가능: p->in.x정답: ①
| 문제 | 포인트 | 정답 |
|---|---|---|
| 1 | 포인터는 ->, 변수는 . | ② |
| 2 | 배열 포인터 연산 | ① |
| 3 | NULL 포인터 접근 | ③ |
| 4 | 중첩 구조체 멤버 접근 | ① |
좋아! 아래부터 하나씩 주제별로 C 언어 구조체 트랩 문제 + 해설을 제공할게. 기본기를 시험하면서도 틀리기 쉬운 포인트들을 짚어줄게.
#include <stdio.h>
typedef struct {
int value;
} Box;
void modify(Box b) {
b.value = 99;
}
int main() {
Box a = {10};
modify(a);
printf("%d\n", a.value);
return 0;
}
Q1. 출력 결과는?
① 10
② 99
③ 컴파일 에러
④ 쓰레기 값
modify()는 구조체를 값으로 전달b는 복사본 → 원본 a는 영향을 받지 않음✅ 수정하려면 포인터로 전달해야 함:
void modify(Box* b) {
b->value = 99;
}
modify(&a);
정답: ①
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[10];
} Student;
int main() {
Student* s = malloc(sizeof(Student));
s->id = 1;
strcpy(s->name, "Alex");
printf("%s\n", (*s).name);
return 0;
}
Q2. 출력 결과는?
① Alex
② 쓰레기 값
③ 컴파일 에러
④ Segmentation fault
Student* s = malloc(sizeof(Student)) → OKs->id, (*s).name 모두 올바른 접근strcpy() 사용 가능 (헤더 <string.h> 빠졌지만 컴파일 되긴 함)정답: ①
하지만 실제 시험이라면
#include <string.h>안 쓰면 감점 가능함!
#include <stdio.h>
typedef struct {
int score;
} Test;
int main() {
Test arr[3] = {{10}, {20}, {30}};
Test* p = arr;
printf("%d\n", (p+2)->score);
return 0;
}
Q3. 출력 결과는?
① 10
② 20
③ 30
④ 컴파일 에러
p = arr → 배열 첫 주소(p + 2)->score → arr[2].score → 30정답: ③
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* name;
} User;
int main() {
User u;
u.name = malloc(10);
strcpy(u.name, "Bob");
printf("%s\n", u.name);
free(u.name);
return 0;
}
Q4. 출력 결과는?
① Bob
② 쓰레기 값
③ 컴파일 에러
④ Segmentation fault
malloc(10)으로 메모리 확보strcpy()로 문자열 복사정답: ①
보너스 트랩
다음과 같이 쓰면 안 됨:
User u;
strcpy(u.name, "Bob"); // ❌ name이 아무 것도 안 가리킴 (Segfault)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* data;
} Info;
int main() {
Info a;
a.data = malloc(10);
strcpy(a.data, "hi");
Info b = a;
strcpy(b.data, "bye");
printf("a: %s\n", a.data);
printf("b: %s\n", b.data);
return 0;
}
Q5. 출력 결과는?
①
a: hi
b: bye
②
a: bye
b: bye
③
a: hi
b: hi
④ 컴파일 에러
Info b = a;는 얕은 복사 (shallow copy)b.data와 a.data는 같은 포인터 가리킴b.data를 바꾸면 a.data도 바뀜정답: ②
깊은 복사를 원한다면 포인터가 가리키는 내용을 새로
malloc하고 복사해야 함
| 문제 | 주제 | 트랩 포인트 | 정답 |
|---|---|---|---|
| Q1 | 구조체 함수 매개변수 | 값 전달 vs 포인터 전달 | ① |
| Q2 | malloc 구조체 | 포인터로 구조체 멤버 접근 | ① |
| Q3 | 배열 포인터 연산 | 인덱싱과 -> 혼동 | ③ |
| Q4 | 포인터 멤버 | 메모리 할당 여부 | ① |
| Q5 | 얕은 복사 | 복사 후 하나만 수정해도 같이 바뀜 | ② |
좋아! 지금부터 네가 요청한 주제별로 C언어 구조체 고급 트랩 문제 + 풀이 + 해설을 차례로 제공할게. 실기 문제에서 혼동하기 쉬운 포인트들을 중심으로 문제를 구성할게.
struct + realloc() 동적 배열 재할당 트랩#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
} Item;
int main() {
int n = 2;
Item* arr = malloc(n * sizeof(Item));
arr[0].id = 1;
arr[1].id = 2;
n = 4;
arr = realloc(arr, n * sizeof(Item));
arr[2].id = 3;
arr[3].id = 4;
for (int i = 0; i < n; i++) {
printf("%d ", arr[i].id);
}
free(arr);
return 0;
}
Q1. 출력 결과는?
① 1 2 3 4
② 3 4 0 0
③ Segmentation Fault
④ 컴파일 에러
realloc()은 기존 포인터를 기반으로 크기를 늘리는 함수id를 직접 채우기 때문에 안전arr[2].id = 3; arr[3].id = 4; → OK정답: ①
주의 포인트:
realloc() 실패하면 NULL 반환하므로 실제로는 tmp에 받았다가 성공 여부 확인하는 게 안전함!#include <stdio.h>
#include <stdlib.h>
typedef struct {
int val;
} Data;
int main() {
Data* arr[2];
for (int i = 0; i < 2; i++) {
arr[i] = malloc(sizeof(Data));
arr[i]->val = i + 1;
}
printf("%d %d\n", arr[0]->val, arr[1]->val);
return 0;
}
Q2. 출력 결과는?
① 1 2
② 쓰레기 값
③ 컴파일 에러
④ Segmentation fault
Data* arr[2] → 구조체 포인터 배열malloc() 필요함arr[i]->val = i + 1 → 정상정답: ①
📌 트랩 구별 요약:
| 선언 | 의미 |
|---|---|
Data arr[2]; | 구조체 배열 |
Data* arr[2]; | 구조체 포인터 배열 |
Data (*arr)[2]; | 구조체 배열을 가리키는 포인터 (복잡한 문법) |
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int age;
} Person;
int compare(const void* a, const void* b) {
Person* p1 = (Person*)a;
Person* p2 = (Person*)b;
return p1->age - p2->age;
}
int main() {
Person arr[3] = {{30}, {10}, {20}};
qsort(arr, 3, sizeof(Person), compare);
for (int i = 0; i < 3; i++) {
printf("%d ", arr[i].age);
}
return 0;
}
Q3. 출력 결과는?
① 30 10 20
② 10 20 30
③ 20 10 30
④ 컴파일 에러
qsort()는 void 포인터 기반 정렬 함수compare()에서 정수 비교: p1->age - p2->age → 오름차순 정렬10 20 30qsort()는 어떤 타입의 배열이든 정렬할 수 있어야 하므로,
모든 타입을 받을 수 있게 void*로 전달합니다.
그래서 타입 정보를 잃었기 때문에, 우리가 직접 캐스팅해야 함.
| 항목 | 의미 |
| ------------------------------------------------------------ | ------------------------------------- |
| compare | 비교 함수의 “주소”를 넘긴 것 (함수 포인터) |
| a, b | qsort가 내부에서 전달하는 “배열 원소의 주소” |
| arr, 3, sizeof(Person) | compare의 매개변수가 아님. qsort가 사용하는 배열 정보. |
| 결과적으로 compare() 안의 a, b는 arr[i], arr[j]의 주소가 들어온다. | |
#include <stdio.h>
typedef struct {
int a;
void (*print)(int);
} Node;
void show(int x) {
printf("value: %d\n", x);
}
int main() {
Node n;
n.a = 100;
n.print = show;
n.print(n.a);
return 0;
}
Q4. 출력 결과는?
① value: 100
② 쓰레기 값
③ 컴파일 에러
④ Segmentation fault
n.print = show; → 함수 포인터에 함수 할당n.print(n.a); → 함수 호출됨정답: ①
✅ 주의 포인트: 함수 포인터 타입이 정확해야 함!
void (*print)(int); // OK
int (*print)(int); // ❌ 타입 다르면 컴파일 에러
| 문제 | 주제 | 핵심 트랩 | 정답 |
|---|---|---|---|
| Q1 | realloc | 재할당 후 접근 | ① |
| Q2 | 포인터 배열 | 각 요소에 malloc 필요 | ① |
| Q3 | 구조체 정렬 | qsort + compare 정확성 | ② |
| Q4 | 함수 포인터 | 구조체 멤버에서 함수 호출 | ① |