함수란?

함수는 프로그램을 구성하는 단위로서 프로그램의 부품 역할을 한다. 프로그램과 함수의 관계는 컴퓨터와 그 부속품의 관계와 유사하다. 여러 부품의 동작들로 컴퓨터라는 작동이 완성되는 것처럼 프로그램이 해야할 각 일들을 각 부품들 (함수)이 나누어 맡으며 그 중에서도 가장 핵심이 되는 함수(main)의 통제 아래 모든 함수들이 체계적으로 실행되어 전체적으로 프로그램이라는 하나의 완성을 이루는 것이다.

함수는 함수의 일므 , 인수목록 , 반환 값 , 본체 로 이루어진다.

int max( int a , int b)

{

}

 

 

(이름 뒤의 괄호가 없으면 함수의 시작 번지를 나타내는 포인터 상수이다.)

함수 별로 특정 기능을 담당하도록 기능을 분할해 놓으면 코드의 구조를 만들 수 있다. 비슷한 작업을 같은 함수를 호출하면 되므로 코드의 중복을 방지 할 수 있다. 이 때문에 함수를 프로그램의 부품이라고 하는 것이다.

인수 (parameter)

인수는 호출원에서 함수에게 넘겨주는 작업 대상이라고 할 수 있다. 두 함수 사이의 정보 교환에 사용되므로 매개변수(Arguments) 라고도 한다.

인수는 형식인수 와 실인수로 구분되는데, 함수의 인수 목록에 나타나는 인수를 형식인수라 하며.. 함수 호출부에서 함수에게 전달되는 인수를 실인수라고 한다.

 

return

인수가 호출원으로 부터 전달되는 작업 대상이라면, 리턴 값은 함수가 호출원으로 돌려주는 작업 결과이다. 앞에어 이미 보았지만 함수가 결과를 리턴할 때는 return문을 사용한다.

void 함수는 리턴이 끝으로 인식될 뿐 아무것도 반환하지 않는다.

c 함수의 특징.

1. 함수끼리는 서로 평등한 관계에 있으며 상호 수평적. 즉, 함수 끼리는 언제나 호출이 가능하다.

2. 함수중 가장 기본이 되는 것이 main함수이며 시작점이 된다.

3. 리턴 값은 존재할 수도, 존재하지 않을 수도 있다.

4. 항상 단독으로 문장을 구성할 수 있다. 리턴 값이 있는 함수라도 반드시 리턴 값을 받거나 써야하는 것이 아니라 버리는 것이 가능하다.

5. 값에 의한 호출 방식을 사용한다.

 

 

함수의 원형

프로그래밍 언어는 해석 방식에 따라 인터 프리터 방식과 컴파일 방식으로 나누어지는데, 컴파일 방식이 성능이 더 좋기 때문에 대부분의 언어가 컴파일 방식을 사용한다. 컴파일 방식은 소스를 읽어 기계어로 한꺼번에 번역하는 방식인데, 번역을 몇번에 나누어 하느냐에 따라 1패스 2패스 등으로 구분된다. (패스 수가 적을 수록 빠르다)

C 컴파일러의 경우 1패스 방식이다. (그래서 빠르다.) (최근의 경우 1패스가 아닌 경우도 있다)

초기의 컴파일러들이 1 패스 방식에 맞추어 설계 되었기 때문에, main 함수보다 아래 있는 함수를 읽어들일 장치를 마련할 필요가 있었는데, 이것이 원형(Prototype)이다.

원형은 함수의 선언부분에 ;를 붙이는 것으로 선언하는데, 이 선언을 통해서 비로소 컴파일러가 해당 함수를 만나지 않아도 어떤 함수인지 파악할 수 있는 것이다.

 

헤더 파일

함수는 사용되기 전에 반드시 그 원형을 선언해야한다. printf나 scanf 등의 함수는 아무런 선언이 안 되어있는데, #include <stdio.h>가 바로 그 원형이 포함된 헤더이다. 표준 함수들의 원형을 미리 작성해 놓은 것을 헤더 파일이라고 하며, stdio.h가 대표적 헤더 파일이다.

 

헤더 파일에는 표준 함수의 원형 뿐만 아니라 아래와 같은 유용한 것들이 등록되어 있으므로, 헤더만 인클루도 해도 쓸 수 있는 것들이 많다.

1. 제일 중요한 정보는 표준 함수의 원형이다. 이 원형이 헤더에 선언되어 있기 때문에, #include문으로 표준함수를 사용할 수 있다.

2.각 표준 함수들이 사용하는 매크로 상수들을 정의한다.

