본문 바로가기
AI/정보처리기사_스터디

5일차_정보처리기사 필기 C언어 오답노트: 시험장에서 틀리기 쉬운 8가지 함정

by 거대웅 TitanBear 2026. 7. 17.
정보처리기사 실기 · C언어 오답노트

정보처리기사 필기 C언어 오답노트: 시험장에서 틀리기 쉬운 8가지 함정

암기 문장을 예외 없이 적용하지 않고 문장 경계 → 주소 → 값 → 자료형·평가 시점 순서로 추적한 학습 기록입니다.

오늘 학습 범위

과목 정보처리기사 필기 프로그래밍 언어 활용
교재 범위 수제비 기반 개인 오답노트 문서 1·2·4절
오늘의 목표 문장 경계, 주소, 값, 자료형과 평가 시점을 차례로 설명하기

정보처리기사 실기에서 C언어 문제를 틀리는 이유는 문법을 전혀 몰라서보다 아는 규칙을 너무 넓게 적용해서인 경우가 많았습니다. 세미콜론 하나, 배열 변환의 예외, 후위 감소가 값을 내보내는 시점처럼 작은 경계가 출력값을 바꿉니다.

핵심 개념 카드

1단계 · 문장 경계 세미콜론과 중괄호로 실제 실행 범위를 표시합니다.
2단계 · 주소 &, 배열 변환, 포인터 덧셈이 가리키는 위치를 적습니다.
3단계 · 값 *[]가 있을 때 그 위치의 값을 읽습니다.
4단계 · 자료형 포인터 보폭과 sizeof의 대상을 확인합니다.
5단계 · 평가 시점 후위 감소의 식 결과와 문장 뒤 저장값을 나눕니다.

제목에서 약속한 8가지

1
true의 의미

C 표준 버전과 헤더에 따라 확인합니다.

2
if (조건);의 빈 문장

세미콜론 하나가 조건문의 본문을 끝냅니다.

3
주소 연산과 역참조

&는 주소를 얻고 *는 주소가 가리키는 객체를 지정합니다.

4
배열 식의 포인터 변환

대부분 첫 원소 포인터로 변환되지만 예외가 있습니다.

5
배열 첨자의 의미

a[i]*(a + i)와 같은 원리입니다.

6
포인터의 보폭

+1은 가리키는 자료형의 원소 한 칸입니다.

7
문자열의 종단 널

문자열 배열에는 끝을 나타내는 \0가 들어갑니다.

8
후위 감소의 결과값

감소 전 값을 식의 결과로 내보낸 뒤 저장값이 감소합니다.

내가 헷갈린 지점

오답노트에 남은 다섯 혼동을 정답 문장만 다시 외우지 않고, 잘못 적용한 규칙과 그것이 깨지는 반례, 시험장에서 던질 질문으로 바꿨습니다.

1
if 뒤 세미콜론

처음 외운 규칙: 들여쓰기 된 다음 문장까지 if의 본문이라고 읽었습니다.

반례: if (0); x = 1;에서는 세미콜론이 빈 문장을 완성하므로 x = 1;이 조건과 관계없이 실행됩니다.

시험장 확인 질문: 조건문 바로 뒤에 세미콜론이 있는가, 실제 본문은 어느 문장까지인가?

2
배열 이름과 포인터

처음 외운 규칙: 배열 이름은 포인터 변수와 완전히 같은 객체라고 외웠습니다.

반례: int a[3]; int *p = a;에서 sizeof(a)는 배열 전체 크기지만 sizeof(p)는 포인터 자체 크기입니다.

시험장 확인 질문: 지금 식이 포인터로 변환되는 문맥인가, 아니면 sizeof(a)&a처럼 배열 자체가 남는 예외인가?

3
포인터의 +1

처음 외운 규칙: 포인터에 1을 더하면 주소가 언제나 1바이트 증가한다고 생각했습니다.

반례: char *int *는 각각 자기 자료형의 다음 원소로 이동하므로 실제 바이트 간격이 같다고 단정할 수 없습니다.

시험장 확인 질문: 이 포인터가 가리키는 자료형은 무엇이며 이동 후에도 같은 배열 안의 원소 또는 끝 바로 다음을 가리키는가?

4
문자열 크기

