Scilab함수는 다음과 같이 세 가지 상태가 있다.


➊ 컴파일이 안 된 상태

➋ 컴파일이 된 상태

➌ 프로파일링을 위한 구문이 들어간 상태로 컴파일 된 상태


만약 콘솔에서 함수를 정의한다면 endfunction이 입력되는 순간 컴파일이 된 후 workspace에 함수가 로드된다. 따라서 그 즉시로 호출하여 사용할 수 있다. 파일로 저장된 Scilab함수는 그 자체로는  컴파일이 안된 상태이고 Scilab에서 이 함수를 사용하기 위해서는 반드시 컴파일한 후 workspace에 로드하여야 한다. 프로파일링(profiling)이란 함수를 실행하는데 각각의 줄(line)이 몇 번 실행되었는지 그리고 실행 시간이 얼마나 되는지를 분석하는 것을 말하며 이를 위해서는 추가적인 구문이 필요하다. 함수가 컴파일 된 것인지 아닌지를 확인하려면 type(functoin_name) 함수를 실행해보면 된다. 결과값이 11이면 컴파일이 안된 함수이고 13이면 컴파일된 것이다.


 Scilab에서 함수를 생성하는 방법은 콘솔창에서 직접 입력하는 방법 외에도 다음에 소개하는 deff()함수를 이용하는 방법과 파일(sci파일)에서 로드하는 방법이 이다.

인라인 함수

 함수를 생성하는 방법은 앞 장에서 설명한 바와 같이 콘솔창에서 직접 입력하는 방법 외에 deff()함수를 이용하여 인라인 함수(in-line function)을 생성하는 방법도 있다. 예를 들어서 다음과 같다.



deff() 함수의 첫 번째 인자는 함수 헤더이고 두 번째 인자는 함수의 본체인데 반드시 문자열로 입력해야 한다. 세 번째 인자는 선택 사항인데 함수를 컴파일할 것인지 (‘c’) 아닌지 (‘n’)를 지정하는 문자열이고 생략하면 ‘c’가 기본적으로 선택된다. (‘p’는 프로파일링 기능을 넣은 컴파일 옵션임) 컴파일을 하는 것이 훨씬 더 실행 효율이 높으므로 보통은 기본 옵션으로 생성하면 문제가 없을 것이다.

파일에 저장된 함수

 함수를 파일에서 정의할 수 있으며 Scilab 함수 파일의 확장자는 .sci 으로 정해져 있다.( 다른 확장자도 사용할 수는 있다.) Scilab 의 sci파일에는 여러 개의 함수가 정의될 수 있으며 파일명과 함수명은 크게 상관이 없어서 서로 달라도 된다. 그리고 외부에서 각각의 함수를 개별적으로 호출할 수 있다. (MATALB은 파일명과 첫 함수명이 같아야 하고 첫 번째 함수를 제외하고 다른 함수들은 외부에서 호출할 수는 없다.)


 파일에 저장된 함수를 사용하기 위해서 컴파일/로드 되어야 한다. 이것을 수행하는 함수는 exec()함수이며 이 함수는 스크립트파일을 실행할 때뿐만 아니라 함수를 컴파일하고 로드하는데에도 사용된다. (인라인 함수를 정의하는 deff()함수도 컴파일을 자동으로 수행한다.)


>> exec(‘filename’ [,mode])


만약 함수 파일이 현재 디렉토리에 있다면 파일명만 써도 되는데 그렇지 않다면 파일명을 포함한 전체경로를 첫 번째 인자로 써주어야 한다. 두 번째 인자는 실행모드로서 선택사항이다. 옵션으로 주는 mode값과 해당하는 동작은 다음과 같다.


[표 1] exec()함수의 mode 옵션

mode 값

동작

0

초기값. 세미콜론(;)이 붙지 않은 명령의 결과만 콘솔창에 출력.

-1

아무런 출력도 하지 않음.

1

(마치 직접 콘솔창에 입력하듯이) 한 줄씩 명령과 그 결과를 출력.

2

프롬프트(-->>) 표시 ??? (0번과 거의 유사함)

3

각 명령 줄과 프롬프트 표시. (2번과 거의 유사함)

4

???

7

한 줄씩 실행 후 멈춤. 엔터키 입력으로 실행 (데모를 보일 때 유용함)


