04 입출력과 전처리

Download Report

Transcript 04 입출력과 전처리

Part 04 입출력과 전처리
©우균, 창병모
1
이 장의 내용





전처리기 지시자
표준입출력
버퍼
입출력 방향 재지정
전처리기 지시자 요약
2
4.1 전처리기 지시자
3
전처리기 지시자

전처리기(preprocessor)


전처리기 지시자(preprocessor directive)



컴파일러가 프로그램을 번역하기 '전'에 소스 프로그램을 '처리'하
는 프로그램
전처리기에게 특정 작업을 지시하는 가짜 명령어(의사명령어)
#으로 시작함
중요한 전처리기 지시자


#include: 다른 파일의 내용을 현재 파일에 포함시킴
#define: 특정 단어를 다른 문자열로 바꿈
4
#include


파일 포함 지시자
헤더파일(header file)


다른 파일에 포함시킬 목적으로 작성된 파일
인클루드 파일(include file)이라고도 함
5
헤더파일 종류

<표준 헤더파일>


시스템의 특별한 위치에 존재
"일반 헤더파일"

소스파일과 같은 위치에서 찾을 수 있는 파일
6
변수 값 출력 프로그램
표준 헤더파일
이 부분을 별도의 헤더파일로 만들자
실행결과:
X = 101
7
직접 작성한 헤더파일 #include 예
일반 헤더파일이므로 defineX.h
는 include.c와 같은 디렉터리에
있어야 함
실행결과:
X = 101
8
#define

다른 문자열로 대치될 단어(매크로; macro)를 정의함
전처리기가 매크로 MESSAGE를
"Have a nice day !"로 바
꾸어 준다.
실행결과:
Have a nice day !
9
매크로 함수


함수 형태의 매크로
실제로 함수는 아니지만 인수를 받는 형태임
문자열 리터럴을 나
란히 두면 접합된다.
DUP("Hello? ")에서 MESSAGE는
"Hello? "이므로 DUP("Hello? ")
는 다음과 같이 바뀐다.
"Hello? " "Hello? "
실행결과:
Hello? Hello?
10
매크로 정의가 길 때
백슬래시(backslash)는 매
크로 정의가 다음 줄에 계
속됨을 의미함
실행결과:
La La La La La La La La La La
11
4.2 표준입출력
12
표준입출력

표준입출력(standard input/output)




거의 모든 컴퓨터가 기본적으로 수행하는 입출력
입출력 모두 문자열로 구성되어 있다고 간주함
표준입력은 통상 키보드, 표준출력은 통상 모니터를 나타냄
에코출력(echo output)


키보드로 입력된 내용을 모니터에 그대로 보여주는 것
에코출력은 운영체제 서비스일 뿐이며, 프로그램이 출력한 것은
아님  에코출력과 표준출력을 구별해야 함
13
표준 라이브러리

라이브러리(library)


표준 라이브러리(standard library)


미리 작성해 둔 프로그램
컴퓨터 시스템이 달라도 같은 기능(same functionality)을 같은 방
식(same interface)으로 사용할 수 있도록 작성해 둔 라이브러리
표준입출력 라이브러리(standard input/output library)

표준입출력을 다루는 프로그램(함수) 집합
14
printf: 형식에 맞는 출력
printf 포맷 스
트링은 데이터 변
환을 지시함
문자열
정수 i
2
%d
문자열
실수 f
3.14
%f
"3.140000"
문자열
문자 c
'5'
"2"
%c
"5"
실행결과:
i = 2
f = 3.140000
c = 5
15
printf
포맷 스트링
16
printf 출력 폭 지정
포맷 스트링에서 % 다음에
양의 정수를 기입하여 출
력 폭 지정
실행결과:
i =
2
f =
3.141593
c =
5
10칸
17
printf 정밀도 지정
포맷 스트링에서 %와 f 사
이에 (출력폭이 지정된 경
우, 출력폭 다음에) ".양수"
형태로 정밀도 지정
실행결과:
pi =
3.141593
pi =
3.14
pi = 3.141592653590
10칸
18
scanf: 형식에 맞는 입력
scanf 포맷 스트
링은 문자열을 데
이터로 변환함
주소연산자 &를 사
문자열
용한 점에 주의!
"27"
정수 n
%d
실행결과:
27
entered n
= 27
double of n = 54
triple of n = 81
27
19
scanf에서 주의할 점