처음 외운 규칙: 화면에 보이는 글자 수가 곧 문자열 배열의 sizeof 결과라고 생각했습니다.

반례: char word[] = "C";에는 문자 C와 종단 널 문자 \0가 들어가므로 sizeof(word)는 2입니다.

시험장 확인 질문: 지금 세는 대상은 보이는 문자 수인가, 널 문자까지 포함한 배열의 저장 크기인가?

5
후위 감소

처음 외운 규칙: B = A--;에서 A를 먼저 감소시킨 뒤 그 값을 B에 넣는다고 생각했습니다.

반례: A가 5라면 식의 결과는 5이므로 B에 5가 들어가고, 저장된 A는 그 뒤 4가 됩니다.

시험장 확인 질문: 지금 필요한 값은 후위 감소식이 내보내는 값인가, 문장이 끝난 뒤 변수에 저장된 값인가?

초보자 눈높이 개념 설명

먼저 보는 용어 상자

초보자가 먼저 알아둘 C언어 용어
용어 정확한 정의 쉬운 말
식별자 변수·함수처럼 프로그램 요소에 붙이는 이름입니다. 코드 안의 이름표입니다.
키워드 C 문법이 미리 정해 둔 뜻으로 예약한 토큰입니다. 언어 사전에 이미 등록되어 다른 이름표로 쓸 수 없는 단어입니다.
매크로 전처리 단계에서 이름을 다른 토큰으로 바꾸도록 정의한 규칙입니다. 본격적인 컴파일 전에 적용되는 치환 메모입니다.
단항 연산자 피연산자 하나에 작용하는 연산자입니다. &value, *p처럼 대상 하나만 받는 기호입니다.
구현 C 표준이 허용한 선택지를 실제 컴파일러와 실행 환경이 정한 방식입니다. 컴파일러나 환경에 따라 달라질 수 있는 부분입니다.

A. 이름과 문장 경계

1
true를 모든 C에서 같은 종류의 이름으로 읽기

C는 대소문자를 구분하므로 true, True, TRUE는 같은 이름이 아닙니다. 더 중요한 점은 소문자 true의 지위도 표준 버전에 따라 다르다는 것입니다.

C11에서는 <stdbool.h>bool, true, false를 매크로로 제공합니다. 근거: WG14 N1570(C11) §7.18.

C23에서는 truefalsebool형의 미리 정의된 상수 키워드입니다. 근거: WG14 N3096(C23) §6.4.1, §6.4.4.5.

C11
#include <stdbool.h>

bool done = true;
2
if 뒤의 세미콜론을 장식처럼 보기

세미콜론은 문장의 마침표입니다. if (조건);에서는 세미콜론 하나가 아무 작업도 하지 않는 빈 문장을 만들고, 그것이 if의 본문이 됩니다.

C
if (score >= 60)
    ;              /* 조건문의 빈 본문 */

result = 1;        /* 조건문 밖: 항상 실행 */

들여쓰기는 사람이 읽기 좋게 만든 모양일 뿐 실행 범위를 정하지 않습니다. 정확한 범위는 세미콜론과 중괄호가 결정합니다.

B. 주소와 값

3
&*를 둘 다 포인터 기호라고만 외우기

단항 &는 객체의 주소를 얻고, 단항 *는 포인터가 가리키는 객체를 지정합니다. 사물함 비유로 보면 &value는 사물함 번호표를 받는 일이고, *pp에 적힌 번호의 사물함을 여는 일입니다.

C
int value = 10;
int *p = &value;
p value의 주소
*p 그 주소에 저장된 값 10
*&value 같은 객체를 다시 지정하므로 값은 10
4
배열 이름을 포인터 변수와 완전히 같다고 보기

배열 식은 대부분의 식에서 첫 원소를 가리키는 포인터로 변환됩니다.

C
int a[] = {10, 20, 30};
int *p = a;

하지만 배열 객체와 포인터 변수는 서로 다른 객체입니다. 특히 sizeof(a)와 단항 &a에서는 배열이 첫 원소 포인터로 변환되지 않습니다. sizeof(a)는 배열 전체 크기를 구하고, &a는 배열 전체를 가리키는 포인터가 됩니다. 근거: WG14 N1570(C11) §6.3.2.1.

5
a[i]*(a + i)를 별개 문법으로 보기