exec()함수로 읽어들인 사용자 함수는 workspace에 컴파일되서 올라오므로 바로 사용가능하다.



Posted by 살레시오
,

 Scilab에서 함수의 정의는 다음과 같이 키워드 function 으로 시작하고 endfunction으로 끝난다.


function [y1, y2, … ] = function_name(x1, x2, …)
      …
      ...
endfunction


출력변수(들)은 대괄호 [ ] 로 묶지만 만약 출력 변수가 하나라면 대괄호는 생략이 가능하다. 입력변수는 괄호 ( )로 묶는데 만약 입력 변수가 없다면 정의에서는 괄호를 생략할 수 있다. 하지만 함수를 호출할 때는 입력 변수가 없다고 하더라도 괄호를 생략하지 못 한다. 함수의 몸체는 Scilab의 문장들(statements)로 작성된다.


 간단한 예로 입력변수를 단순하게 세 제곱하여 반환하는 함수는 다음과 같이 입력할 수 있다.


>> function y=pow3(x)
>> y=x^3
>> endfunction


이렇게 입력하면 pow3()라는 함수가 내부적으로 컴파일 된 후 작업 공간에 올라오며 이 후에 호출할 수 있다. 예를 들어서


>> a=pow(4)

 

라고 호출하면 변수 a에 64가 저장될 것이다.


 또 다른 예로서 숫자 x가 소수(prime number)이면 %t를 아니면 %f 를 반환하는 IsPrime()이라는 함수는 다음과 같다.


function y=isPrime(x)
         for n=2:(x-1)
                   if modulo(x,n)==0 then
                             y=%f
                             return
                  end
         end
         y=%t
endfunction


여기서 함수 내부의 return 명령을 만나면 그 즉시 함수의 실행이 종료되고 호출된 곳으로 되돌아가게 된다. 알고리듬은 2와 x-1 사이의 모든 수로 나누어 보고 한 번이라도 그 나머지가 0이라면 %f를 반환하는 아주 간단한 방법을 사용했다.


 Scilab의 함수는 변수처럼 취급된다. 예를 들어서 입력의 3제곱을 반환하는 다음과 같은  함수를 고려하자.


>> function y=foo(x), y=x^3, endfunction


전술한 바와 같이 이렇게 함수를 정의하면 작업 공간에 이 함수가 올라오게 된다. 그 다음 일반적인 변수에 이 함수를 대입할 수 있다.


>> foo2 = foo


이 명령을 보면 좌변의 새로운 변수에 함수명을 대입했다.  이렇게 되면 함수 본체가 복사되어 새로운 변수 foo2에 대입된다. 이 말은 이후에 원래의 함수 foo를 삭제/변형하더라도 foo2 함수에는 영향을 미치지 않는다는 말이다.


이렇게 함수를 변수처럼 취급할 수 있다는 것은 여러가지 이점이 있다. 함수 자체가 다른 함수의 입력 변수, 혹은 출력 변수가 될 수 있으며 구조체나 리스트의 필드가 될 수도 있다.


 만약 정의된 함수를 삭제하고 싶다면 변수를 삭제할 때와 같이 clear 함수를 이용하면 된다.


>> clear foo
>> clear(‘foo’)


이렇게 원래의 함수 foo()가 삭제되더라도 foo2()함수는 여전히 메모리에 남아있게 된다.




Posted by 살레시오
,

 함수에 대해서 설명한 이전 포스트에서 함수 정의부에 명시된 입력 변수의 개수보다 적은 입력변수를 함수에 넘겨주는 경우 못받은 변수는 생성이 되지 않으므로 이를 따로 처리해야 한다고 하였다. 그렇다면 함수 내부에서 입출력 변수의 개수를 어떻게 알아낼 수 있을까? 이 작업을 위해서 nargin변수와 nargout변수가 마련되어 있다. 이 변수들은 모두 정수값을 가지며, nargin변수는 호출된 함수 내부에서 그 함수로 인가된 입력 변수의 개수값을 가지고 nargout 변수는 출력 변수의 개수를 가진다. 이들 변수값을 이용하여 여러 가지 입출력 방법에 대해서 대처를 할 수 있다. 앞에서 예를 든 mimo()함수를 다음과 같이 수정해 보자.