주소 연산자(address-of operator) &




다음 scanf에서 두 번째 인수에 주의
scanf("%d", &n);
표준입력에서 변환한 값을 저장할 장소를 알아야 하기 때문에 변
수 n의 주소(&n)을 두 번째 인수로 사용함
주소 연산자를 누락시키면 실행시간 오류
프롬프트(prompt)



입력할 내용을 설명해 주는 안내문
프롬프트가 없으면 "프로그램이 죽은" 것으로 오해할 수 있음
앞 슬라이드의 프로그램은 프롬프트가 없다!
20
scanf: 프롬프트를 사용한 버전
바로 이것이 프롬프트!
입력할 내용을 설명해
준다.
실행결과:
정수 n을 입력해 주세요.
입력한 n = 27
n의 두 배 = 54
n의 세 배 = 81
n = 27
21
scanf
포맷 스트링
TIP:
double 타입으로 입
력 받아야 할 경우에
는 %f 대신 %lf를 사
용한다.
22
getchar, putchar: 문자 입출력
표준입력
a.....
문자
getchar
'a'
문자
대문자로 변환하는
함수 toupper()
'A'
putchar
.....A
표준출력
안내문구
(prompt)
putchar가 출력한 문자들
실행결과:
소문자를 입력하세요. a
a의 대문자는 A입니다.
23
gets, puts: 줄 단위 입출력
C99에서는 const int
로 배열 크기 선언이 가
능함
실행결과:
사용자가 입력한 \n
puts가 출력한 \n
line에는 여기까지만
저장됨(\n은 제외됨)
24
gets, puts 주의점

개행문자 처리



gets는 \n을 떼고 \0을 붙여 준다.
puts는 \n을 문자열 출력 끝에 자동으로 붙여 준다.
주의: fgets, fputs는 다르게 동작한다.

이전 예에서 gets 처리 후 line[256] 상황

버퍼 오버런(buffer overrun)


버퍼(임시저장소)의 범위를 넘어섬
gets와 puts는 버퍼 오버런의 위험이 있음  fgets, fputs를
사용하는 것이 권장됨.
25
4.3 버퍼
26
입력 버퍼
실행결과:
정수 n과 문자 c를 입력해 주세요.
250 a
n = 250
c =
a는 어디로?
c에는 공백문자가
저장됨
27
scanf가 공백을 건너뛰는 습성

포맷 스트링 %c의 특이함




포맷 스트링 %c는 공백을 건너뛰지 않음
포맷 스트링에 공백이 하나라도 있으면 여러 공백문자에 대응함
scanf("%d%c", …) ≠ scanf("%d %c", …)
포맷 스트링 %c를 제외하고는 모두 공백을 건너뜀
scanf("%d%d", …) ≡ scanf("%d %d", …)
%s로도 공백을 건너뛰어 문자를 읽을 수 있다


%s로 입력을 받되 입력 폭을 1로 지정
char c;
scanf("%1s", &c); // scanf(" %c", &c);와 같음
%s로 공백을 건너뛰지 않으려면?
 불가능함. gets를 사용하세요!
28
버퍼 관련 용어

버퍼 오버런(buffer overrun)



플러싱(flushing)


버퍼에 저장할 수 있는 한계를 넘어 데이터가 저장되는 상황
다른 공간의 데이터를 무심코 삭제할 수 있으므로 매우 위험함
버퍼의 내용을 모두 처리하고 버퍼를 비우는 것
버퍼 오버런에 주의해야 할 입출력 함수


gets와 puts는 버퍼 오버런을 유발할 수 있음
fgets, fputs를 사용하는 것이 좋음
29
4.4 입출력 방향 재지정
30
입출력 방향 재지정

입력 재지정(input redirection)



출력 재지정(output redirection)