배열 첨자는 포인터 덧셈과 역참조를 합친 표기입니다.

관계식
a[i] == *(a + i)

a + i로 i번째 원소의 위치를 구하고, *로 그 위치의 값을 읽습니다. 근거: WG14 N1570(C11) §6.5.2.1.

C. 자료형과 평가 시점

6
포인터의 +1을 1바이트로 계산하기

p + 1은 주소 숫자에 무조건 1을 더한다는 뜻이 아니라, 같은 배열에서 가리키는 자료형의 다음 원소로 이동한다는 뜻입니다.

char *p char 한 칸
int *p int 한 칸
double *p double 한 칸

실제 바이트 수는 해당 구현의 sizeof(*p)에 달려 있습니다.

7
문자열의 보이는 글자만 배열 원소로 세기

문자열 리터럴로 배열을 초기화하면 끝을 표시하는 널 문자 \0가 함께 저장됩니다.

C
char word[] = "Apple";

word에는 A, p, p, l, e, \0의 여섯 원소가 들어가므로 sizeof(word)는 6입니다. 반면 char *p = "Apple"; sizeof(p)는 문자열 길이가 아니라 포인터 자체 크기입니다.

8
후위 감소를 감소한 값으로 읽기 C
int a = 5;
int b = a--;

후위 감소식 a--의 결과값은 감소 전 값 5입니다. 따라서 b에는 5가 들어가고, 저장된 a는 그 뒤 4가 됩니다.

전위 감소 --a는 먼저 감소한 값을 식의 결과로 사용합니다. 시험에서는 식이 내보낸 값과 문장이 끝난 뒤 저장된 값을 두 칸으로 나눠 적습니다.

코드와 값의 흐름

언어는 C입니다. a의 원소 자료형은 int, pint *, resultint입니다.

C · 통합 예제
#include <stdio.h>

int main(void) {
    int a[] = {10, 20, 30};
    int *p = a;
    int result = *p;

    if (*(p + 1) == 999);
        result = a[2];

    printf("%d %zu\n", result, sizeof("Apple"));
    return 0;
}
통합 C 코드 실행 흐름
순서 실행 내용 변수·메모리 값 출력
1 a 배열 생성 a[0]=10, a[1]=20, a[2]=30 없음
2 p = a pa[0]를 가리킴 없음
3 result = *p result=10 없음
4 *(p + 1) == 999 *(p+1)=20, 조건은 거짓 없음
5 if 뒤의 ; 조건문의 본문은 빈 문장 없음
6 result = a[2] 조건문 밖이므로 result=30 없음
7 sizeof("Apple") 종단 널을 포함해 6 30 6

기출 유형에 적용하기

아래 두 문제는 실제 기출 원문이나 사용자의 실제 오답이 아닙니다. 본문과 같은 출제 원리를 낯선 코드에 적용하기 위해 새로 만든 기출형 예제입니다.

기출형 예제 1. 기준 포인터가 이미 이동했다면

C · 재구성 예제
#include <stdio.h>

int main(void) {
    int data[] = {2, 4, 8, 16};
    int *p = data + 1;

    printf("%d %d\n", *p, *(p + 2));
    return 0;
}
질문 형태 최종 출력 두 값을 구합니다.
흔한 오답 p+2를 배열 처음 기준으로 읽어 4 8이라고 답하기 쉽습니다.
정답 4 16

추적: pdata[1]의 주소입니다 → *p는 4입니다 → p+2는 현재 위치에서 int 두 칸 뒤인 data[3]을 가리킵니다 → 값은 16입니다.

기출형 예제 2. 거짓 조건, 빈 본문, 후위 감소

C · 재구성 예제
#include <stdio.h>

int main(void) {
    int a = 3;
    int b = 99;

    if (a-- == 0);
        b = a;

    printf("%d %d\n", a, b);
    return 0;
}
질문 형태 조건이 거짓일 때 ab의 최종 값을 구합니다.
흔한 오답 b가 99로 남거나 a--가 2를 비교한다고 보기 쉽습니다.
정답 2 2

추적: a--가 비교에 내보내는 값은 3이라 조건은 거짓입니다 → 저장된 a는 2가 됩니다 → 세미콜론이 if의 빈 본문입니다 → b=a는 조건문 밖에서 실행되어 b=2가 됩니다.

