Functions
효과적인 문제 해결의 정수는 문제 분해다.
이를 위해 함수가 필요하다. (모듈화라고 함)
Function Definition
함수는 함수 프로토타입, 함수 정의(헤더/바디), 함수 call(main)으로 구성된다.
이 중 함수 정의부터 살펴보자.
함수 정의의 골격은 다음과 같다.
type function_name(parameter list)
{
declarations;
statements;
}
예시를 보자
#include <stdio.h>
#include <assert.h>
long fact(int n)
{
int i;
long product = 1;
for (i=2;i<=n;++i) product *= i;
return product;
}
void main(void){
int n, m;
long comb;
scanf("%d%d", &n, &m);
assert(n>=0&&m>=0);
assert(n>=m);
comb=fact(n)/(fact(m)*fact(n-m));
printf("%dC%d=%ld\n", n, m, comb);
}
assert.h 헤더 파일의 assert 함수는 statement가 거짓일 경우에
프로그램을 중단하는 역할을 한다.
전체 프로그램은 조합을 출력하는 것
local variable(internal), global variables(external)
#include <stdio.h>
int a = 33;
int main(void){
int b = 77;
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
여기서 a는 global 변수, b는 internal local 변수이다.
디버깅하기 쉬워지므로
프로그램을 작은 함수로 모듈화하는 게 매우 중요하다.
return statement
return;
return ++a;
return (a*b);
function prototypes
함수 사용 이전에 선언하는 부분
type function_name(parameter type list);
이런 식으로~!
styles for function definition order
call by value
function은 기본적으로 call by value로 사용된다.
function 내부의 value들은 모두 로컬함
#include <stdio.h>
int compute_sum(int n);
int main(void){
int n = 3, sum;
printf("%d\n", n);
sum = comput_sum(n);
printf("%d\n", n);
printf("%d\n", sum);
return 0;
}
int compute_sum(int n){
int sum = 0;
for (;n>0;n--){
sum += n;
}
return sum;
}
위 프로그램에 sum이 두 번 등장하지만,
int compute_sum 함수의 sum은 main에 전혀 영향을 끼치지 못함.
developing a large program
보통 큰 프로그램들은 .h 헤더 파일과 .c 소스 파일로 구성된다.
헤더 파일을 직접 작성한 경우,
.c 파일에서 #include "pgm.h"
같은 형태로 헤더 파일을 포함시키면 된다~
헤더 파일은 컴파일할 필요 없고,
c 파일들은
gcc -o pgm main.c fct.c prn.c 의 형태로 컴파일한다.
scope rule
storage classes
c의 모든 변수와 function은 두가지 속성을 가진다.
바로 type과 storage class
storage class에는 auto, extern, register, static이 있다.
하나씩 살펴보자.
- auto
가장 흔한 storage class
자동으로 automatic이 된다.
block 안으로 들어가면, 시스템에서 메모리를 할당해준다.
block을 나가면, 그 안에 할당된 메모리는 free된다.
- extern
external 변수를 활용하면,
블럭을 넘어서도 변수 등 정보를 전달할 수 있다.
function 밖에서 변수를 정의하면, storage가 영구적으로 변수를 저장하고,
해당 변수는 extern storage class가 된다.
+ global 전역 변수
#include <stdio.h>
int a =1, b=2, c=3;
int f(void);
int main(void){
printf("%3d\n", f());
printf("%3d%3d%3d\n", a, b, c);
return 0;
}
int f(void){
int b, c;
extern int a;
a=b=c=4;
return (a+b+c);
}
extern int a;라는 것은 어딘가에 이미 a라는 전역 변수가 있으니, 잘 찾아보라는 뜻이다.
그리고 이 프로그램은 a, b, c 중 a만이 f 함수의 결과가 반영된 것을 알 수 있음.
- register
높은 스피드의 메모리에 저장되도록 한다.
실행 속도를 높이기 위한 것임
그리고 블록 밖으로 나가면, 해당 변수는 free됨
{
register int i;
for (i=0;i<LIMIT;i++){
...
}
}
- static
정적 변수
다시 블럭에 들어갔을 때 이전의 value를 유지할 수 있도록 한다.
auto variables와 대조적임
void f(void)
{
static int cnt = 0;
++cnt;
if (cnt%2==0)
...
else
}
위 프로그램에서 static 변수 cnt=0은
처음 f()에 들어가면 초기화된다.
그러나 cnt가 정적 변수이기 때문에 두번째 접속할 때에는 초기화되지 않는다.
default initialization
external, static
자동으로 0으로 초기화된다
auto, register
garbage 값을 가지고 있다.
recursion
자기 자신을 다시 부르는 경우 (직간접적으로)
ex) factorial
int factorial(int a){
if (a==1) return a;
else {
return a * factorial(a-1);
}
}
ex) fibonacci
int fibonacci(int a){
if (a==0) return 0;
else if (a==1) return 1;
else {
return (fibonacci(a-1) + fibonacci(a-2));
}
}
ex) hanoi tower
int hanoi(int n, int on, int using, int to)
{
if (n==1){
printf("%d->%d\n\n", on, to);
}
else{
hanoi(n-1, on, to, using);
printf("%d->%d\n\n", on, to);
hanoi(n-1, using, on, to);
}
return 0;
}
using assertions
assert.h 헤더 파일에 정의된 매크로
assert(expr)
만약 expr이 true이면, 그냥 넘어가고..
expr이 false이면, 메시지를 남기면서 프로그램이 중단된다. 프로그램의 robustness에 기여함
int f(int a, int b)
{
assert(a==1||a==-1);
assert(b>=7&&b<=11);
}
output function printf()
printf()는 stdio.h 헤더 파일에 정의되어 있다.
형 지정을 잘 해주어야 한다. 이게 은근 헷갈림..
%c %d %f %s 는 기본적으로 사용하는 것
%u (unsigned decimal int) %o(unsigned octal int) %x %X (unsigned hexidecimal int)
%e %E (floating point number) 7.100e+00 st 표기법
추가적인 조건
%- : 좌측 정렬
%3 : 3칸 안에 표현한다.
%.6s : 소수점 6에서 반올림
%03 : 3칸에 표현하되, 나머지는 0으로 채움
%#x : hexadecimal에서 0x 표기법 사용함
input function scanf()
scanf("%d", &in);
%d (integer) %s (string) %f (float) %lf (double) %d (decimal) %ld (long decimal) %c (character)
ex) root of a function
#include <stdio.h>
#include <assert.h>
#include <math.h>
int cnt = 0;
const double eps = 1e-13;
double f(double x){
return(pow(x, 3)-7.0*x-3.0);
}
double bisection(double a, double b){
double m = (a+b)/2.0;
++cnt;
if (f(m)==0.0||b-a<eps) return m;
else if (f(a)*f(m)<0.0) return bisection(a,m);
else return bisection(m,b);
}
int main(void){
double a = -10.0, b=10.0;
double root;
assert(f(a)*f(b)<=0.0);
root = bisection(a, b);
printf("%s%d\n%s%.3f\n%s%e\n", "no. of fct calls: ", cnt, "root:", root, "function value:", f(root));
return 0;
}
mathematical functions
매우 다양함
#include <math.h> 헤더 파일에 포함된 함수들