구조체 연습

류한선·2025년 7월 4일

실기연습-2

목록 보기
82/95

좋아! C언어에서 -> 연산자는 구조체 포인터가 가리키는 멤버에 접근할 때 사용하는 연산자야. 이걸 헷갈리게 하는 문제들도 정보처리기사 실기나 C언어 시험에서 자주 나오는 트랩 포인트야.


✅ 핵심 개념: ->. 차이

표현사용 조건의미
a.b구조체 변수구조체의 멤버 접근
a->b구조체 포인터포인터가 가리키는 구조체의 멤버 접근

즉, .는 변수일 때, ->는 포인터일 때 써야 함.


✅ 문제 1. 구조체 포인터 연산자 트랩

#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

정답: ② 컴파일 에러


✅ 문제 2. 구조체 배열과 포인터 접근 혼동

#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->agearr[0].age = 20
  • (ptr + 1)->agearr[1].age = 25

정답: ①


✅ 문제 3. 구조체 포인터 NULL 참조 트랩

#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
  • 포인터가 아무 것도 가리키지 않을 때 -> 사용하면 터짐

정답: ③


✅ 문제 4. 구조체 안에 구조체가 있는 경우

#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배열 포인터 연산
3NULL 포인터 접근
4중첩 구조체 멤버 접근

좋아! 아래부터 하나씩 주제별로 C 언어 구조체 트랩 문제 + 해설을 제공할게. 기본기를 시험하면서도 틀리기 쉬운 포인트들을 짚어줄게.


✅ 1. 구조체 포인터와 함수 매개변수 트랩(체크)

#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);

정답: ①


✅ 2. malloc + 구조체 포인터 조합

#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)) → OK
  • s->id, (*s).name 모두 올바른 접근
  • strcpy() 사용 가능 (헤더 <string.h> 빠졌지만 컴파일 되긴 함)

정답: ①

하지만 실제 시험이라면 #include <string.h> 안 쓰면 감점 가능함!


✅ 3. 구조체 배열 + 포인터 연산 심화

#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)->scorearr[2].score → 30

정답: ③


✅ 4. 구조체 내 포인터 멤버 (문자열, 동적 배열) (주의)

#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)

✅ 5. 구조체 트랩 (shallow copy vs deep copy) (주의)

#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.dataa.data같은 포인터 가리킴
  • 따라서 b.data를 바꾸면 a.data도 바뀜

정답: ②

깊은 복사를 원한다면 포인터가 가리키는 내용을 새로 malloc하고 복사해야 함


🔁 요약

문제주제트랩 포인트정답
Q1구조체 함수 매개변수값 전달 vs 포인터 전달
Q2malloc 구조체포인터로 구조체 멤버 접근
Q3배열 포인터 연산인덱싱과 -> 혼동
Q4포인터 멤버메모리 할당 여부
Q5얕은 복사복사 후 하나만 수정해도 같이 바뀜

좋아! 지금부터 네가 요청한 주제별로 C언어 구조체 고급 트랩 문제 + 풀이 + 해설을 차례로 제공할게. 실기 문제에서 혼동하기 쉬운 포인트들을 중심으로 문제를 구성할게.


✅ 1. 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에 받았다가 성공 여부 확인하는 게 안전함!

✅ 2. 구조체 포인터 배열 vs 배열 구조체 포인터 트랩

#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];구조체 배열을 가리키는 포인터 (복잡한 문법)

✅ 3. 구조체 정렬 (qsort + comparator) (주의)

#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 30
    const void a, const void b

qsort()는 어떤 타입의 배열이든 정렬할 수 있어야 하므로,
모든 타입을 받을 수 있게 void*로 전달합니다.
그래서 타입 정보를 잃었기 때문에, 우리가 직접 캐스팅해야 함.
| 항목 | 의미 |
| ------------------------------------------------------------ | ------------------------------------- |
| compare | 비교 함수의 “주소”를 넘긴 것 (함수 포인터) |
| a, b | qsort가 내부에서 전달하는 “배열 원소의 주소” |
| arr, 3, sizeof(Person) | compare의 매개변수가 아님. qsort가 사용하는 배열 정보. |
| 결과적으로 compare() 안의 a, barr[i], arr[j]의 주소가 들어온다. | |


✅ 4. 구조체 내 함수 포인터 사용(체크)

#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);   // ❌ 타입 다르면 컴파일 에러

🔁 요약

문제주제핵심 트랩정답
Q1realloc재할당 후 접근
Q2포인터 배열각 요소에 malloc 필요
Q3구조체 정렬qsort + compare 정확성
Q4함수 포인터구조체 멤버에서 함수 호출

0개의 댓글