3.각 표준 함수들이 사용하는 열거형 타입을 정의한다.

4.자료의 가공을 간편하게 해 주는 매크로 함수들을 정의한다.

5.구조체, 공용체 등 표준 함수가 요구하는 사용자 정의 타입을 정의한다.

 

모듈.

함수를 선언하기 전에 원형만 선언한다면, 함수의 본체는 어디에 있건 상관없다.  비주얼 c++ 프로젝트는 하나의 실행파일을 만들기 위한 모듈의 집합이며, 한 프로젝트 안에 여러개의 모듈(cpp파일)을 둘 수 있다.

 

모듈 분할 컴파일 방식의 이점 :

1. 컴파일 속도가 빠르다. 여러개에 분산되어 있으므로, 한 함수를 수정한 후 컴파일할 때.. 해당 함수가 속한 모듈만 컴파일하면 된다.

2. 분담작업이 가능하다. 자기가 잘하는 부분만 신경쓰면 된다. 하나의 소스를 두 사람이 작성하는 것보다 안전하기도 하다.

3. 프로젝트의 관리가 쉽다. 모듈별로 모아두었기 때문에, 문제가 생기면 찾아내기도 쉽다.

4. 모듈을 재 사용할 수 있다. 기능적으로 독립적이기 때문에, 쉽게 재사용할 수 있다.

 

함수 호출 방식.

값 호출. 인수란 호출원에서 함수에게 일을 시키기 위한 정보인데, 인수를 어떻게 전달하느냐에 따라서 값 호출 (call by value)과 참조 호출(call by reference)로 나뉜다. 인수를 넘기는 방식에 따라 실 인수의 값이 변경되는가 아닌가의 차이점이 있다.

값 호출 방식의 경우 실 인수의 값이 형식인수로 전달되는 방식이다.  값에 의한 호출은 값을 복사하여 함수에게 넘겨주는 방식이다. 넘겨준 실인수와, 넘겨받은 형식인수는 아예 데이터가 저장되고 있는 공간 자체가 다르다. 따라서.. 실인수에게 결과값을 넘겨주지 않으면, 형식인수가 어떻게 변화했건 아무런 영향을 미치지 못한다.

반면 참조 호출 방식의 경우.. 특정한 값 a가 있을 때, a의 공간에 들어 있는 값을 바꾸는 것이므로 실제로 값이 바뀐다. 참조 호출이라는 말은 번지값을 전달받아 실인수를 직접 참조(reference)할 수 있기 때문에 참조호출이다.

 

사실 c에서 지원하는 참조호출은 가짜인데.. 포인터를 사용하여 참조호출을 흉내내는 것일 뿐.. 진정한 의미의 참조호출이 아니다. 이때도 실제로는 '값을 복사'하여 전달해주고 있으며.. 그 값이 '주소 값'이기 때문에 해당 주소값 (혹은 번지값)을 받아서 그걸 포인터로서 다루는 것이다.

 

출력용 인수.

scanf를 사용할 때,

scanf("%s",&i); 와 같이 사용한다.

이유는 값 호출은 실인수의 값을 바꿀 수 없기 때문이다. 단 문자열을 입력받거나 할 때는 붙이지 않는데, 배열은 그 자체가 포인터(주소값) 이기 때문이다.

&연산자를 붙이면 해당 값이 아닌, 해당 값이 있는 곳의 주소를 전달하게 된다.

 

//

c++은 포인터를 사용하는 것 이외에 레퍼런스로 참조할 수 있다.

void plusref(int &a);

void main()

{

 int i = 5;

plusref(i);

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

}

plusref(int &a)

{

a+=1;

}

 

i에게 값을 리턴해준 적도, 포인터로 받지도 않았지만 값은 올라간다. 이것이 레퍼런스다.

 

#define 문은 전처리문이지 코드를 생성하는 명령이 아니므로, 끝에 세미콜론은 붙이지 않음. 

2. 매크로의 이름도 일종의 명칭이기 때문에 규칙에 맞게 작성해야한다. (관습적으로 대문자 사용)

3.이름에 공백이 들어갈 수 없지만, 실제 값은 공백을 가질 수 있다.

4.문자열 상수 내에 있는 매크로나 다른 명칭의 일부로 포함된 경우는 치환되지 않는다.

5. 매크로는 중첩가능하다. 매크로 상수가 매크로 상수를 참조하는 일이 가능하다.

6. 값을 가지지 않는 빈 매크로도 얼마든지 정의할 수 있다. ( 이 경우 그 매크로가 존재하는 가 아닌 가 만이 의미를 가진다.)

 