1 : function [y1,y2]=mimo2(x1,x2,x3)
2 : % function [y1,y2]=mimo(x1,x2,x3)
3 : % y1은 입력변수들의 합
4 : % y2는 입력변수들의 곱
5 : if (nargin==1)
6 :     y1=x1;
7 :     y2=x1;
8 : elseif (nargin==2)
9 :     y1=x1+x2;
10:     y2=x1*x2;
11: elseif (nargin==3)
12:     y1=x1+x2+x3;
13:     y2=x1*x2*x3;
14: else
15:    y1 = 0;
16:    y2=0;
17: end


이 수정된 함수에서 5번 줄과 8번 줄 그리고 11번 줄에서 nargin변수가 사용이 되었다. nargin==1이 참이라면, 즉 입력변수가 하나라면 6번 줄과 7번 줄을 수행시킨다. nargin==2이 참이라면, 즉 입력변수가 두개라면 9번 줄과 10번 줄을 수행시킨다. nargin==3이 참이라면, 즉 입력변수가 세 개라면 12번 줄과 13번 줄을 수행시킨다. 마지막으로 모든 경우가 거짓이라면, 즉 입력 변수가 없다면 15, 16번 줄을 수행시킬 것이다. 입력변수가 4개 이상이라도 else 문에 걸려서 15,16번 줄이 수행된다.


>> [x,y]=mimo2()
x = 0
y = 0
>> [x,y]=mimo2(11)
x =  11
y =  11
>> [x,y]=mimo2(11,22)
x =  33
y =  242
>> [x,y]=mimo2(11,22,33)
x =  66
y =  7986
>> [x,y]=mimo2(11,22,33,44)
x = 0
y = 0


연습삼아서 이 mimo2()함수를 switch-case문을 이용하여 수정해 보기 바란다.


'프로그래밍언어.Lib > MATLAB' 카테고리의 다른 글

MATLAB의 함수 m파일  (0) 2015.07.16
MATLAB의 break, continue 명령  (0) 2015.07.16
MATLAB의 반복문 while ~ end  (0) 2015.07.14
MATLAB의 반복문 for ~ end  (0) 2015.07.14
MATLAB의 조건문 switch ~ case ~ end  (0) 2015.07.13
Posted by 살레시오
,

 스크립트 m파일과 구별되는 다른 형태의 파일로서 함수(function) m파일이 있다. 지금까지 자주 사용해왔던 sin(), cos(), exp()같은 함수를 생각해 보면 사용자는 입력값을 이들 함수에 넘겨주고, 예를 들어 sin(pi)명령은 pi라는 값을 sin()함수에 넘겨주고 그 결과값 0을 얻게 된다. 내부적으로 어떠한 계산 과정이 있는 지는 일반 사용자는 알 필요가 없고 단지 입력에 대한 결과값을 얻을 뿐이다. 이와 같이 미리 정의된 함수 외에 사용자만의 함수를 작성할 수도 있다.


 함수 m파일은 입력 값과 출력 값이 존재하며 입력 변수를 받아서 특정한 기능이나 계산 등을 수행한 다음 그 결과 값을 반환하는 기능을 한다. 스크립트 m파일의 경우 생성된 변수들이 작업 공간에 위치하는 것과는 대조적으로 함수 m파일은 함수 내에서 사용된 변수들이 작업 공간과는 별도의 메모리 공간을 사용하며 함수의 수행이 끝나면 그 메모리 공간도 사라진다. 단지 출력 값만을 그 함수가 호출된 곳으로 반환시켜줄 뿐이다.

다음의 예제를 입력하여 보자.


function Y = flipud(X)
   [m,n] = size(X);
   Y = X(m:-1:1,:);


그리고 이 파일을 ‘flipud.m'으로 저장하자. 이 함수는 행렬 x를 받아서 행들의 순서를 역순으로 바꾼 후 출력하는 기능을 하는 함수이다. 이제 명령창에서 다음과 같이 명령을 내려보자.


>>A=rand(3,2) 󰎠
A =
0.0187 0.9737
0.3107 0.5865
0.7713 0.6441

>>B=flipud(A) 󰎠
0.7713 0.6441
0.3107 0.5865
0.0187 0.9737


