제1장 기초 지식

C 프로그래밍 언어

국민대학교 컴퓨터학부 강승식

1.1 C의 유래

1972년 AT&T Bell Lab. Dennis Ritchie와 Ken Tompson  ---  PDP 7에서 UNIX 설계

C  <---  B  <---  BCPL

1.2 C를 사용하는 이유

① 효율적인 언어(efficiency)  ---  프로그램의 실행 속도가 빠르다

② 이식하기 편리(portability)  ---  타 시스템에서 실행시키기가 쉽다

③ 강력하고 융통성이 많다(powerful)  ---  UNIX의 대부분이 C언어로 구현됨

어셈블리어 수준의 low-level 기능 제공

1.3 C의 미래는?  --->  매우 밝다

C 언어 프로그래밍만 잘하면 미래가 보장된다(1996년 현재).

1.4 C의 사용

1. editor를 사용하여 프로그램을 작성한다.

- Turbo editor, edit, vi, q 등을 이용하여

- 작성한 C 프로그램 파일 이름은 *.c이다.      (예) test.c

2. C compiler를 사용하여 C 프로그램을 compile한다.

고급언어 프로그램  --->  기계어 프로그램

(원시 프로그램)	(목적 프로그램)

test.c	test.obj

3. linker에 의하여 목적 프로그램과 라이브러리를 link하여 실행 모듈을 생성한다.

※ UNIX에서 C 프로그램의 compile  :  $ cc test.c  ---  실행파일 a.out 생성

( GNU C compiler gcc 사용 가능 )

※ DOS에서 C 프로그램의 compile

① Turbo C 컴파일러 사용  :  C> tcc test.c  ---  실행파일 test.exe 생성

( 통합환경 TC에서 프로그램 작성 및 compile, 실행 가능 )

② MS C 컴파일러 사용    :  C> cl test.c  ---  실행파일 test.exe 생성

※ Windows에서 C 프로그램의 compile

Bolland C++  또는  Visual C++ 컴파일러 사용  ---  windows에서만 실행 가능

※ 고급언어 프로그램의 compile 과정

compiler  :  test.c   ---> test.obj  ( UNIX에서는 test.o )

linker	:  test.obj ---> test.exe  ( UNIX에서는 a.out )

제2장 C의 소개

2.1 간단한 C 프로그램 예

#include <stdio.h>

main()

{

printf("Welcome to the C world!!!\n");

printf("이곳에는 밝은 미래와 희망이 가득합니다.\n");

printf("C와 함께 유익하고 즐거운 Computer의 세계로...\n");

}

※ 다음과 같이 출력하는 C program을 작성하시오.

This is the 1-st C program.

^.^    :-)    :-D    :-'   -<-@

웃음   웃는모습  크게웃음   담배     장미

I did it!   Thank you.

#include <stdio.h>

main()	/* a simple C program */

{

int i;

i = 1;

printf("This is the %d-st C program.\n", i);

printf("  ^.^    :-)    :-D    :-'   -<-@\n");

printf("I did it!   Thank you.\n");

}

#include <stdio.h>

main()

{

printf("       CCCCCC\n");

printf("    CCCCCCCCCC\n");

printf("   CCC           CC\n");

printf(" CCC              CC\n");

printf("CCC\n");

printf("CCC\n");

printf("CCC\n");

printf("CCC\n");

printf(" CCC              CC\n");

printf("   CCC           CC\n");

printf("    CCCCCCCCCC\n");

printf("       CCCCCC\n");

printf("\n\n");

printf("C와 함께 유익하고 즐거운 Computer의 세계로...\n");

}

※ 두 정수의 합과 곱, 평균을 구하는 프로그램 작성

C 언어 프로그램은  함수들로 구성되어 있다 !!!

제3장 데이터 형(data type)

3.1 데이터 : 변수와 상수

□ 상수(constant) --- 변하지 않는 값,  (예) 123, 12.34, 3.14159, □A□, □string□

□ 변수(variable)  --- 프로그램이 실행되는 중에 값이 변할 수 있는 것

※ 변수의 이름 --- 값을 저장하고 있는 기억장소의 이름

변수(또는 함수)의 이름은 a-z, A-Z, _, 0-9를 사용하고 첫문자는 영문자 또는 _으로 시작한다.

단, C 언어에서 사용되는 지정어(keyword 또는 reserved word)는 허용되지 않는다.

3.2 자료형(data type)

① 기본 자료형

char	---   한 문자를 저장하는 기억장소(1 byte) 이름

-128 ∼ +127  또는  0 ∼ 255

int	---   정수 하나를 저장하는 기억장소(2 or 4 bytes) 이름

-215 ∼ +215-1 또는 -231 ∼ +231-1   <---  signed인 경우

0 ∼ 216-1   또는  0 ∼ +232-1     <---  unsigned인 경우

float	---   실수 하나를 저장하는 기억장소(4 bytes) 이름

10-64 ∼ 10+63, 유효숫자는 최대 8자리  <---  double인 경우는 2배

예제 프로그램: mile 단위를 km 단위로 변환

#include <stdio.h>

main()	/* convert miles to km */

{

float mile;

printf("Input distance in miles = ");

scanf("%f", &mile);

printf("%f mile(s) is about %f km", mile, mile * 1.6093);

}

※ 화씨 온도를 섭씨 온도로 변환하는 program을 작성하시오.

F = 9/5*C + 32,   C = (F-32)*5/9

※ 각 시스템에서 자료형 크기 --->  p.49 표3.1 참조 ( sizeof 내장함수 )

C 언어에서 문자형과 정수형은 모두 정수로 기억된다.

다만, 문자형은 1 byte로 표현되고 정수형은 2 bytes(or 4 bytes)로 표현될 뿐이다.

② 확장 자료형

short, long        ---   int 앞에 덧붙일 수 있는 qualifier

signed, unsigned  ---   int 또는 char 앞에 덧붙일 수 있는 qualifier

double	---   float 앞에 덧불일 수 있는 qualifier

(예)  short (int), long (int)

signed (int), unsigned (int)

signed short (int), unsigned short (int)

signed long (int), unsigned long (int)

double (float)

③ 변수 선언과 초기화

int i, j, k;	int num1, num2, sum, product;

int i = 0, j = 1, k;	int num1, num2, sum = 0, product = 1;

char c = 'A';	char c = 0x41;

float pi = 3.141592;

④ 상수의 표현

정수 : -123, +456, 789, 123U, 123L, 123u, 123l, 123UL, 123ul

8진수는 0으로 시작 : 0123, 0101

16진수는 0x로 시작 : 0x41

※ 1,000,000과 같이 comma가 삽입되면 error

실수 : 1.23, -1.23, +1.23, 0.12e-3, 12.34F, -12.34f, 12.34L, 12.34l

문자 : □A□, □0□, □\0123□, □\x41□, □\n□, □\t□, □\b□, □\r□, □\f□, □\'□, □\"□, □\\□, □\0□, □\007□

스트링 : □This is a string□, □C:\\HWP\\SAMPLE□

예제 프로그램: 정수의 overflow error

#include <stdio.h>

main()

{

short i=32767;

printf("%d, %d, %d\n", i, i+1, i+2);

}

예제 프로그램: 실수의 반올림 오차

#include <stdio.h>

main()

{

float x, y;

x = 2.0e20 + 1.0;

y = x - 2.0e20;

printf("%f, %f\n", x, y);

}

※ 한 문자를 읽어서 그 문자에 대한 ASCII 코드값을 출력하는 program

※ 소문자 하나를 읽어서 대문자로 변환하는 program

제4장 문자열(string)

4.1 문자열이란?

문자열(character string)이란 하나 이상의 문자들의 연속이다.

□I love you.□

I		l	o	v	e		y	o	u	.	\0

1. 문자열은 문자들의 배열로 저장된다.

예)  char name[40];

name[0] = 'I';

name[1] = ' ';

name[2] = 'l';

name[3] = 'o';

....

name[10] = '.';

name[11] = '\0';

2. 문자열의 끝은 null 문자로 표시한다.

3. 문자 □X□와 문자열 □X□는 다르다.

예제 프로그램: 문자열을 사용한 program 예

#include <stdio.h>

#define	MESSAGE	□Welcome to the C programming world !!!□

main()	/* Example of a character string */

{

char name[30];

printf("Input your name : ");

scanf("%s", name);

printf("Hello %s, %s\n", name, MESSAGE);

}

