Transcript 10강의-C언어
1
컴퓨터 개론 및 실습
강의 10
www.msharpmath.com
1
/ 26
2
표준 입력과 출력 (stdio)
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
www.msharpmath.com
2
/ 26
3
getchar, putchar
■ 가장 간단한 입출력
한 번에 한 문자를 읽어들이거나(getchar), 한 문자를 쓰는(puchar) 것이
가장 간단한 입출력이다.
■ getchar
호출될 때마다 다음의 입력문자를 넘겨주고, 파일의 끝을 만나면 EOF 라는
값을 넘겨준다. EOF 는 상수로 <stdio.h> 에 정의되어 있다.
www.msharpmath.com
3
/ 26
4
getch, ungetch 의 작성
교과서 p.111
숫자를 구성하는 문자들의 집합을 생각해보자. 숫자가 아닌 것이 입력되기
전까지는 숫자 입력이 끝났는지 아닌지를 알 수 없다. 그래서 일단 한
문자를 읽은 후 숫자가 아니면 그것을 다시 원상태로 되돌려주어야 한다.
다시 말해서, 프로그램이 한 문자를 읽어 들일 때마다 그것을 입력에 다시
넣어서 프로그램의 나머지 부분들은 그것이 읽히지 않았던 것처럼 처리하면
되는 것이다.
■ getch, ungetch
다행히도 한 쌍의 함수를 사용함으로써 위의 동작을 하도록 할 수 있다.
getch는 다음 입력문자를 읽어 들인다. ungetch 는 문자를 다시 입력에
넣어서, 다음에 getch를 호출할 때 그 것을 넘겨주도록 한다. 이것들의
동작은 아주 간단하다. getch는 버퍼에 어떤 문자가 있으며 읽어 들이고,
버퍼가 비면 getch를 호출한다. 그리고 버퍼 안의 현재 문자 위치를 기록해
두어야 한다(인덱스). 버퍼와 인덱스는 getch와 ungetch에 의해 공유되며,
호출할 때 그들의 값을 유지해야 하므로 모두 외부형으로 선언되어야 한다.
그러므로 getch와 ungetch 그리고 그 들의 공유된 변수는 다음과 같다.
www.msharpmath.com
4
/ 26
5
getch, ungetch 의 작성 (cont.)
#define BUFFSIZE 100
char buf[BUFFSIZE]; // buffer for ungetch
int ibuf = 0; // next free position in buf
int getch(void) // get a (possibly pushed back) character
{
return (ibuf > 0) ? buf[--ibuf] : getchar();
}
void ungetch(int c) // push character back on input
{
if( ibuf >= BUFFSIZE ) printf("ungetch: too many characters");
else buf[++ibuf] = c;
}
www.msharpmath.com
5
/ 26
6
printf
d, i
int 10진수
o
int 부호없는 8진수
x, X
int 부호없는 16진수 (앞에 0x나 OX없는), 10, ..., 15에 대해 abcdef나 ABCDEF
를 사용한다.
u
int 부호없는 10진수
c
int 단일문자
s
char* 문자열로부터 ‘\0’가 있을 때까지 문자가 출력되거나 정밀도에 의해 주어
진 문자수만큼 문자가 출력된다.
f
double [-]m, dddddd 여기서 d의 수는 정밀도에 의해서 주어진다(기본 설정값
은 6이다).
e, E
double [-]m, dddddd e+xx, 여기서 d의 수는 정밀도에 의해 주어진다(기본 설
정값 6).
g, G
double 만일 지수가 주어진 정밀도 이상이거나 -4보다 작으면 %e나 %E를 사용
하고 그렇지 않다면 %f를 사용한다. 뒤에 붙는 0과 소수점을 출력되지 않는다.
p
void* 포인터 (시스템에 따라 표현이 다름)
%
변환되지 않는다. % 를 출력
www.msharpmath.com
6
/ 26
7
문자열 변환효과
■ ”hello, world” (12문자)의 출력
각각 필드의 주위에 콜론(:)을 찍어서 그들의 범위를 알 수 있게 한다.
:%s:
:%10s:
:%.10s:
:%-10s:
:%.15s:
:%-15s:
:%15.10s:
:%-15.10s:
:hello, world:
:hello, world:
:hello, wor:
:hello, world:
:hello, world:
:hello, world
:
:
hello, wor:
:hello, wor
:
■ 폭(정밀도)은 * 로도 표현할 수 있다.
문자열 s로부터 maxlen 문자를 출력하는 경우
printf (“%.*s”, maxlen, s);
www.msharpmath.com
7
/ 26
8
sprintf
■ 출력을 문자열에 저장
int sprintf(char *string, char *format, arg1,arg2,...)
sprintf 함수는 printf 과 동일한 변환을 행하지만, 출력을
문자열(string)에 저장하는 점이 다르다.
www.msharpmath.com
8
/ 26
9
가변길이의 매개변수 리스트
void myprintf(char *fmt, ...)
{
cplx z;
char *p,*sval;
int ival;
double dval;
va_list ap;
va_start(ap, fmt);
for( p = fmt; *p; p++) {
if( *p != '%' ) {
putchar(*p);
continue;
}
switch(*++p) {
case 'd':
ival = va_arg(ap,int);
printf("%d", ival);
break;
www.msharpmath.com
typedef struct Complex cplx;
struct Complex {
double x;
double y;
};
va_list 형은 매개변수를 차례로 가리키는 포인터 변수를 정의
할 때 사용된다. ap는 매개변수 포인터(argument pointer)를
의미한다.
va_start는 첫 번째 이름 없는 매개변수를 가리키도록 ap 가
사용되기 전에 va_start 를 한 번 호출해야 하고 매개변수 중에
서 이름을 가진 것이 적어도 하나는 있어야 한다.
va_arg 를 호출하면 하나의 매개변수를 리턴하고 ap 가 다음
매개변수를 가리키게 한다. va_arg 는 어떤 형이 리턴될 것이
며, ap가 얼마나 전진해야 될지를 결정하기 위해 형 이름을 참
고한다.
9
/ 26
10
가변길이의 매개변수 리스트 (cont.)
case 's':
for(sval = va_arg(ap,char *); *sval; sval++)
putchar(*sval);
break;
case 'f':
dval = va_arg(ap, double);
printf("%f", dval);
break;
사용자가 정의한 구조체를 출력하는 방법을 정해두면 C
언어의 기본 형과 섞어서 출력하는 것이 가능해진다. 예
를 들어
cplx z = {3,-4};
myprintf("test %d %f %s %z", 36, 3.14, "pi=3.14", z);
case 'z': // personalized by users
z = va_arg(ap,cplx);
printf(" :%g%ci%g:", z.x, (z.y>0.) ? '+':'-‘,fabs(z.y));
break;
default:putchar(*p);break;
}
}
va_end(ap);
}
www.msharpmath.com
va_end 는 청소작업을 한다. 이것은 함수가 리턴되기 전에 호
출되어야 한다.
10
/ 26
11
형식화된 입력 : scanf
■ 함수 scanf 는 printf와 사용방법이 유사한 함수인데, 출력함수가 아니고 입력함수이다.
int scanf(char *format, ...)
scanf는 표준입력으로부터 문자를 읽어 들여서 format의 변환형식에 따라 그들을 해석하고
매개변수에 결과를 저장한다. scanf는 성공리에 대응된 것들의 갯수와 할당된 입력 항목의
갯수를 리턴한다. 파일의 끝에 가면 EOF를 리턴한다.
변환형식 지정 문자열에 보통의 문자가 올 수도 있는데, 입력에서 같은 문자가 들어와야 한
다.
monthname은 자체가 포인터이므
int day,month,year; char monthname[20];
로 & 를 붙이지 않는다
25 Dec 1988 의 형식 :
scanf(“%d %s %d”, &day, monthname, &year);
mm/dd/yy 의 형식 :
scanf(“%d/%d/%d”, &month, &day, &year);
www.msharpmath.com
11
/ 26
12
형식화된 입력 : sscanf
■ 표준 입력대신 문자열로부터 읽어들이는 함수 sscanf 도 있다.
int sscanf(char *string, char *format, arg1, arg2, ... )
int day,month,year; char monthname[20];
char line[80];
while( getline(line,sizeof(line)) > 0 ) {
if( sscanf(line, "%d %s %d", &day, monthname, &year) == 3 ) {
printf("valid: %s", line);
printf("%d %s %d\n\n", day, monthname, year);
}
else if(sscanf(line, "%d/%d/%d", &month,&day,&year) == 3 ) {
printf("valid: %s", line);
printf("%d/%d/%d\n\n", month, day, year);
}
else
printf("invalid: %s \n\n", line);
sscanf 의 리턴값은 성공한 입력의
}
갯수이므로 대응하는 포맷을 알 수
있다.
www.msharpmath.com
12
/ 26
13
구조체 *FILE
■ 파일 포인터인 stdin, stdout 는 FILE * 형으로 되어 있는 상수 포인터이다.
■ 함수 fopen
파일을 읽거나 쓰기 전에 파일은 라이브러리 함수 fopen 에 의해 열려야 한다. <stdid.h>에
있는 표준 입출력 정의 중에서 FILE 이라는 구조체 정의가 있으므로
FILE *fp;
FILE *fopen(char *name, char *mode); // 내장된 명령이므로 사용자는 선언할 필요없다.
fp = fopen(name,mode);
// mode 에는 입력(“r”), 출력(“w”), 첨가(“a” )가 있다.
만일 출력과 첨가를 위한 파일이 열려(open)있지 않으면 파일은 새로 만들어진다.
출력을 위해 이미 존재하는 파일을 열면 기존의 내용은 지워진다.
만약 입출력 에러가 있으면 fopen 은 NULL 을 리턴한다.
■ 함수 fclose
int fclose(FILE *fp)
은 fopen의 역기능을 가진다.
www.msharpmath.com
13
/ 26
14
파일 입출력
■ 파일로부터의 입력과 파일로의 출력
int fscanf(FILE *fp, char *format, ...)
int fprintf(FILE *fp, char *format, ... )
첫 번째 매개변수가 입력과 출력을 나타내는 파일 포인터인 것을 제외하면 scanf, printf 와
동일하다. 다시 말해서
scanf(format, ...) fscanf(stdin, format, ... )
printf(format, ... ) fprintf(stdout, format, ... )
으로 생각할 수 있다.
www.msharpmath.com
14
/ 26
15
문자열 조작
■ <string.h>
아래에서 s와 t는 char * 이고, c와 n은 int 이다.
strcat(s,t)
t를 s의 끝에 연결시킨다.
strncat(s,t,n)
t 중에 n 개 문자를 s 의 끝에 연결시킨다.
strcmp(s,t)
s < t, s == t, s > t 에 대해 -,0,+ 를 리턴한다.
strncmp(s,t,n)
strcmp와 같은데 단지 처음의 n 개의 문자만 비교한다.
strcpy(s,t)
s 에 t 를 복사한다.
strncpy(s,t,n)
t 의 n 개 문자를 s 에 복사한다.
strlen(s)
s 의 길이를 리턴한다.
strchr(s,c)
s 에서 첫 번째 c 의 포인터를 리턴하거나 존재하지 않으면 NULL 을 리턴
한다.
strrchr(s,c)
s 에서 마지막 c 의 포인터를 리턴하거나 존재하지 않으면 NULL 을 리턴
한다.
www.msharpmath.com
15
/ 26
16
문자분류와 변환
■ <ctype.h>
아래에서 c 는 unsigned char 로 나타낼 수 있는 int 이거나 EOF 이다.
isalpha(c)
c 가 알파벳이면 0 아닌 숫자, 아니면 0
isupper(c)
c 가 대문자면 0 아닌 숫자, 아니면 0
islower(c)
c 가 소문자면 0 아닌 숫자, 아니면 0
isdigit(c)
c 가 숫자(digit) 이면 0 아닌 숫자, 아니면 0
isalnum(c)
isalpha(c)이거나 isdigit(c)이면 0 아닌 숫자, 아니면 0
isspace(c)
c 가 공백, 탭, newline, 리턴, formfeed, 수직 탭이면 0 아닌 숫자
toupper(c)
c 가 대문자로 변환된다.
tolower(c)
c 가 소문자로 변환된다.
www.msharpmath.com
16
/ 26
17
system(char *s)
■ 명령실행
문자열 s 에 포함된 명령어 라인의 명령을 실행하고 현재의 프로그램으로 다시 되돌아온다.
예를 들어
system(“date”);
는 현재의 시간을 출력한다.
www.msharpmath.com
17
/ 26
18
Miscellanious Topics
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
■ 열거 상수(enumeration)
■ 스택 (stack)
■ 계산기의 원리 (reverse polish)
www.msharpmath.com
18
/ 26
19
enum
■ 정수형 상수의 열거
enum months { JAN=1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC };
따로 지정되지 않으면 집합 안 첫 번째 이름의 값은 0이고, 다음부터는 1씩
증가하면서 값을 자동으로 지정한다. 위의 경우
#define JAN 1
#define FEB 2
또는
const int JAN = 1;
const int FEB = 2;
보다 훨씬 편리하다.
열거 내에서 상수의 이름은 모두 달라야 하지만 값은 같을 수도 있다.
www.msharpmath.com
19
/ 26
20
stack
#define MAX 100
struct stack {
int starray[MAX];
int top;
};
struct stack *create(void)
{
struct stack *st;
st = malloc(sizeof(struct stack));
if (st == NULL) {
printf("malloc error\n");
return NULL;
}
st->top = 0;
return st;
}
www.msharpmath.com
20
/ 26
21
stack (cont.)
int is_empty(struct stack *st) { return st->top == 0; }
void push(struct stack *st, int x)
{
if (st->top == MAX) {
printf("stack is full\n");
return;
}
st->starray[st->top++] = x;
}
int pop(struct stack *st)
{
if (is_empty(st)) {
printf("stack is empty\n");
return;
}
return st->starray[--st->top];
}
www.msharpmath.com
21
/ 26
22
stack (cont.)
int main(void)
{
struct stack *st;
int x;
st = create();
while (1) {
printf("enter x (0 to terminate): ");
scanf("%d", &x);
if (x == 0) break;
push(st, x);
}
while (!is_empty(st)) printf("%d ", pop(st));
printf("\n");
return 0;
}
www.msharpmath.com
22
/ 26
23
reverse polish
■ 중위법
3 + 4 와 같이 연산자 “+” 가 피연산자 3, 4 의 중간에 놓이는 것을 중위법이라고 한다.
중위법의 경우 연산자의 우선순위가 정해지면 3 + 4 * 5 에서 4 * 5 를 먼저 계산하고
나중에 3 + 23 을 계산해야 하므로 순서가 불규칙하여 컴퓨터에서 사용하기 어렵다.
■ 후위법 (reverse polish 라고도 함)
3 4 + 와 같이 연산자 “+” 가 피연산자 3, 4 의 뒤에 놓이는 것을 후위법이라고 한다.
이것은 앞에서 다룬 stack 의 구조를 이용하여 쉽게 처리할 수 있다.
(1) 숫자가 나오면 무조건 stack 에 push 한다(넣는다).
(2) 이항연산자 + - * / 가 나타나면 stack에서 마지막 두 개를 pop 하여 (꺼내어) 계산
하고 결과를 다시 stack 에 push 한다.
(3) stack 에 한 개만 남아있으면 이것을 결과로 리턴한다.
■ 연산자의 우선순위
()
/*
+www.msharpmath.com
3 + 4 * 5 의 후위법에 의한 계산
345*+
3 20 +
23
23
/ 26
24
reverse polish (cont.)
■ 3 + 4 * 5 를 후위법으로 번역하는 과정
■ 3 은 숫자이므로 stack에 넣는다.
■ + 연산자가 오면 일단 buffer 에 넣고 다음 입력을 찾는다
■ 4 는 숫자이므로 stack에 넣는다
■ 연산자를 buffer 에 넣는데 우선순위가 낮은 것이 가장 마지막에 있으면 그 위에
쌓는다. 그렇지 않으면 buffer의 마지막 연산자를 꺼내어 stack에 쌓고, 빈 자리에 채
운다.
■ 5는 숫자이므로 stack 넣는다.
■ buffer에서 가장 위의 것을 꺼내어 stack 에 쌓는다.
■ buffer 가 비워질 때 까지stack 에 쌓는다.
+
5
4
3
+
www.msharpmath.com
3
+
*
*
5
5
4
4
*
4
*
4
3
+
3
+
3
+
3
24
/ 26
25
reverse polish (cont.)
■ 3 + 4 + 5 를 후위법으로 번역하는 과정
■ 3 은 숫자이므로 stack에 넣는다.
■ + 연산자가 오면 일단 buffer 에 넣고 다음 입력을 찾는다
■ 4 는 숫자이므로 stack에 넣는다
■ 연산자를 buffer 에 넣는데 우선순위가 낮은 것이 가장 마지막에 있으면 그 위에
쌓는다. 그렇지 않으면 buffer의 마지막 연산자를 꺼내어 stack에 쌓고, 빈 자리에 채
운다.
■ 5는 숫자이므로 stack 넣는다.
■ buffer에서 가장 위의 것을 꺼내어 stack 에 쌓는다.
■ buffer 가 비워질 때 까지stack 에 쌓는다.
+
4
3
+
www.msharpmath.com
3
+
5
5
+
+
+
4
4
4
3
+
3
+
3
25
/ 26
26
reverse polish (cont.)
■ 3 – (4 – ( 5 – 6 ) ) 를 후위법으로 번역하는 과정
-
3 -
-
-
-
-
-
6
6
6
6
5
5 -
5 -
5
5
5
4
4 -
4 -
4 -
4 -
4 -
4
4
3 -
3 -
3 -
3 -
3 -
3 -
3 -
3
www.msharpmath.com
26
/ 26