위에서 입력 행렬 A의 행의 순서가 바뀌어서 반환된 것이 B에 저장됨을 알 수 있다. 또한 함수 내부에서 사용된 변수 m,n은 작업 공간에 나타나지 않음도 변수창에서 확인할 수 있다. 작업 공간에는 출력변수 B만이 생성되는 것이다.


 함수 m파일은 첫 번째 줄은 이 M파일이 함수라는 것을 나타내는 키워드 'function' 과 출력 변수, 함수 이름, 입력 변수 등으로 구성되며 문법은 다음과 같다.


function [y1, y2, …] = fname(x1, x2, …)


함수의 이름 fname은 m파일의 이름과 되도록이면 같도록 해야 한다. 만약 다르면 m파일의 이름이 우선하게 된다. 함수의 입출력 변수는 여러 개일 수도 있고 하나도 없을 수도 있다. 또한 함수의 정의부에 선언된 입출력 변수보다 적은 수의 변수로 함수를 호출할 수 있지만 더 많은 수의 입출력 변수를 지정하면 에러가 발생하게 된다. 다음의 예를 보자.


function [y1,y2]=mimo(x1,x2,x3)
% function [y1,y2]=mimo(x1,x2,x3)
% y1은 입력변수들의 합
% y2는 입력변수들의 곱
y1=x1+x2+x3;
y2=x1*x2*x3;


이 함수는 입력이 3개이고 출력이 2개인 함수이며 출력 y1은 입력들의 함을, y2는 입력들의 곱을 계산한다. 함수 정의부 밑에 ‘%’로 시작하는 문장들은 주석문으로서 M파일에서 '%'뒤에 오는 것들은 무시하며 실행하지 않으므로 이 기호 뒤에 설명문을 위치시키면 된다. 함수의 선언문과 첫 번째 실행문 사이의 주석문은 단순한 주석문이 아니라 명령창에서 help명령을 수행시켰을 때 보여주는 문장들이다. 명령창에서 다음을 수행해 보자.


>>help mimo 󰎠
function [y1,y2]=mimo(x1,x2,x3)
y1은 입력변수들의 합
y2는 입력변수들의 곱


이제 이 함수를 실행시켜 보자. 함수 정의부에서 출력 변수는 두 개로 지정이 되었지만 함수를 호출할 때는 출력변수를 0개, 1개, 2개 모두 지정할 수 있으며 3개 이상을 지정하면 에러가 발생한다.


>>mimo(3,4,5)
y1 =
12

>>y1=mimo(3,4,5)
y1 =
12

>>[y1,y2]=mimo(3,4,5)
y1 =
12
y2 =
60

>>[y1,y2,y3]=mimo(3,4,5)
-----------------------------------
* MATLAB 디버그 정보 (오류 발생) *
-----------------------------------
파일 이름 : C:\MATLAB_MFILES\mimo.m
라인 번호 : 1 --> function [y1,y2]=mimo(x1,x2,x3)
오류 내용 : 함수의 입출력 갯수가 올바르지 않습니다.


위에서 알 수 있듯이 출력 변수를 지정하지 않으면 첫 번째 출력 변수만을 화면에 보여준다. 그리고 출력 변수를 하나만 지정하면 두 번째 출력변수는 반환되지 않게 된다.

입력 변수도 아예 지정하지 않거나 한 개나 두 개만 입력할 수 있지만 함수 내에서 넘겨받지 않은 변수는 생성되지 않게 되므로 함수 실행 시 에러를 발생하게 된다.


>> mimo(3,4)
-----------------------------------
* MATLAB 디버그 정보 (오류 발생) *
-----------------------------------
파일 이름 : C:\MATLAB_MFILES\mimo.m
라인 번호 : 5 --> y1=x1+x2+x3; %...
오류 내용 : x3라는 변수나 함수가 없습니다. 이름이 맞는지 확인하십시요.


위의 경우는 세 번째 입력변수를 넘겨주지 않았으므로 mimo함수 내부적으로 x3라는 변수 자체가 없어서 덧셈을 수행하지 못하게 되는 것이다. 즉 적은 수의 입력 변수를 넘겨주는 것은 문법적으로 허용이 되지만 넘겨받지 못한 변수를 생성하기 위한 추가적인 실행문이 필요하게 된다. 이에 대해서는 다른 포스트에서 자세히 설명하겠다.





Posted by 살레시오
,

7장 연습문제

pb07-01 자신의 영문 이름과 나이를 출력하는 함수 showMe() 함수를 작성하라. 그리고 이 함수를 100번 연속으로 호출하는 코드를 작성하라.