4.2 상수와 C 전처리기

#define문 --- 어떤 값을 여러 번 사용할 때 하나의 이름으로 정의

( 그 값을 다른 값으로 바꾸기 용이 )

예) #define  PI	3.14	---->   #define  PI   3.14159

#define  MYNAME	"Kang, Seung-Shik"

#define  SMILES	printf("^.^ :-) :-D -<-@\n")

※ compile하기 전에 전처리기(preprocessor)가 처리 --- include문, define문 등

※ 문자열(13장), 전처리기(11장) 참조

4.3 printf와 scanf 함수

C 언어의 입출력(I/O) --- compiler에서 library로 구현되어 있음.

4.3.1 printf 함수

printf(제어문자열, 인자-1, 인자-2, ..., 인자-n);

① 인자는 화면에 출력할 항목 : 값 or 수식

② 인자 수 = 변환문자의 수

변환문자

%d : 10진수로 변환하여 출력

%o :  8  "	"	"

%x : 16  "	"	"

%u : unsigned 10진수

%c : 문자로 변환하여 출력

%s : 문자열 출력

%f : 실수를 [-]xxx.xxxxxx 형태로 출력

%e : 실수를 [-]x.xxxxxe[±]xx 형태로 출력	예) 1.23000e+00

%g : 실수를 %f 또는 %e 형태로 출력 : 문자수가 적은 것으로 자동 선택

예제 프로그램: printf 함수를 사용한 program

#include <stdio.h>

#define	PI	3.14159

main()	/* Example of printf 함수 */

{

char ch = 'A';

short i = 0x41;

float pi = 3.14;

printf("ch = %c, %d, %x\n", ch, ch, ch);

printf(" i = %d, %u, %o, %x, %c\n", i, i, i, i, i);

printf("pi = %f, %e\n", pi, pi);

printf("The value of PI is %f or %e\n", PI, PI);

}

4.3.2 변환 문자의 활용

%f  --->  %[-][m][.][n][l]f

- : 변환된 인수를 왼쪽부터 채운다.	printf("%-7d", 123);

m : 데이터가 출력될 field의 크기.	printf("10d", 123)

. : field 크기와 문자수 or 소수점 이하 구별	printf("%10.5f", 3.14);

n : 소수점 이하 자리수 or 문자열의 폭	printf("%10.3s", □ABCDE");

l : long type integer	printf("%ld", 123);

※ p.73-75 예제 프로그램 참조

4.3.5 scanf 함수

scanf(제어문자열, 인자-1, 인자-2, ..., 인자-n);

① 변환문자는 printf 함수와 유사하며 다른 점은 아래와 같다.

1. %g는 허용하지 않음

2. %f와 %e는 동일하다.

3. %h --- short int를 입력

② 단순변수(정수, 실수, 문자)에 대한 입력은 변수 명칭 앞에 &를 붙인다.

③ 문자열(문자형 배열)에 대한 입력은 &를 사용하지 않는다.

※ scanf에서 각 data를 구분하는 delimiter는 blank, tab, 또는 newline 문자이다.

단, %c는 예외이다. 또한, string 입력시에 한 단어만 입력되는 것에 주의할 것!!!

※ scanf 함수 사용시 주의할 점

1. 정수나 실수를 입력할 때 주로 사용.

2. 문자를 입력할 때는 getchar, 문자열(string)을 입력할 때는 gets를 사용

3. scanf와 다른 함수(getchar, gets 등)를 같이 사용할 때 주의해야 한다.

※ C 언어에서 출력 함수는 printf가 주로 사용되지만,

입력 함수는 scanf가 가장 많이 사용되는 것은 아니다.

※ scanf("%c %d %d", &c, &i, &j); 에 대한 입력 데이터

□A 10 20B 30 40□는 허용되나 □A 10 20<Enter>B 30 40□ or □A 10 20 B 30 40□ 등

20과 B사이에 space가 삽입되면 안됨.

예제 프로그램: scanf 함수를 사용한 program

#include <stdio.h>

main()	/* Example of scanf 함수 */

{

char name[30];

char class;

short number;

printf("Input name, class, number = ");

scanf("%s %c %d", name, &class, &number);	/* sskang A 123 */

/* "%s %c %d"를 "%s%c%d"로 고치면 어떻게 될까? */

printf("%s, %c, %d\n", name, class, number);

}

제5장 연산자, 산술식, 문

5.1 소개

1. primary 연산자 : (), [], ->(구조체의 포인터), .(구조체의 항목)

2. 단항 연산자    : !, ~, ++, --, -, (type명), *(포인터), &(주소 연산자), sizeof

3. 곱셈, 나눗셈   : *, /, %(나머지 연산자)

4. 덧셈, 뺄셈     : +, -

5. shift 연산자   : <<, >>

6. 비교 연산자    : <, <=, >, >=

7. 등가 연산자    : ==, !=

8. bit 연산자     :	& (bitwise AND)

^ (bitwise XOR)

| (bitwise OR)

9. 논리 연산자    :	&& (logical AND)

|| (logical OR)

10. 조건 연산자   : ?:

11. 치환 연산자   : =, +=, -=, *=, /=, %=

>>=, <<=, &=, ^=, |=

12. comma 연산자  : ,

※ 각 연산자의 우선순위는 번호 순서대로 숫자가 낮을수록 높다.

결합규칙은 2, 10, 11번만 우결합 규칙이고 나머지는 좌결합 규칙이다.

5.2 기본적인 연산자

1. 치환 연산자

int i, j, k, n;

i = 20;

j = k = n = 0;

2. 덧셈, 뺄셈, 곱셈, 나눗셈	□	#include <stdio.h>

□

int i, j, x, y, z;        □     main()	/* 1∼20까지 각 숫자의 제곱 계산 */

□     {

i = 100;                  □	int i = 1;

j = 200;                  □

x = i + j;                □	while (i < 21) {

y = i - j;                □	printf(" %10d : %10d\n", i, i*i);

z = x + y - i / 3 * 4;    □	i = i + 1;

□	}

□	}

※ 정수의 나눗셈은 소숫점 이하를 버린다.  --->  5/4와 5./4., 7/4와 7./4.는 다르다.

※ 연산의 우선순위는 연산자의 우선순위 규칙에 따른다.

5.3 기타 연산자

1. modulus 연산자 : %

정수 나눗셈에서 나머지 값

예제 프로그램: 초를 분과 초로 변환하는 프로그램

#include <stdio.h>

#define	SM	60	/* 1분은 60초 */

main()

{

int sec, min, left;

printf("Input seconds = ");

scanf("%d", &sec);

min = sec / SM;

left = sec % SM;

printf("%d seconds = %d minute %d sec.\n", sec, min, left);

}

2. 증감 연산자 : ++, --

i++;	++i;	/* i = i + 1; */

i--;	--i;	/* i = i - 1; */

예제 프로그램: 1∼20까지 제곱을 계산하여 역순으로 출력

#include <stdio.h>

main()	/* 1∼20까지 제곱을 계산하여 역순으로 출력 */

{

int i = 20;

while (i > 0) {

printf(" %10d : %10d\n", i, i*i);

i = i - 1;	/* i--; 또는 --i; */

}

}

예제 프로그램: i++와 ++i의 차이점  ---  값을 사용후 증가 or 증가후 사용

#include <stdio.h>

main()

{

int a = 1, b = 1;

int aplus, plusb;

aplus = a++;

plusb = ++b;

printf("aplus = %d, plusb = %d\n", aplus, plusb);

}

※ 결과가 모호한 경우에는 증감 연산자의 사용을 피할 것 !!!

예) ans = num/2 + 5 * (1 + num++);

printf("%d, %d\n", num, num*num++);

3. comma 연산자  ---  순서대로 연산

i = (j = 15, j + 4);	--->	/* j = 15; i = j + 4; 와 동일함 */

4. 관계 연산자, 논리 연산자  ---  연산 결과는 0(거짓) 또는 1(참)

① 관계 연산자	---  <, <=, >, >=, ==, !=

i > 0, i >= 10, i == 0, i != 0 등

② 논리 연산자	---  &&, ||, !

(c >= 'A') && (c <= 'Z')

!((c < 'A') || (c > 'Z'))

5. bit 연산자  ---  <<, >>, &, |, ^, ~

① shift 연산자  ---  <<, >>

short i, j, k;