매크로 함수

#define 전처리기를 이용하여 함수 흉내를 내는 것이다.

#define doubles(i) i+i;

 이렇게 쓰면 i+i 의 상황으로 치환된다.

 

매크로 사용의 주의점.

1. 매크로 함수의 전체 식을 괄호로 싸야한다. 위의 매크로를 -doubles(i)라고 쓴다면. -2i가 아닌 0이되어버린다. (-i+i 가 되어버리기 때문) 때문에 모든 매크로 함수는 괄호로 묶어주어야한다.

2. 인수도 괄호로 싸준다. 인수 자체가 수치가 아닌 수식일 수도 있기 때문이다. 제곱을 해주는 매크로함수 multiples(i) (i*i)가 있을 때 multiples(3+1)의 결과는 4^2가 아니라. (3+1*3+1)이 된다. 따라서 수식 자체도 묶어주어야한다. 괄호에 따라 결과가 전혀 달라질 수 있기 때문에.. 괄호를 우습게 보지 말고 잘 기억해두어야한다.

3. 매크로 함수는 인수의 타입 따위는 점검하지 않는다. 매크로 함수는 무조건 치환만 하기 때문에.. 유연하게 작동하는 장점이 될 수도 있다.

4.매크로 함수에 여러개의 명령을 동시에 포함시킬 수 있다.  \를(역슬래시) 붙이면 다음 줄까지도 매크로 함수의 범위로 인식하므로.. 여러 구문을 함께 작동 시킬 수 있다.

5.매크로 함수 호출문에서 ++이나 -- 등의 증감연산자나.. += 같은 복합 대입 연산자는 쓰지 않는 것이 좋다. 문법적으로는 상관없지만, 치환 결과를 예측하기 어려우며 부작용이 발생할 소지가 많기 때문이다. 

6. 기존에 있는 함수를 편의를 위해서 매크로로 간략화하거나 변경하는 것은 별로 권장할만하지 못하다. 협업이 필요한 팀 프로젝트에서는 가독성을 떨어트릴 뿐더러 , 불편을 유발할 수 있기 때문이다.

매크로 함수는 잘 사용하면 속도도 빠르고 소스도 간략해진다. 실행시 인수를 전달하는 게 아니라 컴파일시 치환되기 때문에 함수 호출에 대한 부하도 없지만, 같은 매크로 함수를 여러번 쓸 경우.. 동일한 코드가 반복되기 때문에 실행파일의 크기는 커진다. 크기가 크다면 일반 함수가 유리하다. 즉 매크로 함수는 속도에는 유리하고 크기에는 불리한 방법이다.

#define abs(a) (((a) > 0) ? (a) : (-a))

와 같은 매크로 함수는 적절하다고 할 수 있다.

 

 

 

'프로그래밍 > 프로그래밍 공부' 카테고리의 다른 글

8장 표준함수  (0) 2015.02.28
7장 기억 부류  (0) 2015.02.27
6장 함수  (0) 2015.02.27
5장 연산자  (0) 2015.02.27
4장 제어문  (0) 2015.02.27
3장 변수  (0) 2015.02.27
Posted by GENESIS8

댓글을 달아 주세요

기능별 종류

연산자

산술 연산자

+ - * / %

부호 연산자

+ -

대입 연산자

= 복합 대입 연산자

관계 연산자

== != <= < >= >

증감 연산자

++ --

포인터 연산자

* & []

구조체 연산자

. ->

논리 연산자

|| && !

비트 연산자

| & ~ >> <<

삼항 조건 연산자

? :

쉼표 연산자

,

sizeof 연산자

sizeof

캐스트 연산자

(type) type()

괄호 연산자

()

C++ 연산자

new delete :: .* ->*

 

좌변 값이란?

대입 연산자의 우변 -> 에는 상수 , 변수와 연산자들로 구성된 계산할 수 있는 표현 식이오지만.. 좌변에는 좌변 값(l-value : left value)만이 올 수 있다. 좌변 값이란 대입 연산자의 왼쪽에 올 수 있는 값으로.. 실제적인 메모리를 점유하고 있고 그 값을 바꿀 수 있는 대상이다.

연산자의 리턴 값

1 + 2 의 결과가 3이 되는 것은 사실 +가 연산의 결과를 리턴해주기 때문이다. 1과 2를 더한 값을 리턴해주기 때문에 값을 전달받을 수 있는 것이다.

복합 대입 연산자.

a = a+3;을