pb07-02 정수를 받아서 그 정수가 짝수이면 “even number”, 홀수이면 “odd number” 라고 화면에 출력하는 함수를 작성하라. 이 함수의 선언은 다음과 같다.

void isEven(int ia);


pb07-03 구의 반지름을 입력받아서 구체의 부피를 반환하는 함수를 작성하라. 함수의 선언을 다음과 같다.(V = 4πr3/3)

double calcVolumn(double dr);


pb07-04 unsigned char형 정수를 받아서 1부터 그 수까지의 합을 반환하는 함수를 작성하라. 함수의 선언은 다음과 같다.

long sumup(unsigned char uc);


pb07-05 세 개의 int형 정수를 받아서 그중 가장 큰 수를 반환하는 함수를 작성하라. 함수의 선언은 다음과 같다.

int getMax(int ia, int ib, int ic);


pb07-06 (a) char형 문자를 하나 받아서 그 문자가 소문자이면 1, 그 외의 문자이면 0을 반환하는 함수를 작성하라. 함수의 선언은 다음과 같다.

int isLower(char ca);


(b) 작성된 함수를 이용하여 주어진 문자열이 모두 소문자일 경우 “bingo” 라고 화면에 표시하는 프로그램을 작성하라.


pb07-07 (a) unsigned long형 인자를 두 개 받아서 그 두 수의 최대 공약수를 반환하는 함수를 작성하라. 반환값은 long형이다. 함수의 선언부는 다음과 같다.


long getGCD(unsigned long la, unsigned long lb);

(b) 최소 공배수를 구하는 함수 getLCM() 함수를 작성하라.


Posted by 살레시오
,

 파이썬 함수의 기본값 인자(default parameter)란 함수를 호출할 때 인자의 값을 설정하지 않아도 기본값이 할당되도록 하는 기능이다. 기본값은 함수를 정의할 때 지정해준다. 예를 들어 보자.


def funcA(a=10):
   print('a='+str(a))


이 함수는 다음과 같이 두 가지 방법으로 호출할 수 있다.


>>> funcA() # a에 기본값인 10이 자동으로 저장된다.
a=10
>>> funcA(20) #a에 20이 전달된다.
a=20


이 예에서 인자 a는 기본값 인자이고 호출하는 쪽에서 값을 주지 않으면 기본적으로 10 값을 갖게 된다. 그래서 funcA()와 같이 값을 주지 않으면 10이 출력되고 funcA(20)과 같이 값을 주면 그 값이 인자 a 로 전달되는 것이다.


 다른 예를 들어 보자.


def printName(firstName, secondName='Kim'):
   print('My name is '+ firstName +' ' + secondName +'.')


이 함수도 다음과 같이 두 가지 방법으로 호출 가능하다.


>>> printName('Jang-Hyun')
My name is Jang-Hyun Kim.
>>> printName('Jang-Hyun', 'Park')
My name is Jang-Hyun Park.


기본값 인자는 값을 생략해서 호출할 수 있지만 일반 인자는 반드시 값을 지정해 주어야 한다. 따라서 printName()함수를 호출할 때 첫 문자열은 반드시 정해서 넘겨주어야 한다. 여기에서 printName()함수의 두 번째 인자를 입력하지 않으면 기본적으로 ‘Kim’으로 지정된다. 두 번째 인자를 명시적으로 지정하면 그것이 secondName 으로 지정된다.


 한 가지 주의할 점은 일반 인자와 기본값 인자가 같이 올 때에는 반드시 기본값 인자는 뒤에 와야 한다는 점이다. 즉, 아래와 같이 정의하면 오류가 발생한다.


>>> def printName(firstName='Kim', secondName):


기본값 인자가 두 개 이상일 때에서도 항상 일반 인자 뒤에 와야 한다.


>>> def add(a, b=0, c=0):
...     return a+b+c
...
>>> add(1)
1
>>> add(1,2) # b에 2가 들어간다.
3
>>> add(1,2,3) # b에 2, c에 3이 들어간다.)
6


이 예에서 보듯이 함수를 호출할 때 주는 순서 대로 기본값 인자에 값이 할당 됨을 알 수 있다.


 또 한 가지 주의할 점은 기본 인자는 최초의 호출 시에만 지정된 값으로 초기화 되고 이후의 호출에서는 그렇지 않다는 점이다. 따라서 리스트나 딕셔너리와 같은 가변(muatble) 객체를 기본 인자로 사용할 때 문제가 된다.