시험장에서 재현할 풀이 순서

1
문장 경계 표시

;, {, }를 표시해 실제 실행 범위를 찾습니다.

2
이름의 조건 확인

표준 버전과 헤더가 이름의 의미에 영향을 주는지 확인합니다.

3
주소와 값 분리

주소 식과 값 식을 분리하고 현재 포인터의 기준 위치를 적습니다.

4
자료형과 크기 확인

포인터 자료형, 배열 변환 예외, sizeof의 대상을 확인합니다.

5
평가 전후 값 분리

후위 증감은 식의 결과와 다음 저장값을 따로 기록합니다.

시험 직전 암기 카드

카드 1 · true

질문: C11에서 표준 true를 쓰려면?

한 줄 답: <stdbool.h> 포함 여부를 확인합니다. C23에서는 미리 정의된 상수 키워드입니다.

카드 2 · 빈 문장

질문: if (조건);의 본문은?

한 줄 답: 세미콜론 하나로 된 빈 문장입니다.

카드 3 · 주소와 역참조

질문: &x*p는?

한 줄 답: &x는 주소, *p는 가리키는 객체 또는 그 값입니다.

카드 4 · 배열 변환

질문: 대표적인 변환 예외는?

한 줄 답: 배열이 sizeof 또는 단항 &의 피연산자일 때입니다.

카드 5 · 배열 첨자

질문: a[i]와 같은 원리의 식은?

한 줄 답: *(a + i)

카드 6 · 포인터 보폭

질문: p+1은 몇 바이트 이동하는가?

한 줄 답: 가리키는 자료형의 원소 한 칸입니다.

카드 7 · 문자열 널

질문: sizeof("Apple")은?

한 줄 답: 종단 널까지 포함해 6입니다.

카드 8 · 후위 감소

질문: int b = a--;에서 b가 받는 값은?

한 줄 답: 감소 전 a의 값입니다.

미니 퀴즈

1
true의 표준 버전

C11에서 표준 booltrue를 사용하려면 어떤 헤더가 필요한가?

2
빈 문장

if (0); x = 1;에서 x = 1;은 언제 실행되는가?

3
주소와 역참조

int x = 7; int *p = &x;에서 *&x*p의 값은?

4
배열 변환 예외

int a[3];에서 배열이 첫 원소 포인터로 변환되지 않는 대표 식 두 개는?

5
배열 첨자

int a[] = {3, 6, 9};일 때 *(a + 2)의 값은?

6
포인터 보폭

int *pp + 1은 무엇을 기준으로 이동하는가?

7
문자열 널

char word[] = "C";일 때 sizeof(word)는?

8
후위 감소

int a = 5; int b = a--;가 끝난 뒤 ab의 값은?

정답과 해설 확인하기
1
<stdbool.h>

C11에서는 해당 헤더를 포함합니다. C23의 true는 미리 정의된 상수 키워드입니다.

2
조건과 관계없이 실행

if의 본문은 세미콜론으로 끝난 빈 문장입니다.

3
둘 다 7

&x로 주소를 얻고 *로 그 주소의 값을 읽습니다.

4
sizeof(a)&a

두 문맥에서는 배열 자체가 남습니다.

5
9

*(a+2)a[2]와 같습니다.

6
int 원소 한 칸

실제 바이트 수는 구현의 sizeof(int)에 달려 있습니다.

7
2

문자 C와 종단 널 문자 \0가 들어갑니다.

8
a=4, b=5

후위 감소식은 감소 전 값을 먼저 결과로 사용합니다.

오늘의 학습 회고

오늘 이해한 것: 암기 문장보다 적용 조건을 함께 외워야 합니다. 배열 이름은 “포인터다”가 아니라 “대부분의 식에서 첫 원소 포인터로 변환된다”가 정확하고, 후위 감소도 식의 결과와 저장된 다음 값을 분리하면 흔들리지 않습니다.

아직 헷갈리는 것: 2차원 배열에서 int (*p)[N]의 보폭과 배열 포인터·포인터 배열의 선언 모양입니다. 이 글에서는 범위를 억지로 확장하지 않고 다음 학습으로 남깁니다.

참고 자료

개인 학습 자료: 정처기_수제비_오답노트.docx

WG14 N1570 — C11 committee draft

WG14 N3096 — C23 working draft