Skip to Content
독학사독학사 2단계C프로그래밍24. 독학사 C프로그래밍 기출·유형 ③ (구조체·파일·동적 메모리)

이 편은 실제 기출 문제가 아닙니다. 독학사 2단계 C프로그래밍 관련 reference/ 기출 원문은 확보되어 있지 않습니다. 아래 22개 문항은 국가평생교육진흥원 독학학위제 출제기준(평가영역) 중 “구조체·공용체·열거형”, “파일 입출력”, “동적 메모리 관리” 영역의 세부 항목을 근거로 새로 구성한 예상 문항입니다. 실제 시험의 문장·코드·보기 배열과 다를 수 있으므로, 코드를 암기하기보다 한 줄씩 실행을 추적하는 방법 자체를 익히는 데 써야 합니다.

회차별 실제 출제 문항 수·배점·시간은 매 공고마다 다를 수 있으므로, 응시 전 국가평생교육진흥원 공고 원문을 반드시 확인하십시오.

이 편이 다루는 범위와 접근법

이 편은 14편(구조체·공용체·열거형), 16편(파일 입출력), 17편(동적 메모리 할당), 18편(구조체·포인터·파일 통합)에서 다룬 내용을 하나로 묶어 문제 형태로 점검합니다. 이 세 영역은 독학사 C프로그래밍에서 가장 배점이 크고 실수가 잦은 구간이며, 크게 세 가지 문제 유형으로 나뉩니다.

  1. 출력 예측형 — 구조체 멤버 접근, 공용체의 메모리 공유, 파일에 쓰고 다시 읽는 코드, malloc으로 할당한 배열을 다루는 코드의 실행 결과를 정확히 추적하는 유형입니다. 반드시 변수 값이 한 줄씩 어떻게 바뀌는지 표를 그려 가며 확인해야 합니다.
  2. 오류 찾기형 — free 이후 포인터 사용(댕글링 포인터), free를 두 번 호출(이중 해제), malloc 이후 반환값을 확인하지 않는 코드, realloc 실패를 처리하지 않는 코드처럼 컴파일은 되지만 실행 시점에 위험한 코드를 찾는 유형입니다.
  3. 개념 비교형 — 구조체와 공용체의 차이, malloc과 calloc의 차이, 텍스트 모드와 이진 모드의 차이처럼 “겉보기에 비슷하지만 목적이 다른 개념 쌍”을 정확히 구분하는 유형입니다.

풀 때는 항상 다음 순서를 지키십시오. 먼저 코드에 등장하는 변수와 포인터를 나열하고, 한 줄씩 실행하면서 값이 바뀌는 시점을 적습니다. 구조체·공용체는 멤버가 메모리의 어느 위치에 자리 잡는지 머릿속으로(또는 표로) 그려 보고, 포인터가 나오면 “이 포인터가 지금 가리키는 대상이 유효한가”를 항상 확인하는 습관을 들이십시오. 해설은 정답 근거뿐 아니라 각 오답이 어떤 개념과 착각되어 나온 오답인지까지 적어 두었으니, 틀린 문항은 해당 개념이 다뤄진 14·16·17·18편으로 돌아가 다시 확인하십시오.

마무리 복습

유형 1 — 구조체 정의·멤버 접근·메모리 배치

이 유형은 이렇게 접근한다: 구조체(struct)는 서로 다른 자료형을 하나로 묶어 새 자료형을 만들지만, 멤버들이 메모리에 차례로 놓일 때 자료형별 정렬(alignment) 규칙 때문에 패딩(padding) 이라는 빈 바이트가 끼어들 수 있습니다. 그래서 구조체의 크기는 “멤버 크기의 단순 합”이 아니라 “정렬 규칙까지 반영한 합”입니다.

문제 14지선다
구조체(struct)에 대한 설명으로 옳지 않은 것은?

다음 코드로 구조체 포인터의 두 접근 방식을 확인해 보겠습니다.

#include <stdio.h> struct Point { int x; int y; }; int main(void) { struct Point p1 = {3, 4}; struct Point *pp = &p1; pp->x = pp->x + 10; (*pp).y = (*pp).y * 2; printf("%d %d\n", p1.x, p1.y); return 0; }
13 8
문제 24지선다
위 프로그램의 실행 결과로 옳은 것은?
#include <stdio.h> struct Sample { char c; int i; char c2; }; int main(void) { printf("%d\n", (int)sizeof(struct Sample)); return 0; }
문제 34지선다
int가 4바이트이고 구조체 멤버가 자신의 크기에 맞는 배수 위치에서 시작하도록 정렬되는 일반적인 환경을 기준으로, 위 프로그램의 실행 결과로 가장 적절한 것은?