i = 0x41;

j = i << 1;

k = i >> 1;

② AND(&), OR(|), XOR(^), 1의 보수(~)

char c, d, e, f, g;

c = 0x41;	/* c = □A'; */

d = c | 0x20;	/* d = tolower(c); */

e = d & 0xdf;	/* e = toupper(d); */

f = c ^ 0xff;

g = ~c;

6. 치환 연산자  ---  =, +=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=

□변수 = 변수 op 수식;□ 인 경우에 축약하여 사용 가능.

i += 10;	/* i = i + 10; */

x -= y + 5;	/* x = x - y + 5; */

c |= 0x20;	/* c = c | 0x20; */

7. 조건 연산자

i = (i > 0) ? i : -i;	/* i의 절대값 */

max = (x > y) ? x : y;	/* x,y 중에서 큰 값 */

※ p.110 예제 참조  ---  산술연산자의 사용 예

5.4 수식과 문장

5.4.1 수식(expression)

수식은 연산자(operator)와 피연산자(operand)로 이루어진다.

4

-6

5 + 23

a * (b + c / d) / 20

q = 5 * 2

x = ++q % 3

q > 3

5.4.2 문장(statement)

문장은 프로그램의 기본 요소가 된다.

C 프로그램의 문장의 끝은 ;에 의해 구별된다.

예제 프로그램: 여러 가지 문장의 예

#include <stdio.h>

main()	/* 1부터 20까지 정수의 합 */

{

int count, sum;	/* 선언문 */

count = 0;	/* 치환문 */

sum = 0;

while (count++ < 20)	/* while 문 */

sum += count;

printf("sum = %d\n", sum);	/* 함수문 */

}

※ 프로그램 작성: 1부터 n까지 각 숫자의 제곱에 대한 합을 구하시오.

예) n을 읽어들여서 n=2이면 5, n=3이면 14, n=4이면 30을 출력하는 프로그램

5.4.3 복문(compound statement 또는 block)

중괄호 {}에 의해 둘러싸인 문장

위 예제 프로그램의 while문을 복문으로 고쳐 쓰면

while (count < 20) {

count++;

sum += count;

}

5.5 수형(data type) 변환

수형 변환(type conversion) 규칙

1. 두 가지 수형을 수반하는 연산에서 높은 수형으로 변환이 일어난다.  -->  promotion

2. 수형의 우선순위를 높은 것부터 나열하면 다음과 같다.

double, float, long, int, short, char

unsigned는 signed보다 순위가 높다.

3. 치환문에서 연산의 최종 결과는 치환될 변수의 수형으로 변환된다.

promotion 혹은 demotion이 일어날 수도 있다.

※ demotion은 문제점을 야기할 수 있다.

예) char 변수에 255보다 큰 수를 assign하면 ???

예제 프로그램: 수형 변환의 예

#include <stdio.h>

main()	/* automatic type conversion */

{

char ch;

int i;

float fl;

fl = i = ch = 'A';

printf("ch = %c, i = %d, fl = %2.2f\n", ch, i, fl);

ch = ch + 1;

i = fl + 2 * ch;

fl = 2.0 * ch + i;

printf("ch = %c, i = %d, fl = %2.2f\n", ch, i, fl);

ch = 2.0e30;

printf("Now ch = %c\n", ch);

}

cast operator --- 수동으로 수형 변환

예) int i, j;

i = 1.6 + 1.7;	/* i = 3 */

j = (int) 1.6 + (int) 1.7;	/* j = 2 */

예제 프로그램: cast operator 사용 예

#include <stdio.h>

main()	/* 1부터 20까지 1/n 값을 계산 */

{

int i = 0;

while (i++ < 20)

printf("1/%d = %5.3f\n", i, 1.0 / (float) i);

}

제6장 입출력 함수와 리디렉션

6.1 단일 문자의 입출력  ---  getchar(), putchar()

- 함수 getchar()는 keyboard에서 읽어온 문자를 return한다.

- 함수 putchar()는 한 문자를 인자로 받아 화면에 출력한다.

예제 프로그램: keyboard에서 한 문자를 읽어 화면에 표시

#include <stdio.h>

main()

{

char ch;

ch = getchar();

putchar(ch);

}

6.2 버퍼(buffer)

- scanf()나 getchar()는 <Enter> 키를 누른 다음에야 데이터가 입력된다.

( <Enter> 키 이전까지의 데이터가 input buffer라고 하는 임시기억장소에

저장되었다가 <Enter> 키를 누르면 program으로 데이터가 전송된다. )

- 위 예제 프로그램을 실행했을 때 여러 문자를 입력하더라도 <Enter> 키를

입력해야만 getchar()가 실행된다.

- scanf(), printf(), getchar(), putchar()는 buffered I/O 함수이고,

getch(), getche(), putch()는 unbuffered I/O 함수이다.

6.3 심화 학습

예제 프로그램: keyboard에서 문자를 읽어 □*□가 입력될 때까지 출력

#include <stdio.h>

main()	/* 문자 □*□가 입력될 때까지 문자들을 입력하는 프로그램 */

{

char ch;

ch = getchar();	□	while ((ch = getchar()) != '*')

while (ch != □*□) {	□	putchar(ch);

putchar(ch);	□

ch = getchar();	□

}

}

1) 위 프로그램 수정 : 읽어들인 문자의 수를 count하여 출력하는 프로그램으로 고쳐 쓰시오.

2) STOP 문자를 □\n□으로 바꾸면 한 line을 읽어 들인다.  ---  <Enter> 키가 입력될 때까지

3) STOP 문자를 EOF로 바꾸면 end-of-file 문자(ctrl-Z)가 입력될 때까지 문자를 읽어들인다.

6.4 입출력 방향 전환

- scanf(), printf(), getchar(), putchar() 등 표준 입출력 함수는

표준 입력장치(keyboard: stdin)과 표준 출력장치(moniter: stdout)으로 입출력을 한다.

- 표준 입력 or 표준 출력을 file 입출력으로 전환하는 것을 입출력 방향 전환이라 한다.

6.5 입출력 방향 전환 예

입력 방향전환 기능 : <

출력 방향전환 기능 : >

- 6.3절 프로그램의 실행 파일이 test.exe라 할 때 다음과 같이 실행해 보자.

C> test

C> test < c:\autoexec.bat

입력 방향을 파일 c:\autoexec.bat로 전환

C> test > newfile.txt

출력 방향을 파일 newfile.txt로 전환

C> test < c:\autoexec.bat > newfile.txt

C> test > newfile.txt < c:\autoexec.bat

입-출력 방향을 모두 파일로 전환

※ 방향전환 문자의 양쪽에 있는 blank는 없어도 된다.

6.6 시스템 종속적인 I/O  ---  IBM-PC의 I/O 포트

- IBM-PC는 keyboard, 모니터 외에도 HDD, FDD, 내부 memory, timer, speaker 등

CPU와 주변장치간에 통신할 필요가 있다.

이 때 CPU와 주변장치간의 통신은 입출력 포트(I/O port)를 통해서 이루어진다.

I/O port는 65536개가 있다.

- speaker는 97번 port에 의하여 제어된다.

예제 프로그램: 시간지연을 이용하여 □삑□ 소리를 내는 프로그램

#include <dos.h>

#include <stdio.h>

#define LIMIT	2000000

main()

{

int store;

long count = 0;

store = inp(97);

outp(97, 79);

while (count++ < LIMIT)	/* 시간 지연 loop */

;

outp(97, store);

}

제7장 if문과 switch문

7.1 if문

if (조건식)

문장;	/* 또는 { 문장1; 문장2; ...; 문장n } */

else

문장;	/* 또는 { 문장1; 문장2; ...; 문장n } */

※ else 부분은 생략이 가능하다.

예)	if (age < 0)