표준입력 대신 파일로부터 입력 받음
program.exe < inputFile.txt
표준출력 대신 파일로 내용을 저장
program.exe > outputFile.txt
합쳐서…



program.exe < inputFile.txt > outputFile.txt
program.exe > outputFile.txt < inputFile.txt
<를  로, >를 로 생각하면 기억하기 쉽다.
31
4.5 전처리기 지시자 요약
32
전처리기 지시자 복습

매크로 정의가 길 경우에는 행 끝에 \를 넣어 다음 줄에
계속 정의한다.
33
매크로 함수의 한계?
실행결과:
x = 250
x = 747
이 x를 y로 바꾸고 싶지 않
습니까?
34
매크로 인수 연산 #x
매크로 인수 x를 문자열로 바꿈
실행결과:
x = 250
y = 747
# 하나만 넣었을 뿐인데…
PR(y)
 printf(#y " = %d\n", y)
 printf("y" " = %d\n", y)
 printf("y = %d\n", y)
35
매크로 인수 연산 ##

매크로 인수 연산자 ##



매크로 인수 이름을 붙여 줌
문자열을 붙이는 것이 아니라 인수 이름 자체를 붙임
## 사용 예
#define MERGE(x, y)
x ## y
...
MERGE(x, 1) = 25;
// x1 = 25; 로 확장됨
MERGE(blue, berry) *= MERGE(x, 1);
// blueberry *= x1; 으로 확장됨
...
36
Key Point
37
Key Point 1





#include는 헤더 파일을 포함시키고 싶을 때 사용하는 전처리기 지
시자다. 현재 디렉터리의 헤더파일 이름은 큰 따옴표( " )로 감싸서
나타내고 표준 헤더파일은 꺾은 괄호(<, >)로 감싸서 나타낸다.
전처리기는 #define 상수를 해당 정의대로 확장시켜 준다.
#define으로 정의된 상수를 매크로라고 한다. 전처리기는
#define 상수로 정의된 내용이 실제로 ‘상수’인지 아닌지는 신경
쓰지 않는다.
Microsoft Visual C++ 6.0에서 전처리기만 수행하려면 /E 옵션을 이
용한다.
문자열 리터럴을 두 개 나란히 나열하면 자동으로 문자열 리터럴들
을 접합해 준다.
#define을 이용하여 매크로 함수를 정의할 수 있다. 매크로 함수란
인수를 받는 매크로를 말한다.
38
Key Point 2





매크로 정의가 길어서 한 라인에 다 표시하기 힘들 경우에는 백슬래
시를 이용하여 여러 줄에 표시할 수 있다.
C 언어는 매우 단순한 형태의 입출력 기능만을 가정한다. 이를 표준
입출력이라고 하는데 표준입출력이란 간단히 말해서 문자열 수준(텍
스트 수준)의 입출력이다.
C 언어는 다양한 플랫폼에 대해 동일한 서비스를 제공하기 위해 라
이브러리 함수를 사용한다. 플랫폼에 상관없이 공통적으로 제공되는
라이브러리를 표준라이브러리라고 한다.
다양한 자료형의 자료를 표준출력에 출력할 경우에는 printf를 사
용하는 것이 편리하다. printf는 포맷 스트링을 이용하여 자료형
변환 형식을 지정한다. 대표적인 포맷 스트링으로는 %d, %f, %c 등이
있다. 각각 정수형, 부동소수형, 문자형 자료를 문자열로 변환한다.
출력되는 자료의 폭을 지정하기 위해서 포맷 스트링의 % 다음에 숫
자 n을 기입할 수 있다. 또 출력되는 자료의 정확도를 명시하기 위
해 .p 형태의 숫자를 기입할 수 있다. %10.2f는 전체 출력 폭을 10으
로, 소수점 이하 자릿수를 2로 하여 출력하라는 뜻이다.
39
Key Point 3





‘프로그램이 죽었다’는 오해를 방지하기 위해서, 사용자가 입력해야
하는 내용에 대해 설명하는 문구를 출력하는 것이 좋다. 이러한 설명
문구를 프롬프트라고 한다.
다양한 자료형의 자료를 표준입력으로부터 입력받을 경우에는
scanf를 사용하는 것이 편리하다. scanf의 포맷 스트링도 printf
의 포맷 스트링과 유사하다.
getchar는 문자 하나를 입력받아 리턴하고 putchar는 문자 하나
를 출력한다.
줄단위 입출력 함수 gets는 개행문자까지 읽지만 실제로는 개행문
자 대신 널문자를 저장한다. 반면 puts는 널문자 전까지 출력하고
널문자 대신 개행문자를 출력한다.
데이터를 처리하기 전에 임시로 저장해 두는 공간을 버퍼라고 한다.
입력 데이터를 저장하기 위한 버퍼를 입력버퍼라고 하고 출력 데이
터를 저장하기 위한 버퍼를 출력버퍼라고 한다.
40
Key Point 4




버퍼 오버런이란 버퍼에 저장할 수 있는 한계를 넘어 데이터가 저장
되는 상황을 말한다.
파일 infile로 표준입력을 재지정하려면 명령줄에 <infile을 쓰고, 파
일 outfile로 표준출력을 재지정하려면 명령줄에 >outfile을 쓴다.
매크로 함수를 정의할 때, 문자열 내에서는 매크로 인수가 확장되지
않는다.
매크로 인수 x 앞에 #을 붙여 #x와 같이 쓰면, 매크로 인수 x로 주어
진 내용을 문자열로 변환하라는 의미이다.
41
요약(1/2)

전처리기 지시자



표준입출력



#include: 다른 파일을 포함시킴
#define: 매크로(다른 문자열로 바뀔 문구)를 정의함
키보드(std. in)와 모니터(std. out)를 추상화함
문자 단위 입출력을 수행함
표준입출력 라이브러리



형식에 따른 입출력: printf(), scanf()
문자 단위 입출력: getchar(), putchar()
줄 단위 입출력: gets(), puts()
42
요약(2/2)

버퍼




입출력 방향 재지정


입출력 속도 차이를 메워주기 위한 임시 저장소
버퍼오버런: 저장 범위를 넘어 다른 영역에 침범하는 현상
버퍼오버런을 방지하기 위해 gets, puts보다 fgets, fputs를
사용하자.
표준입출력 대신 파일을 사용하도록 지정함
매크로 인수 활용


#x: 매크로 인수 x에 해당하는 문자열
x ## y: 매크로 인수 이름 x와 y를 접합함
43
주의사항 요약


사용자로부터 입력 받을 때에는 안내문구(prompt)를 사
용하는 것이 좋음
scanf의 인수로는 변수의 주소를 주어야 함
int x;
scanf("%d", x);
scanf("%d", &x);


// 잘못됨
// 올바름
scanf로 double형 데이터를 읽으려면 "%lf"를 이용함
scanf 포맷 스트링 "%c"는 공백을 건너뛰지 않음


" %c"를 이용하거나
"%1s"를 이용함
44
프로그래밍 실습
45
▶ 프로그래밍 실습 1

세 정수 a, b, c를 입력 받은 후 a와 b의 합에서 c의 거듭제곱을 빼는
프로그램을 작성하라. 거듭제곱은 c * c로 계산하면 된다. 단 다음과
같은 내용의 헤더파일 myLang.h를 만들고
이를 다음과 같이 #include하여 사용하라.

여러분의 프로그램에는 int, main, scanf, printf, return 등을
사용해서는 안 된다. 대신 myLang.h에 정의된 #define 상수를 이용
하여 작성해야 한다.
46
▶ 프로그래밍 실습 2


텍스트 내용을 간단히 암호화 하는 방법 중 ‘k-증가’라는
알고리즘이 있다. 이는 각 문자를 k문자 뒤의 문자로 변
경하는 알고리즘이다. 이 경우 문자들의 배열은 원형 형
태로 배열되어 있다고 가정한다. 즉 문자 z 다음에는 a가
나타나고 문자 Z 다음에는 A가 나타난다고 가정한다. 정
수 k와 문자 하나를 입력받은 후, k-증가 알고리즘대로 해
당 문자를 암호화 하는 프로그램을 작성하라.
예:
2 Z  B
6 i  o
9 p  y
47