유형 2 — 공용체·열거형

이 유형은 이렇게 접근한다: 공용체(union)는 모든 멤버가 같은 메모리 주소를 공유합니다. 그래서 한 멤버에 값을 쓰면 다른 멤버로 읽을 때 그 비트 패턴을 다른 자료형으로 재해석한 값이 나옵니다. 열거형(enum)은 이름 붙인 정수 상수의 모음이며, 값을 명시하지 않은 멤버는 바로 앞 멤버보다 1 큰 값을 자동으로 받습니다.

#include <stdio.h> union Data { int i; char c[4]; }; int main(void) { union Data d; d.i = 65; printf("%d %c\n", d.i, d.c[0]); return 0; }
문제 44지선다
리틀 엔디안(little-endian, 정수의 최하위 바이트가 가장 낮은 주소에 저장되는 방식) 시스템을 기준으로, 위 프로그램의 실행 결과로 가장 적절한 것은?
#include <stdio.h> enum Weekday { MON, TUE, WED, THU, FRI, SAT = 10, SUN }; int main(void) { printf("%d %d %d\n", WED, SAT, SUN); return 0; }
문제 54지선다
위 프로그램의 실행 결과로 옳은 것은?
문제 64지선다
구조체(struct)와 공용체(union)의 차이에 대한 설명으로 옳지 않은 것은?

유형 3 — 구조체 배열·포인터·함수 인자

이 유형은 이렇게 접근한다: 구조체를 함수 인자로 넘길 때 아무 표시 없이 그냥 넘기면 구조체 전체가 복사되어 함수 안에서 값을 바꿔도 원본은 그대로입니다. 원본을 바꾸려면 반드시 구조체의 주소(포인터)를 넘겨야 합니다.

#include <stdio.h> struct Student { char name[10]; int score; }; int main(void) { struct Student list[3] = { {"Kim", 80}, {"Lee", 90}, {"Park", 70} }; int sum = 0; for (int i = 0; i < 3; i++) { sum += list[i].score; } printf("%d\n", sum); return 0; }
문제 74지선다
위 프로그램의 실행 결과로 옳은 것은?
#include <stdio.h> struct Point { int x, y; }; int main(void) { struct Point arr[3] = {{1, 1}, {2, 2}, {3, 3}}; struct Point *p = arr; p++; p->x += 10; printf("%d %d %d\n", arr[0].x, arr[1].x, arr[2].x); return 0; }
문제 84지선다
위 프로그램의 실행 결과로 옳은 것은?
#include <stdio.h> struct Point { int x, y; }; void moveByValue(struct Point p) { p.x += 100; } int main(void) { struct Point a = {1, 2}; moveByValue(a); printf("%d\n", a.x); return 0; }
문제 94지선다
위 프로그램을 실행하면 101이 아니라 1이 출력된다. 그 이유로 가장 적절한 것은?

유형 4 — 파일 입출력 기초

이 유형은 이렇게 접근한다: fopen은 모드 문자열에 따라 동작이 크게 달라집니다. “r”은 파일이 반드시 있어야 하고, “w”는 있어도 내용을 지우며, “a”는 없으면 만들고 있으면 끝에 이어 씁니다. 파일을 다루는 모든 코드는 fopen이 NULL을 반환할 가능성을 먼저 의심해야 합니다.

문제 104지선다
fopen 함수의 파일 열기 모드에 대한 설명으로 옳지 않은 것은?
#include <stdio.h> int main(void) { FILE *fp = fopen("data.txt", "w"); fprintf(fp, "%d %d\n", 3, 5); fclose(fp); int a, b; fp = fopen("data.txt", "r"); fscanf(fp, "%d %d", &a, &b); fclose(fp); printf("%d\n", a + b); return 0; }
문제 114지선다
위 프로그램(파일 생성이 정상적으로 이루어졌다고 가정)의 실행 결과로 옳은 것은?
#include <stdio.h> int main(void) { FILE *fp = fopen("not_exist.txt", "r"); char buf[100]; fscanf(fp, "%s", buf); fclose(fp); return 0; }
문제 124지선다
not_exist.txt 파일이 실제로 존재하지 않는다고 할 때, 이 프로그램이 실행 중 비정상 종료될 가능성이 높은 이유로 가장 적절한 것은?

