정보처리기사

[정처기] 01. C언어 변수, 연산자, 출력 형식, 제어문 & 반복문

gani00 2026. 6. 26. 16:34

목차

  • 변수
  • 출력 형식
  • 연산자
  • 제어문과 반복문
  • 핵심 요약

변수

변수의 종류

변수는 선언된 위치생존 기간에 따라 지역변수, 전역변수, 정적변수, 동적 할당 변수로 나눌 수 있다.

종류 저장 영역 소멸 시점 초기화 하지 않았을 때
지역변수 스택 함수 실행 시 생성, 함수 종료 시 소멸 불확정 값
전역변수 정적 저장 영역 프로그램 시작 시 생성, 종료 시 소멸 0으로 초기화
정적변수 정적 저장 영역 프로그램 시작 시 생성, 종료 시 소멸 0으로 초기화
동적 할당 변수 할당 후 직접 반환할 때까지 유지 불확정 값

 

지역변수 Local Variable

함수 또는 블록 내부에서 선언하는 변수다.

void func(void) {
    int a = 10;
}
  • 일반적으로 스택 영역에 저장된다.
  • 함수가 호출되면 생성되고, 함수 실행이 끝나면 소멸한다.
  • 선언만 하고 값을 넣지 않으면 불확정 값이 들어 있다.
  • 선언된 함수 또는 중괄호 블록 내부에서만 사용할 수 있다.
void func(void) {
    int a = 10;
    printf("%d\n", a);
}

// printf("%d", a); // 오류: func 내부의 지역변수라 접근 불가

전역변수 Global Variable

모든 함수 바깥에서 선언하는 변수다.

#include <stdio.h>

int a = 10;

int main(void) {
    printf("%d\n", a);
    return 0;
}
  • 정적 저장 영역에 저장된다.
  • 프로그램이 시작될 때 생성되고, 프로그램이 종료될 때 소멸한다.
  • 명시적으로 초기화하지 않아도 기본적으로 0으로 초기화된다.
  • 선언된 파일 내의 여러 함수가 공유해서 사용할 수 있다.
  • 여러 함수가 같은 값을 수정할 수 있으므로, 너무 많이 사용하면 흐름을 추적하기 어려워진다.
int count;

void increase(void) {
    count++;
}

int main(void) {
    increase();
    increase();

    printf("%d\n", count); // 2
    return 0;
}

정적변수 Static Variable

static 키워드를 붙여 선언하는 변수다.

void func(void) {
    static int a = 0;
    a++;

    printf("%d\n", a);
}
  • 정적 저장 영역에 저장된다.
  • 프로그램이 종료될 때까지 값이 유지된다.
  • 초기화는 프로그램 실행 중 한 번만 수행된다.
  • 함수를 여러 번 호출해도 이전 호출에서 변경된 값이 유지된다.
  • 초기값을 지정하지 않으면 0으로 초기화된다.
#include <stdio.h>

void func(void) {
    static int a = 0;

    a++;
    printf("%d\n", a);
}

int main(void) {
    func(); // 1
    func(); // 2
    func(); // 3

    return 0;
}

일반 지역변수였다면 func()가 호출될 때마다 a가 새로 만들어져 매번 1이 출력된다.
하지만 static 지역변수는 한 번 만들어진 뒤 계속 유지되므로 1 → 2 → 3으로 증가한다.

static은 변수의 수명은 길게 유지하면서, 지역변수처럼 함수 내부에서만 접근하게 만들 수 있다.


동적 할당 변수 Dynamic Allocation

실행 중 필요한 크기만큼 메모리를 확보해서 사용하는 방식이다.

int *p = /* 동적 할당으로 확보한 int 저장 공간 */;
  • 힙 영역에 저장된다.
  • 프로그램 실행 중 필요한 시점에 메모리를 확보할 수 있다.
  • 사용이 끝난 메모리는 반드시 반환해야 한다.
  • 초기화하지 않은 공간에는 불확정 값이 들어 있을 수 있다.
  • 반환하지 않고 계속 참조를 잃어버리면 메모리 누수가 발생할 수 있다.

동적 할당은 실행 전에 크기를 정확히 알기 어려운 배열, 연결 리스트, 트리 같은 자료구조를 만들 때 자주 사용한다.

int n;
scanf("%d", &n);

// 실행 중 입력받은 n에 맞춰 저장 공간을 준비하는 상황