a += 3으로 줄여 쓸 수 있다. +나 - 연산자 외에도 * , / , ^ 연산자등 모두에 사용하는 것이 가능하다.

증감 연산자

++ , -- . 어셈블리 레벨의 조작을 하므로 빠르다. +=1이나 -=1은 컴파일러가 ++1과 --1로 치환하므로 별 차이는 없다.

관계 연산자

논리연산에 자주쓰인다.

논리 연산자

연산자

설명

!

논리 부정(Not)

논리식의 진위를 반대로 만든다.

&&

논리곱(And)

논리식이 모두 참이어야 참이다.

||

논리합(Or)

논리식 하나만 참이면 참이다.

 

!는 참 좋다. 어려운 내용도 !() 해서 쓰면 그만이다.

비트 연산자

연산자

설명

~

비트를 반전시킨다.

&

대응되는 비트가 모두 1 1이다.

|

대응되는 비트가 모두 0 0이다.

^

개의 비트가 달라야 1이다.

<<

지정한 수만큼 왼쪽으로 비트들을 이동시킨다.

>>

지정한 수만큼 오른쪽으로 비트들을 이동시킨다.

 

<< >> 는 쉬프트연산자라고도 부른다.

삼항 연산자

(조건식) ? 1:2  :  if문의 축소판. 조건이 맞으면 값1을, 틀리면 2를 반환한다.

쉼표 연산자

, 다. 연산자가 아닌 거 같지만 연산자다. 변수를 여러개 선언 할때 쓰인다.

sizeof 연산자.

sizeof(타입 또는 변수)

이 연산자는 피연산자로 주어진 타입 또는 변수의 크기를 계산한다. 피연산자로 int, double같은 타입을 쓸 수도 있고 변수를 쓸 수도 있으며 상수를 사용할 수도 있다. 아뭏든 괄호안에 있는 대상이 메모리를 얼마나 차지하고 있는지 계산한다.

캐스트 연산자

(int) 변수. 처럼 캐스팅한다. 타입을 바꿀 때 쓴다.

연산 우선순위

순위

연산자

결합순서

1

( ) [ ] -> .

왼쪽 우선

2

! ~ ++ -- + -(부호) *(포인터) & sizeof 캐스트

오른쪽 우선

3

*(곱셈) / %

왼쪽 우선

4

+ -(덧셈, 뺄셈)

왼쪽 우선

5

<< >>

왼쪽 우선

6

< <= > >=

왼쪽 우선

7

== !=

왼쪽 우선

8

&

왼쪽 우선

9

^

왼쪽 우선

10

|

왼쪽 우선

11

&&

왼쪽 우선

12

||

왼쪽 우선

13

? :

오른쪽 우선

14

= 복합대입

오른쪽 우선

15

,

왼쪽 우선

 

그냥 괄호 쓰는게 낫다.

결합 순서

결합 순서는 수식내에 같은 연산자가 있을 때 어디부터 우선 수행 할 것인지이다. 가령 예를 들자면