>>> def f(a, L=[]):
...     L.append(a)
...     return L
...
>>> f(1)
[1]
>>> f(2)
[1, 2]
>>> f(3)
[1, 2, 3]


이 예제를 보면 기본 인자 L은 최초의 호출에서만 빈 리스트로 초기화 되고 그 이후의 호출에서는 그 내용물은 유지된다. 따라서 리스트의 요소가 축적되는 것이다. (마치 C/C++에서의 static 변수와 비슷한 동작을 수행한다.)


 후속 호출에도 mutalbe 객체를 초기화하려면 다음과 같은 방법으로 코딩하면 된다.


def f(a, L=None):
   if L is None:
       L = []
   L.append(a)
   return L


이 경우 실행 결과는 다음과 같다.


>>> f(1)
[1]
>>> f(2)
[2]
>>> f(3)
[3]




Posted by 살레시오
,

 어떤 함수는 호출하는 쪽에선 몇 개의 인수를 넘겨줄지 모르는 경우가 있다. 이럴 경우에 사용되는 것이 가변 개수 인자 기능으로써 함수는 넘어온 인자들을 묶어서 단일 튜플로 받는다.


 예를 들어 입력 인자들 중 짝수의 개수를 구하는 함수를 작성해야 하는데 몇 개의 입력이 들어올 지는 모른다고 가정하자. 인자들을 묶어서 한 개의 리스트를 받는 방식을 먼저 생각해 볼 수 있겠다.


def count_even(lst):
   cnt = 0
   for v in lst:
       if v%2==0:
           cnt +=1
   return cnt

>>> count_even([1,2,3,4,5,6,7])
3
>>> count_even([11,22,33])
1


이런 식으로 하나의 입력 인수를 받되 리스트 요소의 개수는 그때 그때 변할 수 있겠다.


 하지만 이런 경우에 있어서 좀 더 일반적인 해법은 가변 개수 인수를 받는 것이다. 가변 개수 인자를 지정할 때 함수의 정의부에서 변수 앞에 별표(*)를 붙인다.


>>> def count_even(*n):
   cnt = 0
   for v in n:
       if v%2==0:
           cnt +=1
   return cnt

>>> count_even(11,22,33)
1
>>> count_even(1,2,3,4,5,6,7)
3


앞의 경우와 다르게 함수를 호출할 때 콤마로 구분된 입력 인자를 몇 개라도 입력할 수 있다는 것이다. 함수 내부에서는 이들 인자들을 요소로 갖는 튜플이 변수 n에 넘어오게 된다. 즉 type(n)은 tuple 이다.


 한 가지 주의할 점은 일반 인자와 가변 인자가 동시에 오는 경우 반드시 가변 인자는 일반 인자 뒤에 와야 한다는 점이다. 또한 가변 인자는 단 하나만 사용할 수 있다는 것도 유의해야 한다.


>>> def  f1(a, *b): # 정상
>>> def  f2(a, *b, c): # 오류 - 가변 인자 뒤에 일반 인자가 올 수 없다.
>>> def  f3(*a, *b): #오류 - 가변 인자는 하나만 사용 가능
>>> def  f4(a, b, *c) # 정상


이러한 사항에 주의해서 함수를 작성해야 한다.




Posted by 살레시오
,

 함수(function)란 실행문들을 묶어서 하나의 블럭으로 만든 후 이름을 붙인 것을 말한다. 이렇게 수행문들의 집합을 함수로 정의하면 그 수행문들을 동작시킬 때 함수 이름을 이용한 간단한 호출(call)로 반복해서 실행시킬 수 있다.


 파이썬 함수는 다음과 같이 정의된다.


def 함수명(인자1, 인자2, …):
함수 본체


함수의 정의는 항상 def로 시작한다. 함수명은 일반적인 식별자를 사용하며 관례적으로 (변수명과 마찬가지로) 소문자로 시작한다. 그다음에 호출하는 쪽에서 넘겨 받을 인자들의 리스트를 괄호(...)안에 콤마로 구별하여 지정해 주고 콜론(:) 뒤에 함수의 본체를 작성해 주면 된다. 함수의 본체는 반드시 def 의 첫 글자 시작 위치보다 들여 써야 한다.


 간단한 예를 들어보자


