3장 printf scanf 함수

저수준 언어

언어의 수준(Level)은 상대적이지만 요즘은 코볼이나 어셈블리를 배우지 않는 점에서 C언어는 Low-Level 언어에 해당합니다. 코볼이나 어셈블리는 C언어에 대해 상대적으로 더 낮은 수준인 언어입니다.

Level이 낮으면 하드웨어에 직접 엑세스하기 쉬워집니다. 그만큼 처리가 빨리지죠. 반면에 Level이 높아지면 복잡한 구조를 단순하게 만들 수 있다는 점에서 코딩이 편해집니다. 속도는 느려지지만 쉬운 코딩으로 버그가 줄어들고, 복잡한 프로그램을 만들 수 있습니다.
가장 낮은 수준인 어셈블리어는 CPU의 명령어에 맞게 직접 코딩을 해야 합니다. 그러다보니 코딩을 하기 위해선 컴퓨터 구조에 대한 학습은 필수였습니다. 컴퓨터 구조에 맞게 명령을 입력해야 했거든요. 보다 높은 수준인 C언어는 덧셈, 비교, 변수 지정 등을 한 줄로 끝낼 수 있게 되었습니다. 대학교에선 여전히 컴퓨터 구조를 학습하긴 하지만 컴퓨터 언어를 사용하는 데에는 중요하지 않게 되었습니다. 그래서 어셈블리어에 대해 상대적으로 고급 언어입니다.

객체지향 언어는 당연히 객체 개념을 통해 C언어에 비해 고급 언어로 칭해집니다. 객체지향 언어는 메모리에 대한 고려를 거의 하지 않습니다. 그래서 String 형의 변수를 다른 변수에 저장할 때에도 대입 연산을 이용할 수 있습니다. 무엇보다 객체 지향 언어는 객체를 이용하는게 특징입니다. 프로그램 실행에 Stack구조(객체를 계속 쌓는 방식)를 사용하기 때문에 이 전의 코드를 조금 바꾸어 재사용하거나 프로그램 최적화 및 관리가 쉽습니다.
그래서 고급 언어로 사용자와 상호작용을 하기 위한 Front End를 담당하고 저급 언어로 내부의 처리를 담당하기도 합니다. 자바나 코틀린을 사용하는 것으로 잘 알려진 안드로이드도 중요한 시스템 부분은 C언어로 만든 바이너리입니다.

C언어에서 사용하는 scanf는 키보드 입력을 받는 함수인데, 실제 사용자의 입력을 받기 쉽지 않습니다. scanf는 2바이트 문자인 한글을 입력받기 쉽지 않습니다. 또한 키보드로 입력되는 데이터를 버퍼에 저장하는데, 그 버퍼를 자주 비워줘야 프로그램이 의도한 대로 동작합니다. 또한 보안 문제로 대체 함수가 도입되어 있습니다. printf_s, scanf_s이죠. 대부분 보안 프로그램이 scanf를 사용한 경우 프로그램 실행을 차단합니다.

위와 같은 특성으로 인해 printfscanf를 사용자의 입력을 받는 용도로 사용하지 않습니다. 다만 C언어 개발을 배우는 과정에서 콘솔로 입/출력을 받을 때는 가장 자주 사용되는 함수입니다. 실제 프로그램 개발에서는 printf_s를 사용해야 하고, 일반적으로는 객체지향 언어로 프로그래밍 합니다.

예제

보통 C언어 프로그램은 Console(콘솔)로 실행됩니다. Console에서 사용자의 입력 및 출력을 담당하는 함수가 printf, scanf입니다.

int main(void)    //진입함수 main()
{
    int a;    //정수변수 선언
    printf("숫자 입력 : ");
    scanf("%d",&a);    //키보드로부터 값을 입력받아 변수에 저장
    printf("덧셈 결과 %d \n",a+3);     //%d의 숫자와 대응되는 값의 수는 일치
}

printf함수를 통해 숫자 입력 : 를 콘솔 화면에 출력합니다. 줄 내림을 하지 않았기 때문에 콘솔의 커서는 줄 내림을 하지 않고 콜론 오른쪽에 있습니다.

숫자를 입력하고 엔터를 누르면 scanf가 입력 값을 받아서 a에 저장합니다. 큰 따옴표 안에 %d가 있고, 큰 따옴표 뒤에 반점으로 구분하여 변수 이름이 적혀 있습니다.

printf함수를 다시 호출합니다. 큰 따옴표 안에 %d\n이 있지만 콘솔에는 보이지 않습니다. 왜 그런지 아래에서 알아보겠습니다.

printf

printf는 단순히 문장만 출력하지 않습니다. 변수를 출력할 수도 있지요. 그래서 같은 문장이라도 변수에 따라 출력이 달라지게 됩니다.
출력할 문장에 변수를 포함하는 방법이 %d를 사용하는 방법입니다. 그리고 그 뒤에 파라미터를 추가하여 %d에 대응하는 값을 출력하는 겁니다.

%d decimal(10진수)
%x hexadecimal(16진수)
%o octal number(8진수)
%e exponentiation(지수형)
%u unsigned(부호가 없는 자료형)
%f float(실수형)
%p pointer(포인터)
%c char(문자형)
%s string(문자열)

변수 여러개 출력하기

printf는 변수를 여러개 출력할 수 있습니다.