printf("Error\");	/* simple statement */

if (age > 60) {	/* compound statement */

printf("He is too old");

printf("and hard to get a job.\n");

}

예제 프로그램: 입력된 line의 수를 세는 program

#include <stdio.h>

main()

{

int ch;

int linecount = 0;

while ( (ch = getchar()) != EOF )

if (ch == '\n') linecount++;

printf("I counted %d lines.\n", linecount);

}

※ 위 프로그램을 입력된 line수 및 문자수를 세는 program으로 수정

7.2 else를 사용한 if문

예제 프로그램: 간단한 암호화 program

#include <stdio.h>

main()

{

int ch;

while ( (ch = getchar()) != EOF ) {

if (ch == '\n') putchar(ch);

else putchar(ch+1);

}

}

※ if-else는 중첩될 수 있으며, 이 때 else는 가장 가까운 if와 match된다.

if (i > 0)	if (i > 0) {

if (i < 10)	if (i < 10)

printf("0 < i < 10!\n");	printf("0 < i < 10!\n");

else	} else

printf("i >= 10\n");	printf("i >= 10\n");

if (score < 1000)                                if (score < 1000)

bonus = 0;	bonus = 0;

else                                             else if (score < 1500)

if (score < 1500)	bonus = 1;

bonus = 1;                      else if (score < 2000)

else	bonus = 2;

if (score < 2000)                else if (score < 2500)

bonus = 2;	bonus = 4;

else                             else

if (score < 2500)	bonus = 6;

bonus = 4;

else

bonus = 6;

※ 조건식에는 관계 연산자와 논리 연산자가 주로 사용된다.

관계 연산자  ---  <, <=, >, >=, ==, !=

논리 연산자  ---  &&, ||, !

if (ch >= 'A' && ch <= 'Z')

putchar(ch | 0x20);	/* 대문자 --> 소문자 변환 */

else if (ch >= 'a' && ch <= 'z')

putchar(ch - 0x20);	/* 소문자 --> 대문자 변환 */

※ 참, 거짓이란 무엇인가?  관계 or 논리 연산 결과

- 관계 및 논리 연산 결과는 항상 0 또는 1이다.

- 조건식의 참 or 거짓은 연산결과가 0이면 false로, 0이 아니면 true로 판단한다.

예제 프로그램: 관계-논리 연산 결과의 true, false값

#include <stdio.h>

main()

{

int true, false;

true = (5 > 0);

false = (5 == 3);

printf("true = %d, false = %d\n", true, false);

if (1) printf("1 means true.\n");

if (0) printf("0 means true.\n);

if (25) printf("25 is true.\n);

if (-7) printf("-7 is true.\n");

}

※ 0 이외의 모든 값은 true로 간주한다.

if (i != 0)	□□□□□□	if (i)

.....	.....

if (i == 0)	□□□□□□	if (!i)

.....	.....

if (i = 10)	/* 주의: error */

.....

※ C 언어의 논리식은 왼쪽에서 오른쪽으로 평가한다.

while ( (c = getchar()) != EOF && c != '\n' )

.....

※ 195 page  ---  char/word/line count 프로그램 참조

7.8 switch와 break문

switch (수식) {	switch (ch) {

case 값1:                       case 'A':

문장;	printf("Apple\n");

break;	break;

case 값2:                       case 'B':

문장;	printf("Banana\n");

break;	break;

......                          case 'C':

case 값n:	printf("Coconut\n");

문장;	break;

break;                  default:

default:	printf("Watermelon\n");

.....	break;

}                               }

※ default 부분은 생략 가능

제8장 loop문과 기타 제어문

8.1 while문

while (수식)

문장;	/* 또는 { 문장1; 문장2; ...; 문장n } */

int i = 0;	□	int i = 0;

□

while (i < 5)	/* 무한 loop */	□	while (i++ < 5)

printf("Good morning\n");	□	printf("Good morning\n");

int i = 0, sum = 0;	□	int i = 0, sum = 0;

□

while (i++ < 10) sum += i;	□	while (i < 10) {

printf("sum = %d\n", sum);	□	i++;

□	sum += i;

□	}

□	printf("sum = %d\n", sum);

char c = 0x20;	/* blank */

while (c < 0x80) {	/* Ascii 문자를 순서대로 출력 */

putchar(c++);

if (!(c % 8)) putchar('\n');

}

8.2 알고리즘과 의사 코드

알고리즘 : 문제를 해결하는 과정 ( program의 개략적인 내용 )

사용자가 선택한 임의의 숫자를 알아 맞추는 프로그램 : p.221

algorithm-1

1. 사용자에게 숫자를 선택하게 한다.

2. 컴퓨터는 1을 그 수로 추측하고

3. 추측이 틀리면 값을 1씩 증가시키면서 확인한다.

algorithm-2

1. 최소값을 1, 최대값을 100으로 한다.

2. 사용자가 숫자를 선택하게 한다.

3. 추측값 = (최소값 + 최대값) / 2 로 하여 사용자에게 확인.

4. 추측이 틀리면 다음 과정을 반복하여 실행한다.

4.1 추측값이 크면, 최대값 = 추측값 - 1

4.2 추측값이 작으면, 최소값 = 추측값 + 1

4.3 새추측값 = (최소값 + 최대값) / 2

8.3 for문

for (초기화; 수식; 변경부)

문장;	/* 또는 { 문장1; 문장2; ...; 문장n } */

- 초기화 부분은 for loop가 시작될 때 한 번 실행된다.

- 수식은 while문의 수식과 동일함 --- 계속 반복할 것인지를 검사

- 변경부는 for loop의 body를 실행한 후에 실행해 주는 문장이다.

예제 프로그램: 1부터 n까지의 합

#include <stdio.h>	#include <stdio.h>

main()	/* sum of 1 to n */                           main()	/* sum of 1 to n */

{                                                     {

int i, n;	int i, n;

long sum=0;	long sum=0;

printf("Input a integer : ");	printf("Input a integer : ");

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

for (i=1; i <= n; i++)	for (i=n; i > 0; i--)

sum += i;	sum += i;

printf("sum of 1 to n = %ld\n", sum);	printf("sum of 1 to n = %ld\n", sum);

}	}

for문의 융통성

1. 증감부에서 증가(++), 감소(--) 연산자 사용 가능

증감 단위는 1뿐 아니라 2 또는 10 등 원하는대로 가능

2. 숫자 대신 문자 사용 가능

for (ch = ' '; ch <= 'z'; ch++)

printf("ASCII value for %c = 0x%x\n", ch, ch);

3. 조건검사 수식은 계산결과로 참/거짓을 판별할 수 있는 아무 수식이나 가능

for (n = 1; n*n*n <= 1000; n++) ...

4. 초기화, 수식, 증감부는 비어있어도 된다.

( 초기화, 수식, 변경부는 모두 생략할 수도 있다. )

for (;;) ;	/* 무한 loop : null 문장 */

while (1) ;	/* while문은 □수식□ 생략 불가 */

5. 초기화, 증감부는 comma 연산자 사용 가능

for (i=1, sum=0; i <= n; i++) ...

※ for문은 while문을 일반화한 것이다  ---> 모든 while문은 for문으로 변환 가능

예제 프로그램: Zeno의 역설 --- 화살은 과녁에 도달할 수 없다?

#include <stdio.h>

main()	/* 화살이 과녁까지 반을 도달하는데 걸리는 시간을 1초라고 가정 */

{

int count=1;

float sum, x;

for (sum=0.0, x=1.0; count <= 100; count++, x *= 2.0) {

sum += 1.0 / x;

printf("[%d] sum = %f\n", count, sum);

}

}

8.4 do∼while문

do

문장

while (수식);

※ do∼while문과 while문의 다른 점 --- 조건검사 시기

do∼while문의 body부는 1회 이상 실행되나, while문과 for문은 0회 이상 실행된다.

※ 아래 2 문장의 차이점은?

do {	ch = getchar();

ch = getchar();	while ( ch != '\n' ) {

putchar(ch);	putchar(ch);

} while ( ch != '\n' );	ch = getchar();

}

8.5 어떤 loop를 사용할까?	필요에 따라 선택해서 사용

8.6 중첩된 loop (nested loop)

for, while, do-while문은 중첩이 가능하다.

( for/while/do-while문의 body부에 for/while/do-while문을 사용 가능 )

예제 프로그램: sn = 1 + (1+2) + (1+2+3) + ... + (1+2+...+n)

int i, j, n;

long si, sn;

printf("Input n : ");

scanf("%d", &n);

for (i=1, sn=0; i <= n; i++) {

for (j=1, si=0; j <= i; j++) si += j;

sn += si;

}

예제 프로그램: 1부터 n까지 사이에 있는 모든 prime number를 출력

1. 정수 i가 prime number인지를 판별하는 program

for (divisor = 2; i % divisor != 0; divisor++)

;	/* number를 2,3,4,...로 나누어 나머지가 0인 숫자를 구함 */

if (divisor == i)

printf("%d is a prime number.\n", i);

else

printf("%d is NOT a prime number.\n", i);

2. 1부터 n까지 prime number 판별 및 출력

for (i = 2; i <= n; i++) {	/* for (i = 1; i <= n; i += 2) { */

for (divisor = 2; i % divisor != 0; divisor++)

;

if (divisor == i)

printf("%d is a prime number.\n", i);

}

3. 1부터 n까지 prime number를 한 줄에 5개씩 출력

if (divisor == i)

printf("%d is a prime number.\n", i);

===>

if (divisor == i) {

printf(" %5d", number);

if (++count % 5 == 0) putchar('\n');	/* count=0으로 초기화 */

}

8.7 기타 제어문: break, continue, goto

break문 --- 가장 안쪽 loop를 빠져 나간다.

while ( (ch = getchar()) != EOF ) {

if ( ch == '\n' )

break;	/* LF 문자가 입력되면 loop exit */

putchar(ch);

}

continue문 --- loop의 조건검사 부분으로 jump

continue문 이후의 나머지 부분을 실행하지 않고 loop 계속

while ( (ch = getchar()) != EOF ) {

if ( ch == '\n' )

continue;	/* LF 문자면 나머지는 건너뜀 */

putchar(ch);

}

goto문 --- label이 붙은 문장으로 jump

goto next;

......

next:	/* label은 :으로  */

printf("Next process begins.\n");

※ goto문은 가급적 사용하지 않는 것이 좋다 ( goto-less programming )

※ 중첩된 loop를 모두 빠져나갈 때는 유용하게 사용됨.

8.8 배열 (array)

하나의 이름(배열 이름)으로 여러 개의 data를 저장

예) char name[50];   int score[100];   float rains[365];

예제 프로그램: n개의 정수를 읽어서 합, 평균, 가장 큰값을 구하는 program

#include <stdio.h>

main()	/* calculate the sum, average, highest data */

{

int n, data[100];

long sum, highest;

float average;

int i;

printf("Input number of data : ");

scanf("%d", &n);

for (i = 0; i < n; i++)	/* input data */

scanf("%d", &data[i]);

printf("Data = ");

for (i = 0; i < n; i++)	/* print-out data */

printf("%5d ", data[i]);

putchar('\n');

for (i = 0, sum = 0; i < n; i++)	/* sum & average */

sum += data[i];

average = (float) sum / (float) n;

printf("sum = %ld, average = %.2f\n", sum, average);

highest = data[0];

for (i = 0; i < n; i++)

if (data[i] > highest) highest = data[i];

printf("highest data = %d\n", highest);

}

8.9 data 입력 방법

1. data를 입력하기 전에 data의 수를 먼저 입력

2. data의 끝을 나타내는 값(정수의 경우 -1, 문자의 경우 □$□ 등)을 정해서

그 값이 입력되면 그 때까지 입력된 data의 수를 count하는 방법

제9장 함 수

9.1 간단한 함수를 만들어 사용하는 법

#include <stdio.h>

#define NAME	"Hong, Kildong"

#define SCHOOL	"School of Information & Computer Eng., Hansung Univ."

#define ADDRESS	"389 Samsun-dong 2ga, Sungbuk-gu, Seoul 136-792, Korea"

#define LINESIZE	65

main()

{

starbar();

puts(NAME);

puts(SCHOOL);

puts(ADDRESS);

starbar();

}

starbar()

{

int count;

for (count=0; count < LINESIZE; count++)

putchar('*');

putchar('\n');

}

9.2 함수 인자

NAME, SCHOOL, ADDRESS를 centering해서 print

space(n)	/* print-out n blanks */

int n;

{

int i;

for (i = 0; i < n; i++) putchar(' ');

}

각 문자열을 출력하기 전에 space(LINESIZE-strlen(문자열)/2); 를 실행

□ 형식인자(formal parameter) --- 함수 정의에서 사용된 인자

□ 실인자(actual parameter)    --- 함수 호출에서 사용된 인자

9.3 함수로부터 결과값 반환 : return문

□ 정수의 절대값을 계산하는 함수 : abs(x)

□ 두 실수의 합을 계산하여 반환하는 함수 : plus(x, y)

□ xy를 계산하여 결과를 반환하는 함수 : power(x, y)

n개의 정수를 읽어서 합, 평균, 가장 큰값을 구하는 program

#include <stdio.h>

#define MAXDATA	100

long SumOfData();

int HighestData();

main()	/* sum, average, highest data */

{

int n, data[MAXDATA];

long sum, highest;

float average;

printf("Input number of data : ");

scanf("%d", &n);

InputData(data, n);

PrintData(data, n);

sum = SumOfData(data, n);

average = (float) sum / (float) n;

highest = HighestData(data, n);

printf("sum = %ld, average = %.2f\n", sum, average);

printf("highest data = %d\n", highest);

}

InputData(data, n)	/* n개의 data를 입력 */

int data[];

int n;

{

int i;

for (i = 0; i < n; i++)

scanf("%d", &data[i]);

}

PrintData(data, n)	/* 입력된 n개의 data를 출력 */

int data[];

int n;

{

int i;

printf("Data = ");

for (i = 0; i < n; i++)

printf("%5d ", data[i]);

putchar('\n');

}

long SumOfData(data, n)	/* n개의 data의 합 */

int data[];

int n;

{

int i;

long total=0;

for (i = 0; i < n; i++)

total += data[i];

return total;

}

int HighestData(data, n)	/* n개의 data 중에서 가장 큰 것 */

int data[];

int n;

{

int i, max;

max = data[0];

for (i = 0; i < n; i++)

if (data[i] > max) max = data[i];

return max;

}

9.4 지역변수와 전역변수

지역변수 ( local variable )

□ 함수 안에 선언된 변수

□ 그 함수내에서만 사용 가능

전역변수 ( global variable )

□ 함수 밖에서 선언된 변수

□ 변수가 선언된 이후의 모든 함수에서 사용 가능

9.5 주소 연산자 : &

int number = 100;

printf("value = %d, addr = %d\n", number, &number);

9.6 함수 호출시에 인자값의 변경

□ C 언어의 인자전달 방법은 call-by-value이다.

( 실인자의 값을 형식인자에 전달 )

□ 두 변수의 값을 서로 바꾸는 함수 --- interchange(x, y)

두 변수 x, y의 값을 바꾸는 방법

temp = x;

x = y;

y = temp;

......	......

printf("x=%d, y=%d", x, y);	printf("x=%d, y=%d", x, y);

interchange(x, y);	interchange(&x, &y);

printf("x=%d, y=%d", x, y);	printf("x=%d, y=%d", x, y);

......	......

interchange(a, b)	interchange(a, b)

int a, b;	int *a, *b;

{	{

int temp;	int temp;

temp = a;	temp = *a;

a = b;	*a = *b;

y = temp;	*b = temp;

}	}

□ pointer 변수와 pointer 연산자(*)

char *p;	int *q;	float *r;

pointer 변수는 int 크기의 기억장소가 할당되며, 주소가 저장된다.

제10장 Storage Class

10.1 C언어에서 변수의 종류

automatic(자동변수), static(정적변수), extern(외부변수), register

① 자동변수

- 함수 호출시에 기억장소 할당 --- stack에서 memory 할당

- 함수 실행이 끝나면 자동으로 기억장소 반환

- 대부분의 지역변수는 자동변수가 됨

② 정적변수

- 기억장소를 한번 할당받으면 program의 실행이 끝날 때까지 반환하지 않음

- 지역변수 or 전역변수 선언시에 앞에 static을 덧붙여 줌

static 지역변수 --- 함수 실행 후에도 그 값을 유지하고 있음

static 전역변수 --- 다른 file에서 그 변수를 access할 수 없음

※ 정적변수와 자동변수의 차이 : 예제 프로그램

#include <stdio.h>

main()

{

printf("static var.	auto var.\n");

printf("-----------------------\n");

sub();

sub();

sub();

}

sub()

{

static int i = 1;

auto   int j = 3;

printf(" i = %d	j = %d\n", i, j);

i++; j++;

}

③ 외부변수

다른 file에서 선언된 전역변수를 access할 때 사용 ( p.353 참조 )

④ register 변수

- 변수에 대한 기억장소를 CPU내에 있는 register에 할당

- 자주 사용되는 변수의 access 속도를 빠르게 할 때 사용

- 자동변수와 함수의 형식인자에 대해서만 허용

10.2 난수 함수 : rand(), srand()

static int randx = 1;	/* seed 초기화 */

rand()	/* random 함수: <stdlib.h>에도 있음 */

{

randx = ( randx * 25173 + 13849) % 65536U;

return (int) randx;

}	/* 밑줄친 숫자는 prime number로 사용하는 것이 좋음 */

※ 위 rand() 함수의 문제점 --- 항상 동일한 순서대로 난수를 발생시킴

srand(x)	/* seed 값을 변경하는 함수 */

unsigned x;

{

randx = x;

}

main()	/* 난수함수 test program */

{

int seed, i;

printf("Input seed value for random number generation : ");

scanf("%d", &seed);

srand(seed);

for (i = 0; i < 10; i++) printf("%d\n", rand());

}

10.3 주사위 게임

기하학적으로 가능한 주사위: 4/6/8/12/18면 5가지만 가능 ( 컴퓨터로는 n면 주사위 가능 )

#define SCALE	32768.0

int rollem(sides)	/* sides면을 갖는 주사위 */

int sides;

{

float roll;

/*	10.2절의 rand() 함수 이용

-32768 <= rand() < 32768

---> -1 <= rand()/SCALE < 1

--->  0 <= rand()/SCALE+1.0 < 2

--->  0 <= (rand()/SCALE+1.0)*sides < 2*sides

--->  0 <= (rand()/SCALE+1.0)*sides/2.0 < sides

--->  1 <= (rand()/SCALE+1.0)*sides/2.0+1.0 < sides+1

*/

roll = ( (float) rand() / SCALE + 1.0 ) * sides / 2.0 + 1.0;

return (int) roll;

}

main()	/* dice rolling program */

{

int dices, sides;

int count, score, seed;

printf("Input seed value : "); scanf("%d", &seed);

srand(seed);

printf("Input sides of a dice : "); scanf("%d", &sides);

while ( sides > 0 ) {

printf("Input number of dices : "); scanf("%d", &dices);

for ( score = count = 0; count < dices; count++ )

score += rollem(sides);

printf("Using %d-side %d dices, your score is %d.\n",

sides, dices, score);

printf("Input sides of a dice (0 to quit) : ");

scanf("%d", &sides);

}

puts("Thank you!");

}

10.4 정수 입력 함수 : getint()

#include <stdio.h>

#define LENG	80

#define STOP	-1

#define NONUM	0

#define YESNUM	1

int getint(pint)	/* fetch integer string and */

int *pint;	/* convert it to an integer */

{

char intarr[LENG];

int ch;

int ind = 0;

ch = getchar();

while ( ch == '\n' || ch == ' ' || ch == '\t' )

;	/* skip blanks, tabs, new-line characters */

while ( ch != EOF && ch != '\n' && ch != ' ' && ind < LENG ) {

intarr[ind++] = ch;

ch = getchar();

}

intarr[ind] = '\0';

if ( ch == EOF ) return STOP;

else return stoi(intarr, pint);

}

int stoi(string, intptr)	/* convert string to integer */

char string[];	/* string of digits */

int *intptr;	/* integer value for 'string' */

{

int sign = 1;

int index = 0;

if ( string[index] == '-' || string[index] == '+' )

sign = (string[index++] == '-') ? -1: 1;

*intptr = 0;

while ( string[index] >= '0' && string[index] <= '9' )

*intptr = 10 * (*intptr) + string[index++] - '0';

if ( string[index] == '\0' ) {

*intptr = sign * (*intptr);

return YESNUM;

} else

return NONUM;

}

main()

{

int num, status;

puts("Get integer from keyboard.");

puts("Input integers and press <Enter>.");

while ( (status = getint(&num)) != STOP ) {

if ( status == YESNUM )

printf("Integer %d is fetched.\n", num);

else

printf("Input string NOT an integer\n");

}

}

※ 난수 함수 rand(), srand()를 별개의 file로 독립시켜 compile, link해 보자.

정수 입력 함수 getint(), stoi()를 별개의 file로 독립시켜 compile, link해 보자.

10.5 sorting ( 정렬 )

#include <stdio.h>

#define MAX	100

main()

{

int n, data[MAX];

n = getData(data, MAX);

sort(data, n);

putData(data, n);

}

getData(data, limit)	/* input n integers */

int data[], limit;

{

int i = 0;

while ( i < limit ) {

scanf("%d", &data[i++]);

if ( data[i++] == -999 ) return i-1;

}

}

sort(data, n)	/* interchange sort: ascending order */

int data[], n;

{

int i, j;

for ( i = 0; i < n-1; i++ )

for ( j = i+1; j < n; j++ )

if ( data[i] > data[j] )

interchange(&data[j], &data[i]);

}	/* 함수 interchange는 9.6절에 있음 */

putData(data, n)

int data[], n;

{

int i;

for ( i = 0; i < n; i++ )

printf("\t%d\n", data[i]);

}

※ data file(예: sample.dat)에 sort하고자 하는 정수를 나열하여 입-출력 방향 전환으로 실행.

( 끝 표시를 위한 data는 -999 )

※ 함수 getData와 putData는 file 'getput.c', 함수 sort는 'sort.c', 함수 main은 □main.c'로

작성하여 TC에서 project를 이용하여 compile 하시오.

1. 파일 <이름>.prj를 작성하고 <이름>.prj에는 C source 파일들의 이름만 나열한다.

예) test.prj --- main.c getput.c sort.c

2. TC에서 project name을 <이름>.prj로 하고 compile 한다.

※ TCC로 각 파일을 compile하여 TLINK로 link하여 실행 파일을 만드시오.

제11장 C의 선행처리기

11.1 Macro 정의 : #define문

#define PI	3.14

#define MAX	100

#define YES	1

#define NO	0

※ 매크로 확장 : C preprocessor ---- #include, #define 등 # 로 시작되는 문장 처리

11.2 인자를 갖는 #define

#define PI	3.14159

#define MAX(x, y)	(x > y) ? x : y

#define SQUARE(x)	(x * x)	/* ==> ((x) * (x)) */

#define CIRCLE_AREA(r)	(2 * PI * r)

main()

{

int i = 5;

float area;

printf("%d\n", MAX(i, 10));

area = CIRCLE_AREA((float) i);

printf("%5.2f\n", area);

while (i)	/* squares of i from i to 1 : ERROR? */

printf("%d\n", SQUARE(i--));

}

※ 위 while문을 debugging 하시오.

while (i--) printf("%d\n", SQUARE(i+1));  /* ERROR? */

※ SQUARE(x)를 (x * x)로 하는 것과 x * x로 할 때 차이점은?

100 / SQUARE(5)

※ 인자가 있는 macro의 각 인자는 모두 괄호로 싸 주는 것이 좋다.

#define MAX(x, y)	( (x) > (y) ? (x) : (y) )

#define ABS(x)	( (x) < 0 ? -(x) : (x) )

11.3 macro와 함수의 차이점

macro는 확장에 의하여 호출된 위치에 정의부로 대치한다.

( 호출된 횟수만큼 in-line code가 생성되므로 memory 낭비 )

함수는 code를 하나만 생성하여 호출되면 그 code로 jump --> 실행 --> return

※ macro는 memory 낭비 대신 실행이 빠르고, 함수는 memory 절약 대신 실행이 늦다.

11.4 파일 포함 기능 : #include

#include <stdio.h>	/* 표준 system 디렉토리에서 파일을 찾음 */

#include "mydef.h"	/* 현재 디렉토리에서 파일을 찾음 */

#include "c:\work\c\mydef.h"	/* 지정된 디렉토리에서 파일을 찾음 */

※ include되는 파일을 header file이라 하며, 일반적으로 확장자를 *.h 로 한다.

/* file 'mytype.h' */

#define BOOL	int

#define TRUE	1

#define FALSE	0

/* file 'test.c' */

#include "mytype.h"

BOOL whitespace(c)

char c;

{

if ( c == ' ' || c == '\n' || c == '\t' )

return TRUE;

else	return FALSE;

}

11.5 기타 : #undef, #if, #ifdef, #ifndef, #else, #endif

#undef	---  #define에 의하여 정의된 이름을 해제한다.

#define MAX	100

#define PI	3.14

......	/* MAX는 100으로 정의됨 */

#define MAX	200

......	/* MAX는 200으로 중복 정의됨 */

#undef MAX

......	/* MAX는 100으로 정의됨 */

#ifdef, #ifndef, #if, #else, #endif

#ifdef MAVIS

#include "horse.h"

#define STABLES	5

#else

#include "cow.h"

#define STABLES	15

#endif

#if SYS = "IBM"

#include "ibm.h"

#endif

제12장 배열과 pointer

C 프로그래밍 언어

국민대학교 컴퓨터학부 강승식

12.1 배열 ( array )

① 선언(declaration)

int temp[365];

main()

{

float rain[365];

static char code[12];

extern temp[];

......

}

② 배열의 초기화

int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

int *days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };  /* ERROR */