지역변수와 정적 지역변수 비교

void local_func(void) {
    int a = 0;
    a++;

    printf("%d\n", a);
}

void static_func(void) {
    static int a = 0;
    a++;

    printf("%d\n", a);
}
local_func();  // 1
local_func();  // 1
local_func();  // 1

static_func(); // 1
static_func(); // 2
static_func(); // 3

 

구분 지역변수 정적 지역면수
생성 시점 함수 호출 시 프로그램 시작 시
소멸 시점 함수 종료 시 프로그램 종료 시
함수 재호출 시 값 새로 생성됨 이전 값 유지
접근 범위 선언된 함수 또는 블록 내부 선언된 함수 또는 블록 내부

 


자료형

변수는 값을 저장하기 위한 이름이 붙은 메모리 공간이다.

int age = 25;
char grade = 'A'; -> 문자 하나는 작은따옴표
char str[] = "Hello"; -> 문자열 큰따옴표
float height = 165.5f;
double pi = 3.141592;

 

int 정수 10, -3
char 문자 1개 'A', 'b'
float 실수 3.14f
double 더 정밀한 실수 3.141592
void 값이 없음 반환값 없는 함수

 


출력 형식: printf

printf는 화면에 값을 출력하는 함수다.

printf("Hello\n");

자주 쓰는 형식 지정자는 다음과 같다.

%d 정수 int printf("%d", 10);
%c 문자 char printf("%c", 'A');
%s 문자열 printf("%s", "Hello");
%f 실수 float, double printf("%f", 3.14);
%x 16진수 정수 printf("%x", 255);
%p 주소값 printf("%p", ptr);
int age = 25;
char grade = 'A';
double score = 95.5;

printf("나이: %d\n", age); // 25
printf("등급: %c\n", grade); // A
printf("점수: %.1f\n", score); // 95.5
printf("%x", 255); // ff

%.1f는 소수점 아래 한 자리까지만 출력한다.

printf("%.2f", 3.14159); // 3.14

줄바꿈은 \n이다.

printf("A\n");
printf("B\n");

출력 결과:

A
B

연산자

산술 연산자

int a = 10;
int b = 3;

a + b; // 13
a - b; // 7
a * b; // 30
a / b; // 3
a % b; // 1

정수끼리 나누면 결과도 정수다.

printf("%d", 10 / 3); // 3

나머지는 %를 사용한다.

printf("%d", 10 % 3); // 1

증감 연산자

int i = 1;

i++; // i = i + 1
i--; // i = i - 1

전위 연산은 먼저 증감하고 사용한다.

int i = 1;
printf("%d", ++i); // 2

후위 연산은 먼저 사용하고 증감한다.

int i = 1;
printf("%d", i++); // 1
printf("%d", i);   // 2

비교 연산자

비교 결과는 참이면 1, 거짓이면 0으로 취급된다.

a == b; // 같다
a != b; // 다르다
a > b;  // 크다
a < b;  // 작다
a >= b; // 크거나 같다
a <= b; // 작거나 같다

주의: =는 대입, ==는 비교다.

int a = 3;  // 대입
a == 3;     // 비교

논리 연산자

&& // 그리고(AND)
|| // 또는(OR)
!  // 부정(NOT)
int age = 25;
int hasTicket = 1;

if (age >= 19 && hasTicket) {
    printf("입장 가능");
}

삼항 연산자

조건에 따라 두 값 중 하나를 선택할 때 사용한다.

조건 ? 참일 때 값 : 거짓일 때 값;
int score = 80;
char grade = score >= 60 ? 'P' : 'F';

printf("%c", grade); // P

if ~ else를 짧게 쓰는 표현이라고 생각하면 된다.

int max = a > b ? a : b;

제어문과 반복문

if ~ else

조건이 참이면 if 블록을 실행하고, 거짓이면 else 블록을 실행한다.

if (조건) {
    실행문;
} else {
    실행문;
}

C에서는 0을 거짓으로, 0이 아닌 모든 값을 참으로 취급한다.

if (0) {
    printf("실행 안 됨");
}

if (-1) {
    printf("실행됨");
}

중괄호는 실행문이 한 줄일 때 생략할 수 있다.

if (1)
    printf("A");

하지만 중괄호를 생략하면 바로 다음 한 문장만 if의 영향을 받는다.

if (1)
    printf("A");

printf("B");