>>> def sayHi():
print(‘hi’)


이 함수는 ‘hi’라는 문자열을 출력하는 함수이며 함수의 이름은 sayHi()이다. 입력 인자는 없으며 반환값도 없다. 이 함수를 호출하려면 다음과 같이 하면 된다.


>>> sayHi()
Hi


구구단을 출력하는 함수를 예로 들어보자.


>>> def gugu(n):
...     for x in range(2,10):
...         print('%d x %d = %d'%(n,x,n*x))


이 함수는 하나의 입력 인자를 받도록 되어 있다. 다음과 같이 호출한다.


>>> gugu(4)
4 x 2 = 8
4 x 3 = 12
4 x 4 = 16
4 x 5 = 20
4 x 6 = 24
4 x 7 = 28
4 x 8 = 32
4 x 9 = 36

>>> gugu(8)
8 x 2 = 16
8 x 3 = 24
8 x 4 = 32
8 x 5 = 40
8 x 6 = 48
8 x 7 = 56
8 x 8 = 64
8 x 9 = 72


함수명은 함수객체이며 다른 객체와 유사하게 대입이 가능하다. 예를 들어 앞에서 정의한 함수 sayHi()와 gugu()를 하나의 리스트로 묶을 수 있다.


>>> fl = [sayHi, gugu]


여기서 fl 리스트의 첫 번째 요소는 함수 sayHi 이고 두 번째 요소는 gugu 이다. 따라서 다음과 같은 함수 호출이 가능하다.


>>> fl[0]()
Hi.
>>> fl[1](9)
9 x 2 = 18
9 x 3 = 27
9 x 4 = 36
9 x 5 = 45
9 x 6 = 54
9 x 7 = 63
9 x 8 = 72
9 x 9 = 81



또는 함수를 다른 변수에 대입할 수도 있다.


>>> kuku = gugu


이제 kuku 는 함수이며 gugu()함수와 같은 함수이다. 따라서 다음과 같이 동일하게 호출할 수도 있다.


>>> kuku(7)
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63


 가끔 함수의 본체를 구현하지 않고 껍데기만 작성해야 될 경우도 있다. 이럴 경우 다음과 같이 하면 된다.


>>> def nop(): pass


이 함수는 호출은 할 수 있으나 아무런 일도 수행하지 않는다.



Posted by 살레시오
,

 C++에서 (C언어에서는 지원되지 않음) 함수가 호출될 때 입력 인자에 값이 넘어오지 않는다면 미리 정해진 값을 함수 내부에서 가지도록 할 수 있다. 이렇게 기본값을 가지는 함수의 인자를 기본값 인자(default parameter)라고 하며 함수의 선언부에서 예를 들면 다음과 같이 명시해 주어야 한다.


void func(int ia=0); // 함수의 선언에 ia의 기본값을 10으로 지정
….
int func(int ia) { //함수 정의. ia는 기본값 10을 가진다.
   return ia+10;
}


변수 ia는 호출될 때 값이 넘어오지 않으면 자동으로 0값을 가지도록 선언되었다. 즉, 이 함수를 호출할 때 입력인수를 주어도 되고 안 해도 된다.

func(); // 변수 ia는 0값을 자동으로 갖는다.
func(10); // 변수 ia에 10값을 넘겨준다.

 만약 디폴트 입력 인수기능이 없이 함수 중복으로만 이를 구현한다면 다음 그림의 좌측과 같이 두 개의 함수를 별도로 작성해야 할 것이다.


void func() {

   int ia = 0;

   // 함수 본체

   ....

}

void func(int ia) {

   // 함수 본체

   ....

}

void func(int ia = 0);

함수 중복으로 구현한 경우

디폴트 입력 인수 함수로 간략화


이것을 살펴보면 기본 인자 기능이 프로그램을 상당히 간결히 해주는 유용한 기능임을 알 수 있다.


#include "stdio.h"

void print(char *name = "John");// 기본값을 지정

int main(void)
{
print();
print("Jang-Hyun Park");
}

void print(char *name)
{
printf("Hi. My name is %s\n", name);
}


Hi. My name is John
Hi. My name is Jang-Hyun Park

 다른 예를 들어보면 다음과 같다.