char s[] = "abcde";

char s[] = { 'a', 'b', 'c', 'd', 'e', '\0' };

char *s = "abcde";

char *s = { 'a', 'b', 'c', 'd', 'e', '\0' };  /* ERROR */

③ 배열 access : days[0], days[1], ..., days[11]

12.2 배열에 대한 pointer

#include <stdio.h>

int temp[100] = { 10, 20, 30, 40 };

main()

{

int *p = temp, *q = &temp[0];

printf("temp = %u, p = %u, q = %u\n", temp, p, q);

printf("p+1 = %u, p+2 = %u\n", p+1, p+2);

printf("*p = %d, *(p+1) = %d, *p+1 = %d\n", *p, *(p+1), *p+1);

}

※ *(p+1)과 *p+1은 다르다.

12.3 함수의 배열 인자(parameter)

#include <stdio.h>

int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

main()

{

f(days);  /* 또는 f(&days[0]); */

}

f(pd)

int pd[];  /* 또는 int *pd; */

{

int i;

for (i = 0; i < 12; i++)

printf("%d\n", pd[i]);  /* pd[i] □ *(pd+i) */

}

12.4 배열과 pointer의 차이점

□ 배열 : 배열 크기만큼 memory 할당

배열 이름에는 주소를 assign할 수 없음

