정보처리기사2026년 4월 16일· 7 min read

정처기 실기 C언어 정리 (포인터·배열·비트 연산)

정처기 실기 C언어 파트에서 출력 예측에 꼭 필요한 포인터, 배열, 구조체, 비트 연산, 재귀 함수의 핵심을 예제로 정리합니다.

안녕하세요. 문어입니다 🐙


C언어는 실기에서 가장 배점이 큰 언어

회차마다 다르지만, C언어 문제는 대체로 3문제 내외로 가장 많이 나옵니다. 포인터·배열·재귀가 주축이고, 비트 연산과 구조체가 섞여 나오는 해도 있어요.

코드 한 줄에 담긴 포인터 연산을 정확히 따라가는 게 합격 여부를 가르는 편이라, 이 과목만큼은 "대충 아는 것"과 "정확히 아는 것"의 차이가 점수로 바로 드러납니다.


포인터 — 주소, 참조, 값을 분리해서 보기

포인터에서 혼동이 생기는 지점은 거의 항상 세 가지입니다.

  • &a : 변수 a의 주소
  • p : 포인터가 저장하고 있는 주소값
  • *p : 포인터가 가리키는 곳의 값
int a = 10;
int *p = &a;
*p = 20;
printf("%d", a);  // 20

포인터를 통해 값을 바꾸면 원래 변수에도 반영됩니다. *p = 20은 "p가 가리키는 곳에 20을 넣어라"라는 뜻이므로 a가 20으로 바뀝니다.

포인터 산술과 배열

int arr[] = {10, 20, 30, 40};
int *p = arr;
printf("%d ", *(p + 2));   // 30
printf("%d ", *p + 2);     // 12  ← 괄호 위치 주의
printf("%d", arr[3]);      // 40
  • *(p + 2)는 주소 기준으로 2칸 뒤(=30)
  • *p + 2*p(=10)에 2를 더한 값(=12)
괄호 위치가 결과를 바꿉니다. *(p+2)*p+2는 완전히 다른 연산이에요.

이중 포인터

int a = 5;
int *p = &a;
int **pp = &p;
printf("%d", **pp);  // 5

**pp는 "pp가 가리키는 포인터가 가리키는 값" → a → 5.


문자열 — strlen vs sizeof

char s[] = "HELLO";
printf("%d ", strlen(s));  // 5  (널 문자 제외)
printf("%d", sizeof(s));   // 6  (널 문자 포함)
  • strlen은 문자열 길이(널 문자 \0 제외)
  • sizeof는 배열 전체 바이트 수(널 포함)

이 차이를 묻는 문제가 자주 나옵니다.


비트 연산 — AND / OR / XOR / NOT

비트 연산은 2진수로 변환해서 계산해야 합니다.

int a = 12;   // 1100
int b = 10;   // 1010
printf("%d ", a & b);  // 1000 = 8
printf("%d ", a | b);  // 1110 = 14
printf("%d ", a ^ b);  // 0110 = 6
printf("%d ", a << 2); // 110000 = 48  (왼쪽 시프트: × 4)
printf("%d", a >> 1);  // 0110 = 6    (오른쪽 시프트: ÷ 2)
  • & : 둘 다 1일 때 1
  • | : 하나라도 1이면 1
  • ^ : 서로 다르면 1 (같으면 0)
  • <<, >> : 각 비트를 왼쪽/오른쪽으로 이동
XOR은 "다르면 1"이라는 규칙만 기억하면 됩니다. 같은 값을 두 번 XOR 하면 0이 돼서 암호화/스왑에도 쓰입니다.

재귀 함수 — 호출 스택을 그리면서 따라가기

int fn(int n) {
    if (n <= 1) return 1;
    return n * fn(n - 1);
}
printf("%d", fn(5));  // 120

fn(5) = 5 × fn(4) = 5 × 4 × fn(3) = 5 × 4 × 3 × fn(2) = 5 × 4 × 3 × 2 × fn(1) = 120.

실기에서는 재귀식이 팩토리얼처럼 단순하지 않은 경우가 많습니다. 종료 조건을 먼저 확인하고, 값이 들어가는 방향을 종이에 그려보세요.


구조체와 typedef

typedef struct {
    char name[20];
    int age;
} Person;

Person p = {"Kim", 25};
printf("%s %d", p.name, p.age);  // Kim 25

typedef를 쓰면 struct Person p가 아니라 Person p로 선언할 수 있습니다. 구조체 포인터일 때는 -> 연산자를 씁니다.

Person *pp = &p;
printf("%s", pp->name);  // Kim

pp->name(*pp).name과 같은 의미입니다.


동적 할당 — mallocfree

int *arr = (int*)malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++) arr[i] = i * 10;
printf("%d", arr[3]);  // 30
free(arr);
  • malloc은 요청한 크기의 힙 메모리를 할당하고 그 주소를 반환
  • 반환 타입이 void*이므로 필요한 타입으로 캐스팅
  • 다 쓴 뒤 free로 반환하지 않으면 메모리 누수

시험에서 자주 틀리는 지점 정리

헷갈리는 지점정답 기준
*(p+1) vs *p+1괄호 안이 먼저 계산
strlen(s) vs sizeof(s)널 문자 포함 여부
a++ vs ++a전자는 반환 후 증가, 후자는 증가 후 반환
&a[i]a + i와 동일
배열 이름 arr배열의 첫 원소 주소(&arr[0])와 동일
종이에 값을 써가며 따라가는 게 귀찮아도 가장 확실한 방법입니다. 눈으로만 추적하면 한두 번은 꼭 틀립니다.

정리

C언어는 "포인터가 가리키는 것이 무엇인가"를 매 순간 머릿속에서 그릴 수 있으면 거의 다 풀립니다. 다른 영역과 달리 암기보다 추적 능력이 점수를 결정하는 과목이에요.

한 문제를 풀 때 값이 어떻게 변했는지를 주석처럼 여백에 써 보는 연습을 반복해 두면, 시험장에서 긴장한 상태에서도 흔들리지 않습니다.

직접 문제를 풀어보세요

매번 새로운 모의고사와 무한 풀이 모드로 실전 감각을 키울 수 있습니다.