출력 결과:

AB

아래 코드도 printf("B");는 조건문과 상관없이 실행된다.

if (1)
    printf("A");
    printf("B");

가독성과 실수를 막기 위해 중괄호를 쓰는 습관이 안전하다.

if (1) {
    printf("A");
    printf("B");
}

switch

하나의 값에 따라 여러 경우를 나눌 때 사용한다.

switch (값) {
    case 값1:
        실행문;
        break;

    case 값2:
        실행문;
        break;

    default:
        실행문;
}

case는 값이 일치하는 위치로 이동한다.

break를 만나면 switch문을 종료한다.

break가 없으면 다음 case까지 계속 실행된다. 이것을 fall-through라고 한다.

#include <stdio.h>

int main() {
    int num = 2;

    switch (num) {
        case 1:
            printf("ONE\n");
            break;

        case 2:
            printf("TWO\n");
            // break 없음

        case 3:
            printf("THREE\n");
            break;

        default:
            printf("DEFAULT\n");
    }

    return 0;
}

출력 결과:

TWO
THREE

num이 2이므로 case 2부터 실행된다.
그런데 case 2에 break가 없으므로 case 3까지 이어서 실행된다.

default는 항상 실행되는 것이 아니다.

switch (num) {
    case 1:
        printf("ONE");
        break;

    case 2:
        printf("TWO");
        break;

    default:
        printf("DEFAULT");
}
  • num == 1이면 ONE
  • num == 2이면 TWO
  • 어느 case에도 해당하지 않으면 DEFAULT

for

반복 횟수가 비교적 명확할 때 자주 사용한다.

for (초기값; 조건; 증감식) {
    실행문;
}
for (int i = 0; i < 5; i++) {
    printf("%d ", i);
}

출력 결과:

0 1 2 3 4

실행 순서는 다음과 같다.

초기값 → 조건 확인 → 실행문 → 증감식 → 조건 확인 → ...

while

조건이 참인 동안 반복한다.

while (조건) {
    실행문;
}
int i = 0;

while (i < 5) { // 5보다 작은 동안 반복
    printf("%d ", i);
    i++;
}

출력 결과:

0 1 2 3 4

while문에서는 반복 조건을 바꾸는 코드가 빠지면 무한 루프가 될 수 있다.

int i = 0;

while (i < 5) {
    if (i == 2) {
        continue;
    }

    i++;
}

위 코드는 i == 2가 되면 continue로 반복문의 처음으로 돌아간다.
하지만 i++가 실행되지 않으므로 i는 계속 2에 머물고 무한 반복된다.

수정하려면 증가를 먼저 처리하거나, continue 전에 증가시켜야 한다.

int i = 0;

while (i < 5) {
    if (i == 2) {
        i++;
        continue;
    }

    i++;
}

do ~ while

조건을 나중에 검사하므로 do 블록은 최소 한 번은 무조건 실행된다.

do {
    실행문;
} while (조건);
int i = 10;

do {
    printf("%d", i);
} while (i < 5);

출력 결과:

10

조건 i < 5는 거짓이지만, 조건을 검사하기 전에 do 블록을 먼저 실행했기 때문이다.


break와 continue

break는 반복문 또는 switch문을 즉시 종료한다.

for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;
    }

    printf("%d ", i);
}

출력 결과:

0 1 2 3 4

continue는 현재 반복만 건너뛰고 다음 반복으로 넘어간다.

for (int i = 0; i < 5; i++) {
    if (i == 2) {
        continue;
    }

    printf("%d ", i);
}

출력 결과:

0 1 3 4

핵심 정리

지역변수: 함수가 실행되는 동안만 존재 
전역변수: 프로그램 전체에서 공유 가능 
정적변수: 프로그램 끝까지 값 유지, 초기화는 한 번만 동적 
할당 변수: 실행 중 필요한 크기만 확보하고 사용 후 반환 필요

%d: 정수 출력 
%c: 문자 출력 
%s: 문자열 출력 
%f: 실수 출력 
%x: 16진수 출력 
%p: 주소값 출력

if: 조건이 참일 때 실행
switch: 값에 따라 여러 분기 처리
for: 반복 횟수가 명확할 때 사용
while: 조건이 참인 동안 반복
do while: 실행문을 최소 한 번은 실행
break: 반복문 또는 switch 종료
continue: 현재 반복만 건너뛰고 다음 반복 진행