□ pointer : 정수 크기(2 or 4 bytes)만큼 memory 할당

pointer 변수에는 주소를 assign할 수 있음

12.5 pointer 연산

int i = 100;

int *p = &i;

① 치환문(assignment) : p = &i;

② value access : *p

③ pointer 변수의 주소 사용 가능 : &p

④ 증감 연산 가능 : p++, --p, p=p+i

⑤ 두 pointer 변수의 차 : p-q

12.6 다차원 배열 (multi-dimensional array)

① 선언(declaration)

short a[10][3];

char  b[10][20][5];

② 초기화

short a[10][3] = { {5, 6}, {7, 8} };

short a[10][3] = { 5, 6, 7, 8 };

③ pointer

short a[10][3] = { {5, 6}, {7, 8} };

short *p = a, *q = a[3];

④ 함수의 인자

main()

{

short a[10][3];

......

f(a);

}

f(x)

short x[][3];  /* 또는 short (*x)[3]; */

{

......

}

<주의> 배열과 구조체의 초기화

전역변수 및 static 변수는 초기화할 수 있으나, 자동변수 및 register 변수는 안된다.

※ pointer의 의미 --> 중요함!

가. int *p;     ---  pointer 변수 p, 정수 크기(2 or 4 bytes) memory, int *가 저장됨