유형 5 — 파일 입출력 심화(이진 파일)

이 유형은 이렇게 접근한다: 구조체나 실수처럼 이진 데이터를 있는 그대로 저장·복원하려면 텍스트 모드가 아니라 이진 모드(“b” 포함) 로 파일을 열고, fscanf·fprintf 대신 fread·fwrite 를 써야 합니다.

#include <stdio.h> struct Item { int id; double price; }; int main(void) { struct Item a = {1, 1000.0}; FILE *fp = fopen("item.bin", "wb"); fwrite(&a, sizeof(struct Item), 1, fp); fclose(fp); struct Item b; fp = fopen("item.bin", "rb"); fread(&b, sizeof(struct Item), 1, fp); fclose(fp); printf("%d %.1f\n", b.id, b.price); return 0; }
문제 134지선다
파일 생성이 정상적으로 이루어졌다고 가정할 때, 위 프로그램의 실행 결과로 옳은 것은?
문제 144지선다
텍스트 모드와 이진 모드로 파일을 다루는 것에 대한 설명으로 옳지 않은 것은?
문제 154지선다
파일 위치 지시자(file position indicator)를 다루는 함수에 대한 설명으로 옳지 않은 것은?

유형 6 — 동적 메모리 할당: malloc·calloc·realloc

이 유형은 이렇게 접근한다: malloc은 요청한 크기만큼 힙(heap) 메모리를 할당하지만 내용을 초기화하지 않고, calloc은 할당과 동시에 모든 바이트를 0으로 채웁니다. realloc은 기존 데이터를 보존한 채 크기만 조정합니다.

문제 164지선다
malloc과 calloc의 차이에 대한 설명으로 옳지 않은 것은?
#include <stdio.h> #include <stdlib.h> int main(void) { int n = 5; int *arr = (int *)malloc(n * sizeof(int)); for (int i = 0; i < n; i++) { arr[i] = i * i; } int sum = 0; for (int i = 0; i < n; i++) { sum += arr[i]; } printf("%d\n", sum); free(arr); return 0; }
문제 174지선다
위 프로그램의 실행 결과로 옳은 것은?
#include <stdio.h> #include <stdlib.h> int main(void) { int *arr = (int *)malloc(3 * sizeof(int)); arr[0] = 1; arr[1] = 2; arr[2] = 3; arr = (int *)realloc(arr, 5 * sizeof(int)); arr[3] = 4; arr[4] = 5; int sum = 0; for (int i = 0; i < 5; i++) sum += arr[i]; printf("%d\n", sum); free(arr); return 0; }
문제 184지선다
위 프로그램의 실행 결과로 옳은 것은?
#include <stdio.h> #include <stdlib.h> int main(void) { int *p = (int *)malloc(sizeof(int)); *p = 10; free(p); printf("%d\n", *p); return 0; }
문제 194지선다
위 코드의 문제점으로 가장 적절한 것은?

유형 7 — 동적 메모리 오류: 누수·이중 해제·댕글링 포인터

이 유형은 이렇게 접근한다: 컴파일은 되지만 실행 시점에 위험한 코드를 찾는 문제입니다. “할당한 메모리를 되찾을 방법이 사라졌는가(누수)”, “이미 해제한 메모리를 또 해제하는가(이중 해제)”, “이미 사라진 지역 변수의 주소를 계속 쓰는가(댕글링)“를 순서대로 점검하십시오.

#include <stdio.h> #include <stdlib.h> void makeArray(int n) { int *arr = (int *)malloc(n * sizeof(int)); for (int i = 0; i < n; i++) { arr[i] = i; } printf("%d\n", arr[0]); } int main(void) { makeArray(5); return 0; }
문제 204지선다
이 프로그램의 문제점으로 가장 적절한 것은?
#include <stdio.h> int *makePointer(void) { int local = 42; return &local; } int main(void) { int *p = makePointer(); printf("%d\n", *p); return 0; }
문제 214지선다
이 프로그램에 내재된 문제점으로 가장 적절한 것은?
#include <stdlib.h> int main(void) { int *p = (int *)malloc(sizeof(int)); *p = 1; free(p); free(p); return 0; }
문제 224지선다
이 프로그램의 문제점으로 가장 적절한 것은?

참고 자료

Last updated on