글자는 숫자이고, 구조체는 칸의 묶음이고, 재귀는 되감기다. 세 원리로 C 기출 16문항이 풀린다
왜 이걸 하나 — C 42문항 중 16문항이 이 장이고, 2025년에는 세 회 연속 연결 리스트가 나왔다.
11회분 220문항 중 이 장의 기출은 16문항이다. 11회 중 10회에 나왔고(2023년 2회만 빠짐), 2025년 2회에는 4문항(환형 큐 · 이중 포인터 구조체 · 연결 리스트 · 동적 문자열 역순)이 몰렸다. 훈련 C 10문항(7~13 · 17~19)이 붙는다.
| 꼴 | 몇 문항 | 무엇을 적나 | 보기 |
|---|---|---|---|
| 문자열 · 문자 코드 | 5 | 글자 순회 · 대소문자 변환 · 역순 · 시저 암호 | 2023-1회 3번 · 2024-1회 4번 · 19번 · 2025-2회 18번 · 2025-3회 7번 |
| 구조체 값 계산 | 4 | 멤버 접근 · 화살표 · 배열 구조체 · 함수 포인터 멤버 | 2023-3회 4번 · 2024-1회 11번 · 2024-2회 19번 · 2026-1회 8번 |
| 연결 리스트 · 큐 | 5 | 순회 출력 · 교환 · 환형 큐 · 이중 포인터 | 2024-3회 12번 · 2025-1회 18번 · 2025-2회 12번 · 14번 · 16번 |
| 재귀 · 트리 | 2 | 팩토리얼 · 후위 순회 세 번째 노드 | 2023-3회 15번 · 2026-2회 7번 |
→ 연결 리스트가 5문항이다. 2024년 3회부터 2025년 2회까지 세 회 연속이었고, 2026년 2회 7번의 트리도 구조체 포인터 둘(a · b)이 자식을 가리키는 같은 꼴이다. 노드를 그리고 화살표를 따라가는 절차 하나로 여섯 문항이 풀린다.
E01 진단의 7번(트리 후위 순회, 답 12)이 이 장이다. 「재귀」와 「구조체 포인터」가 한 문제에 있어 어렵게 보이지만, 03절의 되감기 표와 화살표 그림을 합치면 순서가 하나로 정해진다.
문항 수는 이 노트의 문제 데이터에서 ch=E03 인 것을 센 값이다(2026-09-14). 기출 코드는 grandlife.co.kr 복원에서 옮겼고, 16문항 전부 gcc(도커 alpine)로 실행해 정답을 확인했다.
왜 이걸 하나 — 시험 전날 규칙 8개를 다시 본다.
c + 1 은 다음 글자, c - 'a' 는 알파벳 몇 번째. %c 로 찍으면 글자, %d 로 찍으면 숫자.\0 이 끝. while (s[i] != '\0') · while (*p) 가 끝까지 순회. strlen 은 \0 앞까지 개수, sizeof 는 \0 포함 바이트.strcpy(a, b) 복사 · strcat(a, b) 이어 붙임 · strcmp(a, b) 같으면 0, 앞이 크면 양수 · strlen 길이 · toupper · tolower · isalpha · isdigit.s.member, 포인터면 p->member(= (*p).member). typedef struct { … } Name; 로 이름을 만든다. 구조체 배열은 arr[i].member.next). 순회는 for (p = head; p != NULL; p = p->next). 삽입 · 교환은 화살표를 다시 잇는 것. malloc 으로 노드를 만들면 free 로 돌려준다.(x + 1) % SIZE 로 돈다. 넣으면 rear 가, 꺼내면 front 가 움직인다. 두 값을 매 연산마다 적는다.if (n <= 1) return …)까지 내려간 뒤 되감으며 계산. 표를 아래(가장 깊은 호출)부터 채운다. 팩토리얼 · 피보나치 · 자릿수 합 · 트리 순회.func(n->a); func(n->b); 뒤에 자기 처리가 있으면 후위다.왜 이걸 하나 — 세 원리가 왜 그런지를 알면, 함수 이름이 낯설어도 코드가 무엇을 하는지 읽힌다.
C 의 char 는 8비트 정수다. 'A' 는 65, 'a' 는 97, '0' 은 48 이고 그 차이가 규칙을 만든다. 대문자에 32 를 더하면 소문자, c - '0' 은 글자 숫자를 진짜 숫자로, c + 3 은 알파벳 세 칸 뒤다. 2024년 1회 19번의 시저 암호가 이 덧셈이고, 범위를 넘으면 % 26 으로 돌린다.
순회는 \0 을 만날 때까지다. while (s[i] != '\0') 든 while (*p) 든 같은 뜻이고, 2023년 1회 3번은 두 문자열을 이중 반복문으로 대조해 있는 글자만(qwe) 찍는다. 2024년 1회 4번은 마지막 첨자부터 두 칸씩 건너뛰어(6 · 4 · 2 · 0) GECA 를 만든다 — 첨자를 종이에 0 1 2 … 로 적고 조건을 대 보면 된다.
역순 출력은 두 가지 꼴로 나온다. 첨자를 len - 1 부터 내려오거나(훈련 8번), malloc 으로 새 칸을 잡아 거꾸로 복사하거나(2025년 2회 18번, TSEB). 어느 쪽이든 strlen 으로 길이를 먼저 재고 마지막 첨자가 len − 1 이라는 것이 출발점이다.
struct Item { int price; int count; }; 는 두 칸을 한 묶음으로 만든 새 자료형이다. 변수면 item.price 로, 포인터면 p->price 로 칸을 연다 — 화살표는 (*p).price 의 줄임이고, 2023년 3회 4번의 빈칸이 바로 -> 다. 2024년 1회 11번은 구조체의 잔액에서 100 을 빼고 1.1 을 세 번 곱해 %.2f 로 2795.10 을 찍으므로 소수 둘째 자리까지 그대로 적는다.
2026년 1회 8번은 구조체 멤버가 함수 포인터다. int *(*fn)(int *) 는 「int 포인터를 받아 int 포인터를 돌려주는 함수」를 가리키는 포인터이고, s.fn(&x) 로 부른다. 선언이 낯설어도 괄호 안의 * 가 함수 포인터, 밖의 것이 반환형으로 읽으면 된다.
노드는 값 하나와 next 주소 하나로 된 구조체다. 순회는 head 에서 시작해 p = p->next 로 화살표를 따라가다 NULL 에서 멈춘다. 2025년 1회 18번은 노드 5개를 잇고 순회해 35421 을 찍는데, 이어 붙인 순서와 값의 순서가 다르다는 것이 함정이다 — 코드가 next 를 어디에 꽂는지를 그림에 그려야 한다.
교환 문제(2024년 3회 12번, 312)는 값을 바꾸는지 화살표를 바꾸는지를 먼저 본다. 값을 바꾸면 노드는 그대로이고 값만 오가고, 화살표를 바꾸면 노드의 순서가 바뀐다. 2025년 2회 16번(3 1 2)은 화살표를 두 번 다시 이은 뒤 head 를 c 로 잡는 꼴이라, 마지막에 이은 화살표가 순서를 정한다.
환형 큐(2025년 2회 12번, 2 그리고 3)는 배열에 front · rear 두 첨자를 두고 (x + 1) % SIZE 로 돌린다. 넣을 때 rear 가, 꺼낼 때 front 가 움직이므로 연산마다 두 값을 표로 적으면 무엇이 남는지 보인다. 이중 포인터 구조체(2025년 2회 14번, 5 그리고 6)는 **pp 가 「포인터의 포인터」라 두 번 따라가 원본 구조체에 닿는다.
재귀 함수는 자기를 부르며 내려가다 종료 조건에서 멈추고, 거기서부터 값을 돌려주며 되감는다. 표를 아래부터 채운다 — factorial(1) = 1, (2) = 2, (3) = 6 … (7) = 5040(2023년 3회 15번). 자릿수 합(예상 1회 3번)은 n % 10 + f(n / 10) 로 뒤 자리부터 더한다.
트리 순회는 재귀와 구조체 포인터가 합쳐진 것이다. 2026년 2회 7번의 func(n->a); func(n->b); if (++c == 3) result = n->v; 는 왼쪽 → 오른쪽 → 자기 순서라 후위 순회이고, 방문 순서 35 → 53 → 12 → 64 → 21 에서 세 번째인 12 가 답이다. 자기 처리가 두 재귀 호출 앞에 있으면 전위, 사이에 있으면 중위다.
. 과 -> 를 가르고 구조체 멤버 값을 계산한다. 셋째, 연결 리스트 · 환형 큐를 그림과 표로 순회한다. 넷째, 재귀를 되감기 표로 계산하고 트리 순회 3종을 코드에서 구분한다. 기출 16문항이 이 넷 안에 있다.왜 이걸 하나 — 그림(노드 · 화살표)과 표(재귀 되감기)를 종이에 그리며 푸는 연습이다.
문자열 문제는 첨자를 0 부터 적어 두고, 구조체 · 리스트는 노드를 상자로 그려 화살표를 잇고, 재귀는 아래부터 표를 채운다. 세 가지 종이 도구가 이 장의 답이다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — qwe. 왼쪽 문자열의 글자를 하나씩 들고 오른쪽 문자열 전체와 견주어, 같은 글자를 만날 때마다 그 글자를 찍는다.
원리 — 이중 for 문은 "바깥 글자 하나마다 안쪽 문자열을 처음부터 끝까지 훑는다"는 뜻이다. 바깥은 left 의 q · w · e · r 네 글자, 안쪽은 right 의 q · w · t · e · t · y 여섯 글자라 비교는 4 × 6 = 24번 일어난다. 그중 두 글자가 같은 순간에만 printf 가 돈다. 그러니 답은 "left 의 글자 중 right 에도 있는 것"을 left 순서대로, 그리고 right 에 그 글자가 여러 번 있으면 그 횟수만큼 찍은 것이다. '\0' 은 문자열 끝표라 거기서 각 반복이 멈춘다.
따라가기
헷갈리는 자리 — right 에 t 가 두 개라 t 를 두 번 적는 것. t 는 left 에 없으므로 바깥 반복이 t 를 들고 오는 일이 없다. 찍히는 글자는 언제나 left 쪽 순서이고, 중복 횟수는 right 쪽 개수를 따른다는 두 규칙을 나눠 기억한다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 코드에서 구조체 포인터가 멤버에 접근하도록 ①에 들어갈 기호를 쓰시오.
답 — ->. 포인터를 거쳐 구조체의 멤버로 들어갈 때 쓰는 화살표다.
원리 — 구조체 변수에 바로 붙을 때는 점(data.score)을 쓴다. 그런데 pointer 는 구조체가 아니라 구조체의 주소를 적은 쪽지라, 먼저 쪽지를 따라가서 구조체를 연 다음(*pointer) 점을 붙여야 한다. 그 두 동작 (*pointer).score 를 한 글자로 줄인 것이 pointer->score 다. 화살표는 "따라가서 그 안의"라고 읽는다. 괄호가 필요한 이유는 점이 별표보다 먼저 붙어 *pointer.score 가 "pointer.score 를 연다"로 읽히기 때문이다.
따라가기
struct Member data = {90} — data.score = 90pointer = &data — pointer 는 data 의 주소pointer->score → data.score → 90 이 찍힌다헷갈리는 자리 — 답 칸에 점을 적는 것. 점은 구조체 변수 자체에만 붙고 포인터에는 못 붙는다(컴파일 오류). (*pointer).score 도 뜻은 같지만 문제는 "기호 하나"를 물었으므로 화살표만 적는다. 화살표는 빼기와 부등호를 붙여 쓰며 사이에 띄어쓰기가 없다.
빈칸에 답을 넣어 gcc(도커 alpine)로 컴파일 · 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 5040. factorial(7) = 7 × 6 × 5 × 4 × 3 × 2 × 1 이다.
원리 — 재귀 함수는 자기 자신을 더 작은 문제로 부른다. "7 의 계승은 7 곱하기 6 의 계승"이고, "6 의 계승은 6 곱하기 5 의 계승"… 이렇게 내려가다 1 이하가 되면 더 부르지 않고 1 을 돌려준다(멈춤 조건). 그다음은 돌아오는 길이다 — 안쪽에서 돌려받은 값에 자기 수를 곱해 위로 올린다. 재귀는 "내려갈 때는 아무것도 계산하지 않고, 바닥에 닿은 뒤 올라오면서 곱한다"고 보면 값이 틀리지 않는다.
따라가기
헷갈리는 자리 — 멈춤 조건이 number <= 1 이라 factorial(0) 도 1 이고, 1 을 곱하는 단계가 하나 더 있다고 생각해 두 번 곱하는 것. 곱은 7 부터 2 까지 여섯 번이다. 계승은 빨리 커져 13! 부터는 int 를 넘치지만 7! 은 안전하다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — GECA. 마지막 글자부터 두 칸씩 건너뛰며 앞으로 온다.
원리 — strlen("ABCDEFG") 은 7 이고 첨자는 0 부터 6 까지다. 반복은 i = n - 1(6, 마지막 글자)에서 시작해 i -= 2 로 두 칸씩 줄어들며 i >= 0 인 동안 돈다. 즉 6 · 4 · 2 · 0 네 자리를 차례로 찍는다. putchar 는 글자 하나를 줄바꿈 없이 찍는 함수다. "역순 + 건너뛰기"는 시작 첨자, 감소량, 멈춤 조건 세 가지를 적어 두면 틀릴 데가 없다.
따라가기
i >= 0 거짓 → 끝. GECA헷갈리는 자리 — n 을 7 로 두고 첨자 7 부터 시작하는 것(끝표 자리라 아무것도 안 찍히거나 엉뚱한 값). 마지막 첨자는 길이 − 1 이다. 그리고 i > 0 이었다면 0 번 A 가 빠져 GEC 가 된다 — 등호 유무를 본다. putchar 는 줄바꿈을 넣지 않으므로 네 글자가 한 줄에 붙고, strlen 을 쓰려면 string.h 가 있어야 한다는 것도 시험에서 빈칸으로 나올 수 있는 자리다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 9981 and 2795.10. 잔액에서 19 를 빼고, 저축액에 3% 이자를 붙여 소수 둘째 자리까지 찍는다.
원리 — 함수에 구조체의 주소(&a)를 넘기면 함수 안에서 a->balance 처럼 원본의 칸을 직접 고칠 수 있다. 값을 넘겼다면 복사본만 바뀌어 main 의 a 는 그대로였을 것이다. a->savings *= (1.0 + rate) 는 "저축액에 1.03 을 곱해 다시 저축액에 넣어라"다. %d 는 정수를 그대로, %.2f 는 실수를 소수 둘째 자리에서 반올림해 찍는다. 문자열 안의 " and " 는 서식이 아니라 그대로 찍히는 글자다.
따라가기
%.2f → 2795.10 → 화면 9981 and 2795.10헷갈리는 자리 — 2795.1 로 적는 것. 서식이 둘째 자리까지라 끝의 0 도 적어야 한다. 이자를 더하기(2713.69 + 0.03)로 착각하는 것 — 곱셈 대입(*=)이다. 답에는 " and " 까지 문제의 출력 그대로 들어간다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — Nd sc 1. 대문자는 5칸, 소문자는 10칸, 숫자는 3칸 뒤로 미는 자리바꿈(시저 암호)이다.
원리 — 글자는 코드값이라 text[i] - 'A' 는 "A 로부터 몇 번째 글자인가"다. 거기에 밀 칸 수를 더하고 26 으로 나눈 나머지를 취하면 Z 를 넘어도 A 로 돌아온다. 마지막에 'A' + … 로 다시 글자로 만든다. 숫자도 같은 꼴로 '0' 기준 10칸이다. isupper · islower · isdigit 은 글자 종류를 가르는 함수이고, 공백은 셋 다 아니라 그대로 남는다. 세 종류가 밀리는 칸 수가 다르다는 것이 이 문제의 핵심이다.
따라가기
헷갈리는 자리 — 대문자와 소문자를 같은 5칸으로 밀어 t 를 y 로 적는 것. 조건문이 셋으로 갈라진 이유가 밀 칸 수가 다르기 때문이다. s 는 18 + 10 = 28 이 26 을 넘어 2 로 돌아온다 — 나머지 연산을 잊으면 알파벳 밖으로 나간다. 공백 두 개도 답에 그대로 있다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 20. 포인터 p 가 가리키는 구조체의 price 4 와 count 5 를 곱한다.
원리 — 구조체는 이름 붙은 칸들을 한 묶음으로 만든 것이다. {4, 5} 로 초기화하면 선언한 순서대로 price = 4, count = 5 가 들어간다. struct Item *p = &item 은 그 묶음의 주소를 p 에 적은 것이고, p->price 는 "p 를 따라가서 그 안의 price"다. 화살표 접근은 값을 복사하는 것이 아니라 원본 칸을 읽는 것이라 item.price 와 같은 값이다. 이 문제는 구조체 포인터 문법을 아는지 하나만 묻는다.
따라가기
헷갈리는 자리 — 초기화 순서를 바꿔 읽는 것(price 가 먼저 선언됐으니 4 가 price). p.price 는 컴파일 오류이고 (*p).price 는 화살표와 같다. 곱셈이라 답은 20 이지 "4 5" 가 아니다. 구조체는 배열과 달리 칸마다 이름과 자료형이 따로 있어 첨자가 아니라 이름으로 꺼낸다 — 그래서 p[0] 같은 꼴은 안 쓰고 p->price 로 쓴다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 312. 리스트가 1 → 3 → 2 순서로 이어져 있고, 앞의 두 노드 값만 맞바꾼 뒤 순서대로 찍는다.
원리 — 연결 리스트는 각 노드가 "다음 노드의 주소"를 들고 있는 사슬이다. 순서는 변수 이름(n1 · n2 · n3)이 아니라 next 가 정한다. n1.next = &n3; n3.next = &n2 이므로 사슬은 n1 → n3 → n2 → NULL 이다. swap_pairs 는 두 노드씩 짝지어 값(value)만 맞바꾸고, node = node->next->next 로 두 칸 건너뛴다. 남은 노드가 하나뿐이면(node->next == NULL) 짝이 없어 그대로 둔다. 사슬(next)은 안 바뀌고 값만 바뀐다는 것이 핵심이다.
따라가기
헷갈리는 자리 — 사슬을 n1 → n2 → n3 으로 넘겨짚고 213 이라 적는 것. 초기화의 NULL 은 나중 대입으로 덮였으니 마지막 대입 두 줄이 사슬이다. 또 "교환"을 노드 순서 교환으로 읽는 것 — 이 코드는 값만 바꾼다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 35421. 1~5 를 앞에 끼워 5 4 3 2 1 이 된 리스트에서 3 을 떼어 맨 앞에 붙인다.
원리 — push 는 새 노드를 만들어 next 를 지금의 머리에 걸고 새 노드를 머리로 돌려준다. 앞에 끼우는 방식이라 1 · 2 · 3 · 4 · 5 순으로 넣으면 5 → 4 → 3 → 2 → 1 로 거꾸로 선다. move_front 는 목표 노드를 찾을 때까지 previous(바로 앞 노드)와 current 를 나란히 옮기고, 찾으면 앞 노드의 next 를 목표의 다음으로 잇고(사슬에서 빼기), 목표의 next 를 옛 머리로 걸고(맨 앞에 끼우기), 목표를 새 머리로 삼는다. 노드를 새로 만들지 않고 화살표 두 개만 바꾼다.
따라가기
헷갈리는 자리 — push 가 뒤에 붙인다고 보고 1 2 3 4 5 에서 시작하는 것. node->next = head 가 "새 노드 뒤에 옛 머리"라 앞 끼우기다. 그리고 목표를 뺀 뒤 앞 노드(4)의 next 를 2 로 잇는 줄을 빼먹으면 4 → 3 이 남아 3 이 두 번 나온다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 2 그리고 3. 크기 3 짜리 원형 큐에 1 · 2 를 넣고 하나 빼고 3 을 넣은 뒤 두 번 꺼내면 2 와 3 이다.
원리 — 큐는 줄서기다. 뒤(rear)로 들어가 앞(front)으로 나온다. 원형 큐는 칸이 끝에 닿으면 % SIZE 로 첫 칸으로 돌아와 다시 쓴다. enqueue 는 rear 칸에 넣고 rear 를 한 칸 앞으로(3 이면 0 으로), dequeue 는 front 칸을 읽고 front 를 한 칸 앞으로 옮긴다. 값은 지우지 않아도 front 가 지나갔으니 없는 것과 같다. 넣은 순서대로 나온다(FIFO)는 것만 지키면 칸 번호는 회전판으로 따라가면 된다.
따라가기 — data[3], front = 0, rear = 0.
헷갈리는 자리 — 첫 dequeue 의 결과 1 을 first 로 적는 것. 그 값은 변수에 안 담고 버렸다. 스택으로 착각해 3 · 2 로 적는 것도 흔하다. 출력에 " 그리고 " 글자가 그대로 들어간다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 5 그리고 6. 이중 포인터를 풀면 values 그 자체라, 셋째 원소를 둘째 원소에 통째로 복사한 것이다.
원리 — pointer = values 는 배열 첫 칸의 주소, doublePointer = &pointer 는 그 쪽지의 주소다. *doublePointer 는 쪽지 pointer 를 다시 꺼낸 것이므로 values 첫 칸 주소와 같고, 거기에 [1] 을 붙이면 values[1], [2] 를 붙이면 values[2] 다. 구조체는 = 로 통째 복사가 되므로 values[1] = values[2] 는 x 와 y 를 한꺼번에 덮어쓴다. 별표가 두 개라도 "쪽지를 따라 원래 배열로 돌아온다"는 것이 전부다.
따라가기
(*doublePointer) = pointer = valuesvalues[1] = values[2] → values = [{1,2}, {5,6}, {5,6}]헷갈리는 자리 — 대입 방향을 거꾸로 읽어 values[2] 가 바뀌었다고 보는 것(3 그리고 4). 왼쪽이 바뀐다. 이중 포인터를 보고 값이 아니라 주소가 복사됐다고 넘겨짚는 것 — 대괄호가 붙는 순간 구조체 값이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 3 1 2. 마지막에 남은 화살표는 c → a → b → NULL 이고 머리가 c 다.
원리 — 연결 리스트의 순서는 오직 next 가 정하고, 같은 next 에 여러 번 대입하면 마지막 대입만 남는다. 코드가 화살표를 여섯 번 바꾸지만 노드마다 마지막 줄만 보면 된다: a.next 는 마지막에 &b, b.next 는 NULL, c.next 는 &a. 머리(head)를 c 로 잡았으니 c 에서 출발해 화살표를 따라간다. 노드가 선언된 순서(a · b · c)는 아무 상관이 없다.
따라가기
헷갈리는 자리 — 앞의 세 줄(a → b → c)만 보고 1 2 3 으로 적는 것. 뒤의 세 줄이 덮어쓴다. head->next->next->value 까지만 찍으므로 b.next 가 NULL 이어도 오류가 없다 — 네 번째를 찍었다면 NULL 을 따라가 죽는다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — TSEB. 글자를 하나씩 리스트 맨 앞에 끼우면 순서가 뒤집혀, 앞에서부터 찍으면 거꾸로 나온다.
원리 — make_list 는 문자열을 한 글자씩 읽으며 새 노드를 만들고 node->next = head; head = node 로 맨 앞에 끼운다. 첫 글자 B 가 제일 안쪽에, 마지막 글자 T 가 맨 앞에 서므로 리스트는 T → S → E → B 다. *text++ 는 "지금 글자를 읽고 나서 한 칸 옆으로"이고, while (*text) 는 끝표(0)를 만나면 멈춘다. main 은 머리부터 화살표를 따라가며 글자를 찍고 지나온 노드를 free 로 돌려준다 — 출력에는 영향이 없다.
따라가기
헷갈리는 자리 — 리스트를 "만든 순서대로" 보고 BEST 를 적는 것. 뒤에 붙이는 코드였다면 node->next = NULL 과 꼬리 포인터가 있어야 한다. 앞에 끼우기는 늘 뒤집힌다. free 뒤에 current 를 쓰지 않도록 미리 old 에 빼 두는 것도 눈여겨본다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — E. 글자 수를 센 뒤 끝에서 둘째 글자를 찍는다.
원리 — while 문은 끝표('\0')를 만날 때까지 n 을 하나씩 올리므로, 끝나면 n 은 글자 수다. "REPUBLICOFKOREA" 는 15글자라 n = 15. 첨자는 0 부터라 마지막 글자는 word[n - 1], 그 앞 글자는 word[n - 2] 다. strlen 을 직접 만든 것이라고 보면 된다. ++n 과 n++ 는 여기서 값을 쓰지 않으니 결과가 같다.
따라가기
헷갈리는 자리 — n − 2 를 "끝에서 두 번째"가 아니라 "13번째 글자"로 세다가 하나 어긋나는 것. 첨자와 순번은 1 차이다. 글자 수를 세다 하나 빠뜨리면 R 이 나온다 — REPUBLIC(8) + OF(2) + KOREA(5) = 15 로 묶어 센다. 반복이 끝난 순간 word[n] 은 끝표이므로 n 자체는 글자가 아니라는 것도 같은 함정이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램을 실행했을 때 출력되는 값을 쓰시오.
답 — 20. 함수 포인터로 dummy 를 불러 배열의 둘째 칸 주소를 받고, 그 값 32 를 16진수로 찍는다.
원리 — int *(*fn)(int *) 는 "int 포인터를 받아 int 포인터를 돌려주는 함수"를 가리키는 포인터다. 구조체 멤버 fn 에 dummy 를 넣으면 mine.fn(n) 은 dummy(n) 과 같다. dummy 는 받은 주소에 1 을 더해 돌려주므로 배열의 다음 칸(&n[1]) 주소다. 앞의 별표가 그 칸을 열어 32 가 나온다. %x 는 값을 16진수로 찍는 서식이라 32 는 0x20, 화면에는 20 이다.
따라가기
* → 32%x → 32 = 2 × 16 + 0 → 20헷갈리는 자리 — 32 를 그대로 적는 것. 서식이 %d 가 아니라 %x 다. 함수 포인터 선언이 낯설어 d + 1 을 값 17 로 읽는 것 — d 는 주소라 +1 은 한 칸 옆이다. 첫 칸 16 을 16진수로 바꾼 10 도 오답이다(dummy 가 한 칸 옮겼다).
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 12. 후위 순회(왼쪽 → 오른쪽 → 자기)에서 세 번째로 도착하는 노드가 nb 이고 그 값이 12 다.
원리 — 구조체 N 은 값 v 와 자식 두 개(a 왼쪽, b 오른쪽)를 가진 트리 노드다. na(21) 아래 nb(12) · nd(64), nb 아래 ne(35) · nc(53) 가 있다. func 는 자식 a, 자식 b 를 먼저 다 처리한 다음에 자기 차례에 ++c 를 센다 — 이것이 후위 순회다. 전역 c 는 "자기 차례가 온 횟수"이고, 그것이 3 이 되는 순간의 노드 값이 result 에 들어간다. if (!n) return 은 자식이 없을 때(0) 되돌아가는 멈춤 조건이다.
따라가기
헷갈리는 자리 — 전위 순회(자기 먼저)로 세어 세 번째를 ne(35)로 적는 것. 자기 처리(++c)가 두 재귀 호출 뒤에 있으니 후위다. c 가 3 을 지난 뒤에도 순회는 계속되지만 result 는 그대로다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 코드의 출력을 쓰시오.
답 — 10. 1234 의 각 자리 4 + 3 + 2 + 1 을 재귀로 더한 것이다.
원리 — n % 10 은 마지막 자리, n / 10 은 마지막 자리를 뗀 나머지 수다(정수 나눗셈이라 소수점이 버려진다). f(n) 은 "마지막 자리 + 나머지 수의 자릿수 합"으로 자기 자신을 부르고, n 이 0 이 되면 더할 것이 없으니 0 을 돌려준다. 재귀는 "지금 한 자리만 처리하고 나머지는 같은 함수에 맡긴다"는 발상이다. 호출은 f(1234) → f(123) → f(12) → f(1) → f(0) 순으로 쌓였다가 f(0) = 0 부터 거꾸로 값이 돌아오며 더해진다.
따라가기
헷갈리는 자리 — 종료 조건을 n == 1 로 착각해 마지막 1 을 빠뜨리는 것. 이 코드는 n == 0 에서 멈추므로 1 의 자리도 더해진다. 그리고 순서 — 자릿수 합은 순서가 상관없지만, 자리를 "출력"하는 재귀라면 호출 순서(4 3 2 1)인지 반환 순서(1 2 3 4)인지가 답을 가른다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
다음 코드의 출력을 쓰시오.
답 — 2O. 대문자 K · A 두 개를 세고, s[1] 인 'o' 에서 32 를 빼 'O' 로 만든다.
원리 — 아스키 코드에서 대문자 A~Z 는 65~90, 소문자 a~z 는 97~122 로 정확히 32 차이다. 그래서 소문자 − 32 = 대문자, 대문자 + 32 = 소문자다. 반복문은 널 문자까지 돌며 'A' 이상 'Z' 이하인 글자만 센다 — "KoreA" 에서 K 와 A 다. s[1] 은 'o'(111) 이고 111 − 32 = 79 = 'O' 를 %c 가 글자로 찍는다. 서식이 "%d%c" 라 숫자와 글자가 붙어서 나온다.
따라가기
헷갈리는 자리 — 2 뒤의 글자를 숫자 0 으로 적는 것. 알파벳 O 다. 그리고 s[1] 을 "첫 글자"로 읽어 K 로 계산하는 것 — 첨자는 0 부터다. 대소문자 변환은 ±32 또는 toupper() · tolower() 함수로도 나온다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
왜 이걸 하나 — 원리는 알아도 글자 하나 · 순서 하나에서 깎인다.
| 자리 | 새는 꼴 | 적는 법 | 기출 |
|---|---|---|---|
| 대소문자 | E 를 e 로, TSEB 를 tseb 로 | 코드의 변환(toupper · +32)을 따라 그대로. 출력은 대소문자가 답이다 | 2025-3회 7번 · 2025-2회 18번 |
| 소수 자리 | 2795.1 · 2795.104 | %.2f 면 둘째 자리까지 반올림 | 2024-1회 11번 |
| 「그리고」 표기 | 「2 그리고 3」을 「2, 3」으로 | printf 문자열에 한글이 있으면 그 글자까지 답이다 | 2025-2회 12번 · 14번 |
| 공백 | 3 1 2 를 312 로 | 서식에 공백("%d ")이 있으면 공백까지 | 2025-2회 16번 · 2024-3회 12번 |
| 순회 순서 | 노드를 만든 순서대로 적는다 | next 화살표를 그려 head 부터 따라간다. 마지막에 이은 화살표가 이긴다 | 2025-1회 18번 · 2025-2회 16번 |
| 순회 종류 | 후위를 전위로 센다 | 자기 처리가 두 재귀 호출 뒤에 있으면 후위 | 2026-2회 7번 |
| 시저 범위 | z 를 넘어도 그대로 더한다 | % 26 이 있으면 a 로 돌아간다. 없으면 코드값 그대로 | 2024-1회 19번 |
| 화살표 기호 | -> 를 . 이나 => 로 | 포인터면 ->, 변수면 . | 2023-3회 4번 |
이 장의 답에는 한글 · 공백 · 소수점이 섞인 출력이 많다. printf 의 서식 문자열을 답 칸 옆에 베껴 놓고 그 틀에 값만 넣으면 표기 감점이 없어진다.
왜 이걸 하나 — 세 원리를 짧은 코드 10개로 돌린다. 매일 5문항씩 곁들이는 자리다.
훈련 10문항은 문자 세기, 역순 복사, 재귀 누적합, 피보나치, 구조체 화살표, 구조체 배열, 대소문자 반전, strcmp 원리, strcat + strlen, 그리고 static 지역변수다. 정답은 전부 gcc 로 실행해 확인했다.
답 — 3 8. "ENGINEER" 에서 E 는 3개, 길이는 8 이다.
원리 — C 문자열은 끝에 널 문자 '\0' 이 붙어 있어, 첨자를 0 부터 올리며 널을 만날 때까지 도는 것이 문자열 순회의 기본형이다. 첫 반복문은 각 글자를 'E' 와 비교해 세고, 둘째 while 은 널이 나올 때까지 len 을 올려 길이를 잰다 — strlen 을 손으로 만든 것이다. 널 문자 자체는 길이에 안 들어간다. 두 반복문의 조건이 같은 모양이라는 것을 보면 둘 다 "끝까지 훑는다"는 것이 보인다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — EDOC. "CODE" 를 뒤집어 새 배열에 담았다.
원리 — r[i] = s[len − 1 − i] 는 "r 의 i 번 칸에 s 의 뒤에서 i 번째 글자"를 넣는다. i = 0 이면 s[3] = 'E', i = 3 이면 s[0] = 'C' 다. 글자 4개를 옮긴 뒤 r[4] = '\0' 로 끝을 표시해야 %s 가 어디서 멈출지 안다 — 이 줄이 없으면 쓰레기 값이 이어져 찍힐 수 있다. r 을 5칸으로 잡은 이유도 널 자리 때문이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 55. 1 부터 10 까지의 합을 재귀로 구한 것이다.
원리 — f(n) = n + f(n − 1) 이고 f(1) = 1 이 바닥이다. f(10) 은 10 + f(9), f(9) 는 9 + f(8) … f(2) 는 2 + f(1) = 3 까지 내려갔다가 위로 값이 돌아온다. 결국 10 + 9 + … + 1 = 10 × 11 ÷ 2 = 55 다. 재귀 문제는 "바닥이 무엇인가"와 "한 단계가 무엇을 더하나"만 잡으면 손으로 안 펼쳐도 식으로 계산된다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 13. 피보나치 수열의 7번째 항이다.
원리 — f(n) = f(n − 1) + f(n − 2), f(1) = f(2) = 1 은 피보나치 정의다. 재귀로 펼치면 호출이 나무처럼 갈라져 f(7) 하나에 f 가 25번 불리지만, 값은 앞에서부터 표로 채우면 금방이다 — 1 1 2 3 5 8 13. 시험은 이 모양의 코드를 보면 "피보나치"임을 알아보고 표로 푸는 것이 빠르다. 바닥이 n <= 2 라 f(1) · f(2) 둘 다 1 이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 1001 95. 구조체 포인터로 score 에 7 을 더했고, 그 변화가 s 에 그대로 반영된다.
원리 — 구조체 변수 s 의 멤버는 s.no · s.score 로 접근하고, 구조체를 가리키는 포인터 p 로는 p->score(또는 (*p).score)로 접근한다. p = &s 이므로 p->score 는 s.score 와 같은 칸이다. p->score += 7 은 88 을 95 로 바꾸고, 그 값은 s.score 로 읽어도 p->score 로 읽어도 95 다. 화살표 -> 는 "포인터가 가리키는 구조체의 멤버"라는 뜻이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 50b. v 가 20 이상인 20 + 30 = 50 이고, arr[1].g 는 'b' 다.
원리 — 구조체 배열 arr 은 {g, v} 짝이 3개 있는 배열이다. arr[i].v 로 i 번째 구조체의 v 를 읽는다. 조건 v >= 20 은 첫 번째(10)를 걸러내고 20 · 30 을 더한다. arr[1] 은 두 번째 원소 {'b', 20} 이라 g 는 'b' 다. 서식 "%d%c" 라 50 과 b 가 붙어 찍힌다. 구조체 배열 문제는 "몇 번째 원소의 어느 멤버인가"를 표로 그리면 틀리지 않는다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — kOREA. 소문자는 대문자로, 대문자는 소문자로 서로 바꾸었다.
원리 — 아스키에서 대소문자는 32 차이다. 소문자면 32 를 빼 대문자로, 아니면(대문자면) 32 를 더해 소문자로 만든다 — 대소문자 토글이다. "Korea" 는 K 만 대문자라 K → k, o r e a → O R E A 가 된다. s[] 는 문자 배열이라 제자리에서 고칠 수 있다 — char *s = "Korea" 처럼 문자열 리터럴을 가리키는 포인터였다면 고치는 순간 오류가 난다는 것이 짝으로 나오는 함정이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 4 e y. 두 문자열이 처음으로 달라지는 자리가 4번이고, 그 자리 글자가 e 와 y 다.
원리 — while 조건은 "a 가 안 끝났고, 두 글자가 같다"이다. 같을 동안 i 를 올리다가 다른 글자를 만나면 멈춘다 — strcmp 가 하는 일의 앞부분이다. "apple" 과 "apply" 는 a p p l 네 글자가 같고 5번째(첨자 4)에서 e 와 y 로 갈린다. 멈춘 시점의 i 가 4 이고, a[4] = 'e', b[4] = 'y' 다. 문자열이 완전히 같았다면 a[i] 가 널이 되는 순간 앞 조건이 거짓이 되어 멈춘다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — ABCDE 5. strcat 으로 두 번 이어 붙여 다섯 글자가 됐다.
원리 — strcat(a, b) 는 a 의 널 자리부터 b 를 복사해 붙이고 끝에 널을 다시 놓는다. a 를 10칸으로 잡은 것은 붙일 공간을 미리 두기 위해서다 — 2칸짜리였다면 넘쳐서 사고가 난다. "AB" + "CD" = "ABCD", 거기에 "E" 를 붙여 "ABCDE" 다. strlen 은 널 앞까지의 글자 수라 5 다(널 포함 아님). 이 둘은 string.h 함수라 헤더가 필요하다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
왜 이걸 하나 — 아래를 안 보고 적을 수 있어야 이 장이 끝난다.
. 과 -> 의 차이, typedef struct 의 꼴.