내용 참고
YES C (정보공학연구소/생능출판사)
혼자 연구하는 C/C++ (Soen.kr/와우북스)
Microsoft Docs (구 MSDN)
함수
Ⅰ. 프로그래밍에서의 함수
ⅰ. 절차지향 프로그램에서 함수의 의의
■ 함수란 C로 만들어진 프로그램에서 프로그램을 구성하는 단위이다.
■ 이는 C언어가 기본적으로 절차지향 프로그래밍 방법론에 따라 설계되었기 때문이다.
◆ 절차지향 프로그래밍 (Procedual Oriented Programming)
■ 절차치향 프로그래밍에서는 분할정복전략으로 문제를 해결한다.
◆ 분할 정복 전략 (Divide and Conquer)
■ 분할정복전략이란 큰 문제를 여러개의 작은 문제로 나눠서 해결하는 문제 해결 전략이다.
■ C 프로그램은 주로 함수라는 기능별 문제 해결 단위를 모아서 큰 문제를 해결한다.
▶ 객체 지향 프로그램에서는 함수 대신에 객체가 프로그램의 단위를 이룬다.
▶ 함수형 프로그래밍에서의 함수는 '순수 함수'를 의미하며 절차지향 프로그래밍에서 말하는 함수와는 개념이 좀 다르다.
★ 클래스 안에 있는 함수는 메소드라고 한다. 추후에 클래스를 공부할 때 참고하자.
ⅱ. 함수의 장점
■ 프로그램내에서 반복되는 부분을 함수로 처리함으로 불필요한 반복을 줄이고 메모리를 절약할 수 있다.
■ 프로그램의 기능에 따라 함수로 만드는 것으로 프로그램이 모듈화되어 프로그램의 가독성을 높일 수 있다.
■ 기능 단위로 제작된 함수는 다음 프로그램을 제작할 때 재사용이 가능하다.
■ 함수의 내부 구조를 몰라도 매개변수와 반환값만 맞으면 타인이 만든 함수를 사용할 수 있다.
Ⅱ. C/C++의 함수의 종류
ⅰ. main 함수
■ C/C++ 프로그램이 실행되면 운영체제는 main함수를 실행하며 main함수가 끝나면 프로그램도 종료한다.
■ 즉, main함수는 C/C++ 프로그램의 시작과 끝의 역할을 수행한다.
■ 그러므로 main함수는 프로그램내에 단 하나만 존재해야한다.
■ main 함수는 기본적으로 int값을 반환하지만 반환값이 없을 수도 있다.
▶ main함수에 대해서는 추후에 공부해야 하는 쉽지 않은 내용이 많다.
ⅱ. 표준 함수
■ printf나 scanf와 같이 언어 자체에서 제공되는 함수를 의미한다.
■ 하지만 C/C++ 같은 경우에는 언어 자체에서 라이브러리를 제공하는 것일 뿐 함수가 언어에 내장되어 있지는 않다.
■ 그러므로 표준 함수를 사용하려면 그에 맞는 라이브러리 파일을 include 명령어로 링킹해줄 필요가 있다.
ⅲ. 사용자 정의 함수
■ 프로그래머가 필요에 따라 직접 정의하는 함수를 의미한다.
ⅳ. 매크로 함수 (or 인라인 함수)
■ 실제 함수 정의는 아니지만 #define 선언문을 이용해서 함수처럼 사용할 수 있는 수식을 만든 것을 의미한다.
■ 매크로 함수는 컴파일 과정에서 코드의 문자열을 수식으로 치환하기에 '인라인 함수'라고도 부른다.
■ 매크로 함수는 속도면에서는 유리하지만 파일의 크기가 커진다는 단점이 있다.
■ 무엇보다도 단순 치환이기 때문에 의도와 다르게 작동할 수도 있으므로 사용시 세심한 주의가 필요하다.
#include <iostream>
using namespace std;
#define ab(a) ( (a)>0?(a):-(a) )
int main()
{
cout << ab(-123);
return 0;
}
■ 단순 치환이라는 부분 때문에 매크로 함수를 만들 때는 주의할 점이 많은데 이는 추후에 자세히 다룰 예정이다.
Ⅲ. 함수 정의하기
ⅰ. 함수의 정의
■ 함수의 기본 구조는 아래와 같다.
■ 반환데이터타입 : 함수가 최종적으로 반환하는 값의 데이터 타입. 없으면 void라고 명시해야한다.
■ 함수명: 함수의 이름, 식별자로 구분되므로 C언어의 이름짓기 규칙을 지켜야 한다.
■ 인수목록 : 함수 내부로 전달되는 값. 없으면 비워놓는다.
■ 본체 : 함수가 호출되면 실행할 명령 목록.
■ 우측의 함수는 정수 하나를 입력받고 정수 하나를 반환하는 함수로 입력된 값의 절대값을 반환한다.
ⅱ. 함수 본문 작성하기
■ 함수의 기본구조에 맞게 함수의 틀을 마련했다면 함수의 본문을 작성해야 한다.
■ 인수는 함수를 호출한 호출원에서 함수에게 넘겨주는 값이다.
■ 두 함수 사이의 정보 교환에 사용된다는 의미에서 매개변수라고도 한다.
■ 인수가 필요하지 않다면 인수 목록을 비워놓거나, 인수 목록에 void라고 쓰면 된다.
■ 물론 인수 목록에 굳이 void를 쓰는 경우는 아직 본 적이 없다.
■ 함수 정의의 인수는 영어로 parameter, 함수 호출시에 전달하는 인수의 값은 argument라고 한다.
■ 함수 본문에서 parameter를 사용할 땐 parameter에 쓴 변수명을 그대로 쓰면 된다.
■ 함수 안에서 새로운 변수를 정의하는 것도 가능하다.
■ 다만 이렇게 정의한 변수는 스코프 규칙에 의해서 정의한 함수 안에서만 사용할 수 있다.
■ 이를 이용하여 원하는 작업을 수행하고 나서 return문을 이용하여 값을 반환해주면 된다.
■ 반환값이 없는 함수를 만들었어도 return문을 쓰면 함수가 종료된다.
■ 즉, return문을 사용하면 분기에 따라 중간에 함수를 끝내고 값을 반환시킬 수도 있다.
■ 반환값이 void인 경우 return문을 생략할 수도 있지만 이는 컴파일러가 return문을 추가하는 것으로 추천하지 않는다.
■ 대신 반환값은 없으므로 return; 만 쓰면 된다.
■ 반환값이 지정된 타입이 아닐 경우 컴파일러는 암시적 형변환을 시도하고 실패하면 에러를 표시한다.
■ main 함수도 함수이기 때문에 return 0;를 만나면 종료된다.
ⅱ. 만든 함수 사용하기
■ 표준 함수를 사용했던 것 처럼 사용하면 된다.
■ 반환 타입이 들어가는 자리에는 같은 반환 값을 가진 함수를 항상 쓸 수 있다.
■ 예를 들어 정수를 인수로 받는 함수의 인자로 정수를 리턴하는 함수를 쓸 수도 있다.
■ 선언과 정의를 분리했다면 선언만 있어도 사용할 수 있다.
■ 선언하고 사용했는데 정의가 없다면 링크 과정에서 에러가 나니 주의해야한다.
Ⅳ. 선언과 정의 분리하기
ⅰ. 라이브러리 링킹과 함수 선언
■ 프로그램의 시작은 main함수이므로 정의한 함수는 기본적으로 main함수에서 사용된다.
■ 그런데 C/C++ 컴파일러는 소스 코드를 위에서 아래로 해석한다.
■ 그러므로 함수 정의나 라이브러리는 기본적으로 main함수 위에 위치해야한다.
■ 이 때 main 함수 위에는 함수의 원형만 선언하고 실제 정의는 main 함수 아래에서 할 수도 있다.
#include <iostream>
using namespace std;
int main()
{
cout << a(-19); // 오류C3861 : 식별자 a를 찾을 수 없습니다.
cout << abs(-123);
return 0;
}
int a(int a) {
return a;
}
int abs(int a) {
return a > 0 ? a : -a;
}
■ 위의 코드는 main함수에서 함수 a를 호출하는 시점에서 오류가 발생한다.
◆ 참고로 함수 abs는 오류가 나지 않는데, 아마 abs라는 함수가 헤더파일에 이미 정의되어 있기 때문이다.
◆ 이런 경우 추후에 에러를 유발할 가능성이 높으므로 주의하는 것이 좋다.
#include <iostream>
using namespace std;
int a(int a); // 함수 a에 대한 원형만 미리 선언
int main()
{
cout << a(-19);
return 0;
}
//함수 a에 대한 실제 정의
int a(int a) {
return a;
}
■ 위와 같이 main 함수 위에 함수 a에 대한 원형을 선언해주면 해결된다.
■ 이런식으로 함수의 선언과 정의를 분리하는 것은 함수의 정의가 길 경우 큰 도움이 된다.
■ 추후에는 함수를 헤더파일에 정의 및 선언하고 헤더를 가져다 쓰는 경우가 많다.
■ 헤더파일에는 이 외에도 매크로 상수나 열거형 타입, 매크로 함수, 사용자 정의 자료형 등이 선언 및 정의되어 있다.
ⅱ. 함수 원형
■ 함수의 원형이란 함수의 본체를 정의하기 전에 함수의 형태를 컴파일러에게 먼저 알려주기 위해서 사용하는 함수 선언문이다.
■ 함수 원형은 변수데이터타입 함수명(인수목록); 의 형태로 작성하면 된다. (세미콜론 필수!)
■ 함수의 원형 선언에는 인수의 타입만 적고 인수의 이름은 생략할 수도 있지만 사용시 의미를 명확히 하기위해서 권장하지는 않는다.
■ 함수 원형을 사용하지 않을 경우에는 아래와 같이 함수의 정의가 main함수 위에 와야한다.
■ 이는 사용자 정의 함수가 여럿이거나 함수간의 상호 참조등이 이루어질 경우 매우 불편하며 문제를 일으킬 수도 있다.
■ 아래 예제의 경우 max2의 함수 정의와 max1의 함수 정의의 순서가 바뀌면 에러가 일어난다.
⑤ 하지만 원형을 사용하면 원형이든 정의든 순서가 상관없어진다.