printf("아스키코드 %d은 %c입니다.", 97, 97);

%d%c를 두개 넣었습니다. 그리고 파라미터로 두개를 전달했습니다.
그랬더니 아스키코드 97은 a 입니다. 라고 출력됩니다.

2장 자료형에서 살짝 언급했는데, 같은 97을 전달받고도 정수형으로 표현한 것과 문자형을로 표현한 것이 다릅니다.

변수의 자릿수 정렬하기

printf는 자릿수를 정할 수 있습니다.
아래와 같이 입력하면

printf("%d \n",192);
printf("%d",6);
192
6

위와 같이 출력됩니다. 그런데 아래와 같이 입력하면

printf("%3d\n",192);
printf("%3d",6);
192
  6

위와 같이 출력됩니다. 자료형을 나타내는 문자 앞에 숫자를 붙이면 자릿수를 미리 지정할 수 있습니다.

실수형에서는 좀 더 복잡한 정렬도 가능합니다.

#include<stdio.h>
int main(){
    float a = 3.14159;
    int b = 192;
    printf("%6.3f\n",a);
    printf("%.3f\n",a);
    printf("%6d\n",b);
}

위와 같은 프로그램을 실행하면

  3.142
3.142
   192

와 같은 결과를 얻을 수 있습니다.

실수형은 전체 자릿수와 소숫점 아래 자릿수를 제한할 수 있고, 반올림하여 표현할 수 있습니다. 또한, 전체 자릿수는 지정하지 않고 소숫점 아래 자릿수만 제한할 수도 있습니다.

정수형과 실수형을 모두 6자리로 제한하니 출력에서는 마지막 숫자가 같은 위치에 있는 것을 알 수 있습니다.

printf줄 내림을 위해 특별한 표현을 사용합니다. 

printf는 한 줄로 명령이 이루어집니다. 게다가 컴파일러는 줄 내림을 무시합니다. 그렇다면 줄 내림을 출력하는 방법은 무엇일까요?

바로 이스케이프 시퀸스(Escape sequence) 라는 것을 사용하면 됩니다!. 문자열을 입력하고 있는데 \를 통해 escape해서 컴파일러의 처리를 한다고 보면 될 것 같습니다.

printf("줄 내림\n테스트");

라고 입력하면

줄 내림
테스트

라고 뜨게 됩니다.

그 외에도

\t 탭
\r 엔터(carriage return)
\v 수직 탭(vertical tab)
\b 지우기(backspace)
\f 폼 피드, 페이지 피드
\a 경고(beep음 경고)

가 있습니다. 대부분은 직접 입력이 가능하지만 알아두면 좋습니다.

그렇다면 컴파일러가 인식하고 콘솔에 출력하지 않는 문자를 콘솔에 출력하고 싶으면 어떻게 해야 할까요? 큰 따옴표는 문자열을 의미하는 것이어서 큰 따옴표를 입력하면 문자열이 끝나버리고 말죠. %도 %d, %f를 위해 할당된 문자여서 출력이 안됩니다. 도 마찬가지죠.
이러한 문자를 출력하는 것도 Escape Sequence 입니다.

\\
\"
\?
%%

와 같은 방법이죠. 음... Escape Sequence로부터 한번 더 Escape한다는 느낌입니다.

printf("\"큰 따옴표\" \\n %%d");

라고 입력하면

"큰 따옴표" \n %d

라고 출력됩니다.

scanf

scanf의 기본적인 사용법은 같습니다. printf와 다른 부분은 변수를 작성하는 뒤의 변수 이름 부분에 a가 아닌 &a를 사용한다는 것입니다.
추후 포인터를 학습하면서 자세히 다룰 부분인데, 변수의 메모리 주소를 의미합니다. scanf는 입력받은 데이터를 변수에 저장하는 것이 아니라 변수가 저장된 메모리 주소에 저장하기 때문에 &a를 사용합니다.

복습

#include<stdio.h>
int main()
{
    int salary;//월급
    int deposit ;//저금액

    printf("월급을 입력하시오: ");
    scanf("$d",&salary);

    deposit = 10 * 12 * salary;

    printf("10년간 저축액: %d \n", deposit);
    return 0;
}
#include<stdio.h>
int main()

    float radius;
    float area;

    printf("반지름을 입력하십시오: ");
    scanf("%f", %radius);

    area = 3.14 * radius * radius;

    printf("원의 면적: %f\n", area);
    return 0;
}
#include<stdio.h>
int main(){
    int id, pass;
    //ID와 PW자리에 '_'가 4개가 있고, ID 또는 PW를 입력하면 '\'가 없어지는 프로그램

    printf("ID와 PW를 4개의 숫자로 입력하세요:\n");
    printf("id:____\b\b\b\b");
    scanf("%d", &id);
    printf("pass:____\b\b\b\b");
    scanf("%d", &pass);
    printf("\a입력된 아이디는 \"%d\"이고 패스워드는 \"%d\"입니다.\n", id, pass);
    return 0;
}

요약

  • 출력을 위해 printf를 사용할 수 있다. 변수를 출력할 수도 있다.
  • 입력을 받기 위해 scanf를 사용할 수 있다.
  • printf나 scanf에 변수를 포함하도록 할 수 있다.
  • escape squence를 사용하여 원하는 문자열을 출력할 수 있다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다