나. int *p[n];   ---  pointer 배열 p, n개의 memory 할당, p[0], …, p[n-1]에 int *가 저장됨

다. int (*p)[n];  ---  pointer 변수 p, 정수 크기(2 or 4 bytes) memory,

크기 n인 정수형 배열 구조를 갖는 주소가 저장됨

라. int *p()[];   ---  함수 p의 선언, □return값이 int pointer 배열□인 함수 p

마. int *p();    ---  함수 p의 선언, □return값이 int pointer□인 함수 p

바. int (*p)();   ---  pointer 변수 p, □return값이 int인 함수□의 주소가 저장됨

사. int (*p[])();  ---  pointer 배열 p, □return값이 int인 함수□의 주소가 저장됨

제13장 STRING (문자열)

□ string --- NULL 문자로 끝나는 문자들의 sequence

string 상수 --- 큰따옴표(")로 둘러싸인 문자들  □  static memory 영역에 할당됨

□ string 초기화

char s[20] = "abcde"; /* { 'a', 'b', 'c', 'd', 'e' } */

char s[] = "abcde";   /* char *s = "abcde"; */

※ char s[20];  s = "abcde";   □   ERROR !!!

char *s = "abc\ndef";

char *s = "c:\\dos\\format.exe";

char *s = "This is a \"test\" string.";

※ 배열과 pointer의 차이점

pointer에 저장되는 주소는 그 값이 변경되거나 다른 주소로 치환할 수 있으나,

배열 명칭은 그 배열에 할당된 memory의 첫번째 주소로 고정되어 변경될 수 없다.

char *p = "abcde";	對   char q[] = "abcde";

① data access시에 둘 다 첨자 또는 pointer 연산자 사용 가능

p[i-1]    q[i+1]    *(p+1)    *(q-1)

② 피연산자로 사용과 치환문은 pointer만 가능 : p+i, p++; --p; p = q;

q+i, q++; --q; q = p; 는 허용되지 않음

□ string 배열 : 다음 3가지 선언문의 차이점은?

① char *names[] = { "김건모", "서태지", "H.O.T", "GOD" };

names[2] == "solid"

*names[2] == 's'

*(names[2]+1) == names[2][1] == 'o'

② char *names[4] = { "김건모", "서태지", "H.O.T", "GOD" };

③ char names[4][20] = { "김건모", "서태지", "H.O.T", "GOD" };

□ string 입력

#include <stdio.h>

main()

{

int i;

char s[100];  /* char *s; 또는 char s[]; 라고 선언하면?? */

scanf("%s %d", s, &i);  /* scanf("%3s %d", s, &i); 로 고치면?? */

printf("%s, %d\n", s, i);

}

□ string 함수 : <string.h>

① ptr = gets(s);  /* return value : char pointer 또는 NULL */

한 line을 입력함 ( line끝의 LF 문자는 제거 )

② puts(s);  /* string s를 stdout으로 출력 --- appends a newline char. */

char *s = "abcdefg"; 로 선언된 string s에 대해서

puts(s+4); 와 puts(&s[4]); 은 모두 "efg"를 출력한 후에 줄바꿈을 한다.

③ n = strlen(s);  /* string s의 문자 개수, cf. sizeof(s) */

④ strcat(s, t);  /* string concatenation : s의 뒤에 t를 이어줌 */

⑤ i = strcmp(s, t);  /* string s와 t가 같으면 i=0이고, 다르면 i≠0 */

if (!strcmp(s,t))

printf("스트링 s와 t는 같다.\n");

else

printf("스트링 s와 t는 다르다.\n");

⑥ strcpy(s, t);  /* string t를 s에 복사 */

제14장 구조체, 공용체, typedef

□ 구조체 (structure)

(1) 구조체 type 선언

struct person {

char name[50];

short age;

char phone[20];

};

main()

{

struct person x;

static struct person y = { "박찬호", 20, "123-4567" };

strcpy(x.name, "선동렬");  /* x.name = "선동렬"; 라고 하면 ERROR */

x.age = 21;

strcpy(x.phone, "234-5678");

......

}

(2) 구조체 배열 : 직접 선언한 예

main()

{

struct person {

char *name;

short age;

char *phone;

} x, y, man[10], woman[20];

man[0].name = "Bill Gates";

man[0].age = 36;

man[0].addr = "1-12-345-6789";

......

}

(3) 중첩된 구조체 ( nested structure )

struct address {

char *nation;

char *city;

char *zipcode;

};

struct person {

char *name;

short age;

char *phone;

struct address addr;

};

main()

{

struct person singer;

singer.name = "김건모□;

singer.age = 35;

singer.addr.nation = "Korea";

singer.addr.city = "서울";

.......

}

(4) 구조체 pointer

#include <stdio.h>

struct person {

char name[50];	/* char *name; 이라 선언하면, p->name = "name"; */

short age;

char phone[20];	/* char *phone; 이라 선언하면, p->phone = "..."; */

};

main()

{

static struct person singer = { "서태지", 28, "molla" };

struct person *p = &singer;

strcpy(p->name, "H.O.T□);

strcpy(p->phone, "789-1234");

printf("가수 %s는 팬들이 많다.\n", p->name);

}

(5) 구조체 list

#include <stdio.h>

struct person {

char name[50];

short age;

char phone[20];

struct person *next;

};

struct person x = { "김건모□, 50, □222-2222□, NULL },

y = { □서태지□, 60, □333-3333□, NULL },

z = { □H.O.T□,  70, □555-5555□, NULL };

main()

{

struct person *head, *p;

/* make a LIST */

head = &x;

x.next = &y;

y.next = &z;

p = head;

while (p) {

printf("%s\n", p->name);

p = p->next;

}

}

(6) 구조체 변수의 parameter passing

#include <stdio.h>

struct person {

char name[50];

short age;

char phone[20];

};

main()

{

static struct person x = { "박세리□, 28, "molla" };

f(x);   /* □ f(&x); */

printf("그녀의 나이는 %d살이다.\n", x.age);

}

f(y)                        □     f(y)

struct person y;            □     struct person *y

{                           □     {

y.age++;            □	y->age++;

}                           □     }

□ 공용체 (union)

구조체와 공용체의 유사점과 차이점은 무엇인가?

#include <stdio.h>

main()

{

union u {

long i;

char c, d;

} x;

x.c = 'A';

x.d = 'B';

printf("%c, %c, %x\n", x.c, x.d, x.i);

x.i = 0x4142;

printf("%c, %c, %x\n", x.c, x.d, x.i);

}

□ 나열형 (enumeration)

#include <stdio.h>

enum yes_no { NO, YES };

enum days   { MON, TUE, WED, THU, FRI, SAT, SUN };

enum months { JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

main()

{

enum yes_no answer;

enum days d;

enum months x;

answer = YES;

d = MON;

x = MAY;

printf("%d, %d, %d\n", answer, d, x);

}

□ typedef

data type에 명칭 부여

typedef float	REAL;

typedef int	BOOL;

typedef unsigned char	BYTE, *PBYTE;

typedef unsigned short	TWOBYTE;

typedef struct person {

char name[50];

short age;

char phone[20];

} HUMAN, *PHUMAN;

typedef signed short	SHORT;

typedef SHORT *	PSHORT;

typedef unsigned short	USHORT;

typedef signed long	SLONG;

typedef unsigned long	ULONG;

- typedef를 이용하는 예제 프로그램

#include <stdio.h>

typedef struct person {

char name[50];

short age;

char phone[20];

} HUMAN, *P_HUMAN;

main()

{

static HUMAN singer = { □김건모□, 30, □789-1234□ };

P_HUMAN p = &singer;

strcpy(p->name, "G.O.D");

p->age = 25;

strcpy(p->phone, "456-7890");

printf("%s, %d, %s\n", p->name, p->age, p->phone);

}

제15장 C 라이브러리와 file 입출력

□ 파일 입-출력 함수

#include <stdio.h>

main()

{

FILE *fp1, *fp2;

int ch;

fp1 = fopen("c:\\autoexec.bat", "r");

fp2 = fopen("newfile.txt", "w");

while ((ch = getc(fp1)) != EOF)

putc(ch, fp2);

fclose(fp1);

fclose(fp2);

}

※ Header file <stdio.h>에 정의되어 있는 FILE type

typedef struct  {

short           level;          /* fill/empty level of buffer	*/

unsigned        flags;          /* File status flags	*/

char            fd;             /* File descriptor	*/

unsigned char   hold;           /* Ungetc char if no buffer	*/

short           bsize;          /* Buffer size	*/

unsigned char   *buffer;        /* Data transfer buffer	*/

unsigned char   *curp;          /* Current active pointer	*/

unsigned        istemp;         /* Temporary file indicator	*/

short           token;          /* Used for validity checking	*/

}       FILE;                           /* This is the FILE object	*/

① fopen(□파일이름□, □연산의 종류□) --- file open ( 파일 access 시작 )

- 파일에 대한 연산의 종류 : □r□, □w□, □a□, □rw□ 등

- return value : FILE pointer 또는 NULL

② fclose(fp) --- file close ( 파일 access 끝 )

③ getc(fp) --- FILE pointer □fp□에서 한 문자를 읽어 온다.

return value는 읽어온 문자의 Ascii code 값

※ ungetc(ch, fp) --- int ch를 FILE *fp에 되돌려 준다.

④ putc(ch, fp) --- FILE pointer □fp□로 문자 □ch□를 출력한다.

※ □stdin□, □stdout□, □stderr□, □stdaux□, □stdprn□은 <stdio.h>에 정의되어 있는 특수한 FILE pointer

<예제> text file에서 매 3번째 문자만 출력하는 program : p.587

⑤ fscanf(fp, ...)와 fprintf(fp, ...)  ---  formatted 파일 I/O

scanf("%s", s);  □  fscanf(stdin, "%s", s);

printf("%s\n", s);  □  fprintf(stdout, "%s\n", s);

⑥ fgets(s, max_chars, fp)와 fputs(s, fp)

gets(s);  □  fgets(s, max_chars, stdin);

puts(s);  □  fputs(s, stdout);

⑦ fseek(fp, offset, base)  ---  파일의 random access 기능

- base(기준점) --- 0: 파일의 시작 위치로, 1: 현재 위치, 2: 파일의 끝

- offset(변위) --- 기준점으로부터 n-번재 byte ( long type )

⑧ fread(ptr, byte_size, n, fp); 와 fwrite(ptr, byte_size, n, fp);

- 파일 fp에서 byte_size 크기인 데이터 n개를 ptr로 read or write

※ exit(err_code) --- 실행 중단 함수, err_code가 0이면 정상적인 실행 끝

※ 기타 library 함수

- 고급 I/O 기능

open(), close(), create(), lseek(), read(), write() 등

- Header file : <ctype.h>

isalpha(ch), isdigit(ch), islower(ch), isupper(ch), isspace(ch),

isalnum(ch), isascii(ch), iscntrl(ch), ispunct(ch), toupper(ch), tolower(ch)

- Header file : <stdlib.h>

atoi(), itoa() --- 문자열 <--> 정수 변환

malloc(bytes), calloc(기억장소의 수, 단위 기억장소의 크기) : <stdlib.h>

heap에서 필요한 byte수 만큼 memory 할당

char *p;

int *q;

p = (char *) malloc(100);

q = (int *) calloc(200, sizeof(int));

<예>   struct XXX { ....... } *str_ptr; 에 대하여

str_ptr = (struct XXX *) malloc(sizeof(struct XXX));

str_ptr = (struct XXX *) calloc(MAX, sizeof(struct XXX));

기타 중요한 기능

□ 명령행 인자(command-line argument)

명령어에 인자를 주는 방법 -- 예) type 명령

아래 예제 프로그램은 명령행 인자로 파일이름을 1개 주면 파일 내용을 화면으로 출력한다.

또한, 파일이름을 2개 줄 경우는 첫 번째 파일을 두 번째 파일로 복사한다.

C> type <파일 이름>

#include <stdio.h>

#define MAXLIN	1024

main(int argc, char *argv[])

{

FILE *fp1, *fp2;

char line[MAXLIN];

switch (argc) {

case 1: fp1 = stdin;

fp2 = stdout;

break;

case 2: fp1 = fopen(argv[1], "r");

fp2 = stdout;

break;

case 3: fp1 = fopen(argv[1], "r");

fp2 = fopen(argv[2], "w");

break;

default:

perror("usage: type <inputfile> <outputfile>\n");

exit(0);

}

while (fgets(line, MAXLIN, fp1)) fputs(line, fp2);

fclose(fp1);

fclose(fp2);

}

□ pipeline 기능을 수행하는 프로그램

파이프라인이란 한 명령의 출력결과를 다른 명령(프로그램)의 입력으로 전달하는 기능이다.

아래 예는 □type□ 명령의 실행결과가 파이프라인 □|□에 의해 □more□의 입력으로 전달된다.

(□filename.txt□가 한 화면을 넘어갈 때 한 화면단위로 보여준다.)

C> type filename.txt | more

표준 입출력을 행하는 프로그램은 모두 pipeline으로 연결될 수 있다. 즉, printf(), scanf(), getchar(), putchar() 등 표준 입출력 함수를 사용한 프로그램이다. 다만, 어떤 프로그램을 pipeline으로 연결할 때는 대화형으로 작동이 불가능하므로 대화형 입출력을 행하는 프로그램은 파이프라인으로 연결하기가 곤란하다.