본문으로 건너뛰기

입출력과 전처리

개요​

printf·scanf 등 표준 입출력 함수, 형식 지정자, 전처리기(#include·#define) 지시자.

표준 입출력 함수​

scanf()를 이용한 표준 입력​

scanf() 함수는 키보드로부터 데이터를 입력받기 위한 표준 입력 함수이다. 이 함수를 사용하기 위해서는 stdio.h 헤더 파일이 필요하다.

scanf()는 변환 명세(Conversion Specification)를 포함하는 제어 문자열과 입력받을 값을 저장할 변수의 주소를 인자로 받는다. 변수의 주소를 전달하기 위해 변수 이름 앞에 주소 연산자 &를 붙여야 한다.

int age;
scanf("%d", &age); // 키보드로 입력한 정수를 age 변수에 저장한다.

scanf()에서 사용하는 주요 변환 명세는 다음과 같다.

  • %d: 10진수 정수 (int)
  • %o, %x: 8진수, 16진수 정수 (int)
  • %u: 부호 없는 10진수 정수 (unsigned int)
  • %f: 단정밀도 실수 (float)
  • %lf: 배정밀도 실수 (double)
  • %c: 단일 문자 (char)
  • %s: 문자열 (string)

문자 입력 시 주의사항: scanf()로 여러 데이터를 연속으로 입력받을 때, 숫자 등을 입력한 후 누른 Enter키(\n)가 입력 버퍼에 남아 다음 문자 입력(%c)에 영향을 줄 수 있다. 이를 방지하려면 %c 앞에 공백을 추가하여 scanf(" %c", &variable); 형태로 사용해야 한다. 이 공백은 버퍼에 남아있는 공백 문자(스페이스, 탭, 개행 등)를 무시하는 역할을 한다.

printf()를 이용한 표준 출력​

printf() 함수는 화면에 데이터를 출력하기 위한 표준 출력 함수이다. scanf()와 마찬가지로 제어 문자열과 출력할 값(표현식)들을 인자로 받는다.

출력 형식 지정​

printf()의 변환 명세에 추가적인 정보를 결합하여 출력 형식을 제어할 수 있다.

  • 필드 폭(Field Width): 출력할 전체 자릿수를 지정한다.
    • %5d: 5칸을 확보하고 오른쪽 정렬로 정수를 출력한다.
    • %-5d: 5칸을 확보하고 왼쪽 정렬로 정수를 출력한다.
    • %+5d: 부호를 항상 표시하며 5칸에 오른쪽 정렬로 출력한다.
  • 정밀도(Precision): 실수를 출력할 때 소수점 이하 자릿수를 지정한다.
    • %5.2f: 전체 5칸 중 소수점 이하 2자리까지 출력한다.
    • %10.4e: 전체 10칸을 확보하고 지수 형태로 소수점 이하 4자리까지 출력한다.

출력 제어 문자 (Escape Sequence)​

printf()의 제어 문자열 안에서는 특수한 기능을 하는 출력 제어 문자를 사용할 수 있다.

  • \n: 줄 바꿈 (Newline)
  • \t: 수평 탭 (Horizontal Tab)
  • \": 큰따옴표 출력
  • \\: 역슬래시() 출력
  • \a: 경고음 (Alert)

getchar()와 putchar()​

getchar()와 putchar()는 한 번에 문자 하나만을 입출력하기 위한 함수이다. 사용법은 다음과 같다.

char c;
c = getchar(); // 문자 하나를 입력받아 c에 저장한다.
putchar(c); // c에 저장된 문자를 출력한다.

전처리기 (Preprocessor)​

전처리기는 소스 코드가 컴파일러에 의해 번역되기 전에 특정 작업을 먼저 수행하는 프로그램이다. 전처리기 지시자는 # 문자로 시작한다.

#include 와 헤더 파일​

**Header File(헤더 파일)**은 확장자가 .h인 텍스트 파일로, 주로 함수 원형, 매크로 정의, 자료형 재정의 등을 포함한다. #include 지시자는 이러한 헤더 파일을 소스 코드에 포함시키는 역할을 한다.

  • #include <stdio.h>: 시스템 헤더 파일을 포함할 때 사용한다.
  • #include "myheader.h": 사용자가 직접 작성한 헤더 파일을 포함할 때 사용하며, 현재 소스 파일이 있는 폴더부터 검색한다.

주요 시스템 헤더 파일은 다음과 같다.

  • stdio.h: 표준 입출력 함수 (printf, scanf 등)
  • math.h: 수학 관련 함수 (pow, sqrt 등)
  • string.h: 문자열 처리 함수 (strcpy, strlen 등)
  • stdlib.h: 메모리 할당, 유틸리티 함수 (malloc, exit 등)

#define 과 매크로​

#define 지시자는 특정 식별자(기호 상수 또는 매크로)를 지정된 문자열로 치환하는 역할을 한다.

  • 기호 상수: 값에 이름을 부여하여 가독성과 유지보수성을 높인다.

    #define PI 3.141592
  • 인자가 있는 매크로: 함수처럼 동작하는 코드를 정의한다.

    #define SQUARE(x) ((x) * (x))

    매크로 정의 시, 인자와 전체 식을 괄호로 감싸는 것이 중요하다.

    괄호가 없으면 연산자 우선순위에 의해 예기치 않은 결과가 발생할 수 있다.

typedef 를 이용한 자료형 재정의​

typedef 키워드는 이미 존재하는 자료형에 새로운 이름을 부여하는 기능이다. 이는 코드의 가독성을 높이고, 다른 시스템으로 코드를 이식할 때 자료형의 크기 차이로 인한 문제를 쉽게 해결할 수 있게 도와준다.

typedef int myint; // int 자료형을 myint라는 이름으로도 사용할 수 있다.
myint salary; // int salary; 와 동일하다.

기본 연산자

연산자의 기본 개념​

  • Operator(연산자): 덧셈(+), 곱셈(*)과 같이 특정 연산을 수행하도록 정의된 기호나 키워드이다.
  • Operand(피연산자): 연산의 대상이 되는 변수나 값이다.

연산자는 피연산자의 수에 따라 단항, 이항, 삼항 연산자로 분류된다.

주요 연산자​

대입 연산자 (Assignment Operator)​

Assignment Operator(대입 연산자) =는 오른쪽 피연산자의 값을 왼쪽 피연산자(변수)에 저장하는 역할을 한다. 연산자들 중 우선순위가 매우 낮아 대부분의 다른 연산이 끝난 후 마지막에 수행된다.

관계 연산자 (Relational Operators)​

**Relational Operator(관계 연산자)**는 두 피연산자의 값을 비교하는 데 사용된다. 연산 결과는 참(true)이면 1, 거짓(false)이면 0의 정수 값을 가진다.

  • >,<, >=, <=, ==(같다), !=(같지 않다)

증감 연산자 (Increment/Decrement Operators)​

Increment/Decrement Operator(증감 연산자) ++와 --는 피연산자의 값을 1 증가시키거나 감소시킨다. 연산자의 위치에 따라 평가 결과가 달라진다.

  • 전위(Prefix): ++a, --a. 변수의 값을 먼저 증감시킨 후, 그 결과를 수식의 값으로 사용한다.
  • 후위(Postfix): a++, a--. 변수의 현재 값을 먼저 수식의 값으로 사용한 후, 변수의 값을 증감시킨다.

논리 연산자 (Logical Operators)​

**Logical Operator(논리 연산자)**는 논리적인 관계를 평가하는 데 사용된다. C언어에서는 0을 거짓으로, 0이 아닌 모든 값을 참으로 간주한다.

  • && (AND): 두 피연산자가 모두 참일 때만 1(참)을 반환한다.
  • || (OR): 두 피연산자 중 하나라도 참이면 1(참)을 반환한다.
  • ! (NOT): 피연산자가 참이면 0(거짓)을, 거짓이면 1(참)을 반환한다.

단축 평가 (Short-circuit Evaluation)​

논리 연산자 &&와 ||는 **Short-circuit Evaluation(단축 평가)**를 수행한다.

  • && 연산에서 첫 번째 피연산자가 거짓(0)이면, 전체 결과는 무조건 거짓이므로 두 번째 피연산자를 평가하지 않는다.
  • || 연산에서 첫 번째 피연산자가 참(1)이면, 전체 결과는 무조건 참이므로 두 번째 피연산자를 평가하지 않는다.

이러한 특성은 b++와 같은 증감 연산자가 논리 연산식 내에 있을 때 예기치 않은 동작의 원인이 될 수 있으므로 주의해야 한다.