void send(int ia, string str=“Hello”);

이 함수는 다음과 같이 두 가지로 호출이 가능하다.


send(10);
send(10, “Hi”);

 

기본값 인자가 설정된 변수만 생략 가능하다는 점에 유의해야 한다. 따라서 다음과 같은 호출은 오류를 발생시킬 것이다.

send(); //오류 발생
send(“Hi”); //오류 발생

 만약 다음과 같이 디폴트 입력 인수를 두 개 가진 함수라면

void sum(double da, double db=10.0, double dc=20,0);

다음과 같이 세 가지 방법으로 호출할 수 있다.

sum(1.0); // da는 1.0, db는 10.0, dc는 20.0 값을 갖는다.
sum(1.0, 2.0); // da는 1.0, db는 2.0, dc는 20.0 값을 갖는다.
sum(1.0, 2.0, 3.0); // da는 1.0, db는 2.0, dc는 3.0 값을 갖는다.

 디폴트 입력 인수를 가진 함수를 선언할 때 주의할 점은 이것들이 모두 끝 쪽에 몰려있어야 하며 디폴트 입력 인수를 가지는 변수 다음에 일반 변수는 못 온다는 것이다. 다음 예는 모두 잘못된 것이다.

 void sum(int ia, int ib=5, int ic, int id=10);// 에러 발생
 void sum(int ia=10, int ib, int ic);// 에러 발생

그리고 다음과 같은 함수 중복도 오류를 발생한다.


void print(string stra);
void print(string stra = “Hello”); // 허용되지 않는 함수 중복

 

그 이유는 두 함수가 입력 인수의 개수와 형이 같기 때문이다. 그리고 다음과 같은 함수 중복도 오류를 발생한다.

void func(int ia, string strA=“Hi”);
void func(int ia); // 허용되지 않는 함수 중복

두 함수는 분명히 입력 인수의 개수가 다르지만 만약 func(10) 이라고 호출했을 때 두 개 중 어느 것을 호출해도 문제가 없기 때문에 컴파일러는 오류를 발생시킨다.



Posted by 살레시오
,

 C 언어 프로그램은 같은 이름을 갖는 함수를 정의할 수 없으나 C++에서는 가능하다. 이렇게 같은 이름을 갖는 함수들을 작성하는 것을 함수 중복(overloading)이라고 하며 전역 함수와 클래스의  멤버 함수 모두에 가능하다.


 예를 들면 다음과 같다.

void print();
void print(int ia);
void print(char *str);
void print(int ia, bool bNewLine);

이 예제들의 세 개의 print()함수는 모두 같은 이름을 갖지만 입력 인자가 서로 다르므로 모두 다른 함수들이다. 이와 같이 함수의 중복이 가능하려면 각각을 구별해야 하므로 다음의 조건들을 만족해야 한다.

       ❶ 중복되는 함수들의 입력 인자의 개수가 다르거나 타입이 달라야 한다.

       ❷ 반환형만 다르고 입력 인자가 같은 중복은 허용되지 않는다.

따라서 다음의 두 함수는 함수 중복의 요건이 안 되기 때문에 오류를 발생한다.

void print(string stra);
int print(string stra);

 함수 중복을 이용하면 같은 종류의 일을 하는 서로 다른 입력 인자를 갖는 함수들을 같은 이름으로 일관성 있게 관리할 수 있으므로 무척 효율적이다. 또한 컴파일러는 함수가 호출될 때 대응되는 함수를 프로그램이 실행될 때가 아니라 컴파일할 때 결정하므로 함수 중복으로 인해서 실행 시간이 지연되는 않는다.


 다음 예를 실행해 보자.


#include "stdio.h"

void print();
void print(char *);

int main(void)
{
print(); //❶을 호출
print("Jang-Hyun Park");//❷를 호출
}

void print() //
{
printf("Hello.\n");
}

void print(char *name) //
{
print(); //❶ 을 호출
printf("My name is %s.\n", name);
}


Hello.
Hello.
My name is Jang-Hyun Park.


함수 ❷ 내부에서도 함수 ❶을 호출할 수 있음을 유의해서 보자. 사실 두 함수는 이름만 같을 뿐 내부적으로는 완전히 다른 함수로 취급되므로 이러한 상호 호출이 가능하다.



Posted by 살레시오
,