`a=b=c=3 이 대입문은 a, b, c 모두 3을 대입하는데 대입 연산자는 오른쪽 우선이다

산술변환

이항 연산시 양변의 타입이 다르면 큰 쪽으로 상승 변환된다. 그래야 가급적이면 정확한 계산을 할 수 있다.

대입 연산시 좌변의 타입을 따른다. 값을 대입받을 변수의 능력치를 초과할 수는 없기 때문에 대입되는 값이 변수보다 더 크면 잘라낸다.

함수 호출시 실인수와 형식인수의 타입이 다르면 형식인수의 타입을 따라간다. 함수 호출 과정에서의 인수 전달은 결국 대입 동작이기 때문에 2번 규칙과 같은 규칙이다.

캐스트 연산자를 사용하면 강제로 타입을 변환할 수 있다. 이 변환은 암시적인 산술 변환 규칙이 아니라 사용자가 직접 지정한 명시적 변환이다.

수식내에서 사용될 경우 char, unsigned char, enum형은 int형으로 자동 확장되며 float형은 double형으로 확장된다.

 

 

'프로그래밍 > 프로그래밍 공부' 카테고리의 다른 글

7장 기억 부류  (0) 2015.02.27
6장 함수  (0) 2015.02.27
5장 연산자  (0) 2015.02.27
4장 제어문  (0) 2015.02.27
3장 변수  (0) 2015.02.27
2장 프로그램의 구성 요소  (0) 2015.02.26
Posted by GENESIS8

댓글을 달아 주세요

프로그램을 실행할 명령들을 다룰 때 사용된다. 중요하다.


조건문

if문

주어진 조건에 따라 명령의 실행 여부를 결정하는 문장이다.


if( 조건 ) 과 같이 쓰며, 조건이 맞으면 명령을 수행한다.

비교연산자가 주로 활용된다.


{}로 블록을 활용하여 실행시킬 문장의 범위를 넓게 잡는 것도 가능하다.

if(x>3) 명령  보다는

if(x>3)

{

명령들..

명령들..

}

이 더 많은 작업을 처리할 수 있다.


else를 사용할 수 있는데, 특정 조건에 맞아야하는 if와 달리 맞지 않으면 다 성립한다.

if () { } else { } 와 같이 사용한다.


조금 더 나아가 else if가 있는데, if와 거의 같다고 보면되지만, 첫 번째 if가 거짓인 이후에야 순번이 오므로, 일단 if는 아닌데, 다른 조건을 만족하거나, 조금 덜 만족하거나.. 하는 경우 등에 쓰인다.



for문 반복문이다.

for(int i = 0; i < 10 ; i++)

{

}

로 굉장히 유명한 for문은 특정 조건이 성립하는 동안 반복시키기보다는 특정 횟수를 반복시키게 하고 싶은 경우에 주로 쓴다.

기본적으로는 i < 10 부분이 조건식이 되어 '조건식이 참인 동안 계속 실행하는 것이다.

역시 { } 부분에는 실행할 명령이 들어간다.

i++ 부분은 증감식으로 위의 경우 i값을 0부터 1씩 올리고 있기 때문에, 10번 올린 후에는 i < 10이 거짓이 되어 for문을 마치게 된다.


무한 루프하고 싶을 경우 for(;;) 처럼 아무런 조건도 없는 내용을 써주면 반복한다.

for문 안에 for문이 들어가는 것도 가능하다.


while문

반복문이다. for문과 100% 호환되며. for문으로 짠 코드는 모두 while문으로 변환하는 것이 가능하다. 다만 while문은 while(i<10) 처럼 조건식만을 넣고 선언되며.. 보통 특정 조건이 만족되는 동안~ 반복하려는 때에 많이 사용한다.


확장판으로 do while이 있는데, 이 경우 조건의 참 여부와는 상관없이 일단 한번은 실행한다.


do

{

}

while(); 과 같이 사용한다. do while의 경우 ;가 붙는다.



switch문

다중선택을 하고 싶을 때 사용한다. if문을 사용해서 받은 숫자가 뭔지 확인한다면? 10개의 숫자가 있을 경우 if문을 10번이나 쓰거나.. else if를 여러개 두는 수고를 해야한다. 그런 불편함을 해소해주는 다중 선택문이다.


switch(x)

case 0 : ~내용

break;

case 1 : ~내용

break;

처럼... 사용하며 여러가지 처리문에 대응하기 적절하다.

단, switch 문으로 평가할 수 있는 것은 정수형이다. float형이나 사용자 정의형 등은 판별할 수 없기 때문에 지양해야한다. enum문을 사용하기에 좋다.

case문 사이에 break를 넣지 않으면 break를 만날때 까지 선택지들을 실행하기 때문에..

break가 없이 1부터 10까지 만들어두었다면 10은 10의 내용만 실행되고 끝나겠지만, 1은 1부터 10까지 전부 실행될 수도 있다.


goto

컴파일러가 코드를 읽다가 goto문을 만나면, 지정한 곳으로 점프하게 하는 제어문이다. 그러나.. 잘 쓰지 않을 뿐더러 잘 쓰지 않는 것이 좋다.


break;

if문이나 for문 등의 제어 영역에서 탈출하게 해주는 코드이다. break를 만나면 그 아래에 실행할 내용등을 무시하고 해당 영역을 탈출한다.


continue

if문에는 사용되지 않고 for , while의 반복문에만 사용되는데, break가 해당 영역을 탈출한다면 continue는 해당 영역을 읽은 것으로 치고.. 넘어간다. while 안에 break가 있다면 해당 코드는 거기서 끝이지만, continue를 만난 것이라면, 한번은 실행했다 치고.. 바로 조건식 쪽으로 돌아간다.






'프로그래밍 > 프로그래밍 공부' 카테고리의 다른 글

6장 함수  (0) 2015.02.27
5장 연산자  (0) 2015.02.27
4장 제어문  (0) 2015.02.27
3장 변수  (0) 2015.02.27
2장 프로그램의 구성 요소  (0) 2015.02.26
1장 프로그래밍 입문  (0) 2015.02.26
Posted by GENESIS8

댓글을 달아 주세요