안녕하세요!! 코딩하는 경제학도 쏘코입니다.
오늘은 이전 포스팅에서 다루지 못했던 함수의 심화 버전입니다!
만약 아직 함수 1편을 보시지 않았다면 아래 링크를 통해 확인하실 수 있습니다!
[객체지향프로그래밍] 5. 함수 1
안녕하세요! 코딩하는 경제학도 쏘코입니다. 오늘 포스팅의 주제는 C++의 핵심, 함수입니다. 비단 C++ 뿐만이 아니라 거의 모든 프로그래밍 언어에서 가장 중심이 되는 요소가 함수가 아닐까 생각
ssocoit.tistory.com
목차
0. 전역변수와 정적변수
함수 내에 있는 변수의 종류에는 일반적인 변수 이외에도 전역 변수(Global variable)와 정적 변수(Static Variable)이 있습니다.
전역변수와 정적변수의 공통점은 프로그램이 끝날 때 소멸됩니다.
(일반적인 지역변수의 경우 함수가 끝날 때 소멸되었었죠!)
이제 전역변수와 정적변수 각각의 특징에 대해서 알아보겠습니다.
전역변수는 해당 프로그램의 어느 파일, 함수에서도 접근이 가능합니다.
본문에서 사용할 때에는 main함수가 아닌 밖에 선언을 하면 되며
다른 파일에서 선언 후에 사용할 때에는 extern을 붙여서 사용할 수 있습니다.
아래 예시에서는 result라는 double형 전역변수를 이용하여 report, add, subtract 함수의 계산을 완료했습니다.
정적변수는 해당 변수가 선언된 파일 혹은 함수 내에서 접근이 가능한 변수입니다.
선언 시 static을 반드시 앞에 붙여줘야 하고, 초기화를 딱 한 번만 할 수 있습니다.
extern을 사용하지 않기 때문에 다른 파일에서 사용할 수 있는 방법은 없습니다.
특히, 초기화 하지 않은 상태로 사용되지 않으면 메모리가 할당되지 않습니다.
1. 함수의 특징
1.0. 함수 오버로딩
같은 이름의 함수이지만 매개변수를 각각 다르게 받는다면 다르게 동작하도록 만들 수 있습니다.
아래와 같은 사용이 가능합니다.
1.1. 기본값
사용자가 매개변수의 값을 제공하지 않을 경우에 기본적으로 함수에 전달되는 값이 바로 기본값입니다.
사용법은 매개변수의 옆에 (= 기본값) 을 붙여줍니다.
아래 예시에서는 5를 넣으면 n에 5가 전달되고, 아무 것도 넣지 않으면 기본값인 10이 n에 전달됩니다.
선언부와 구현부가 분리되어 있는 경우, 선언문에 기본값을 입력합니다.
여러 개의 기본값을 사용할 수 있지만, 기본값이 있는 변수는 반드시 뒤에 위치해야합니다.
그렇지 않으면 값을 덜 입력받았을 때 어떤 변수에 기본값을 넣어줘야 할 지 모르기 때문입니다.
1.2. 재귀
함수는 자기 자신을 함수 내부에서 다시 사용할 수 있습니다.
아래 예시는 F라는 함수를 함수 내부에서 다시 사용하여 입력받은 수의 첫 자리부터 끝 자리까지 순서대로 출력하는 예시입니다.
가장 대표적인 재귀함수의 예시는 팩토리얼입니다.
n! = n * (n-1) * ... * 1인데, 이것을 함수 식으로 표현하면 아래와 같이 표현할 수 있습니다.
재귀함수의 경우 반드시 종료 조건이 존재해야 합니다.
종료 조건이 없다면 함수가 끝나지 않고 무한루프에 빠지는 상황이 됩니다.
아래 팩토리얼의 예시에서는 종료조건이 n == 0입니다.
1.3. 파일 분리
다른 파일에 선언된 변수를 전역변수로 가져와서 사용하는 경우가 있다고 위에서 언급했었죠?
이번엔 파일 분리를 직접 하는 것을 보여드리겠습니다.
파일을 분리하면 따로 관리하기에도 편하고, 함수의 재사용성도 높아집니다.
파일 분리의 경우 함수의 구현부를 .cpp파일에, 선언부를 .h파일에 작성합니다.
(.cpp의 경우 소스 파일, .h의 경우 헤더 파일이라고도 부릅니다)
그리고 두 파일을 연결할 때에는 구현부에서 #include "헤더파일명.h"를 넣어주면 됩니다.
이전에 #include <iostream>과는 다르게 <>가 아닌 큰따옴표를 사용했죠?
기본 라이브러리의 경우 <>를 사용하고 그 외의 경우 ""를 사용한다고 생각하시면 됩니다!
선언부룰 .h에 작성하고, 구현부를 .cpp에 작성했다면 이제 어떻게 main함수가 있는 곳에서 사용할 수 있을까요?
연결했을 때와 똑같이 #include 전처리문을 이용하여 .h 파일을 불러옵니다.
아래 예시는 어떻게 나눠서 작성하고, test.cpp에서 사용할 수 있는 지에 대해 나와있습니다.
2. 포인터
C++에서 피해갈 수 없는 코너, 바로 포인터입니다.
포인터를 이해하기 위해서는 먼저 주소값에 대한 이해가 필요합니다.
데이터의 주소값은 해당 데이터가 저장된 메모리의 시작 주소를 의미합니다.
C++에서는 주소값을 1byte 크기의 메모리 공간으로 나누어서 이해할 수 있습니다.
int형 데이터는 4byte의 메모리 공간을 필요로 하지만, int형 데이터의 주소값은 메모리 공간의 맨 앞 1byte만을 가리킵니다.
C++에서는 어떤 변수의 주소값에 접근하고 싶을 때 변수 앞에 &(주소 연산자)를 넣어줍니다.
int x의 주소값은 &x가 되는 것이죠!
그렇다면 포인터는 무엇일까요?
포인터는 메모리의 주소값을 저장하는 변수입니다. 포인터 변수라고도 부르죠.
char가 문자, int가 정수를 저장한다면 포인터 변수는 주소값을 저장합니다.
이 포인터 변수는 변수명 앞에 *(참조 연산자)를 붙임으로써 자신이 포인터 변수임을 드러냅니다.
int* p를 선언하면 p라는 이름의 포인터 변수가 생성됩니다.
*(참조 연산자)의 경우 포인터 변수에 저장되어 있는 주소값의 실제 값에 접근할 때도 사용합니다.
p라는 포인터 변수에 저장되어 있는 주소에 들어있는 값에 접근하고 싶다면
*p를 통해 접근할 수 있습니다.
*p의 값을 변경해줌으로써 p라는 주소에 있는 요소를 변경시킬 수도 있습니다.
우리가 주소값에 접근할 때 &를 사용한다고 했죠?
그렇다면 포인터에 주소값을 넣어줄 때는 *와 &를 적절히 섞어주면 되겠죠?!!
아래 예시에서는 x라는 변수의 주소값을 p라는 포인터 변수에 넣어줬습니다.
&x, p, x, *p의 값을 출력하면서 값이 어떻게 변화하는 지를 이해해보면 도움이 됩니다!
3. Pass by Reference
이전 포스팅에서 Pass by Value에 대해서 배운 적이 있습니다.
value값을 그대로 전달하고, 전달된 변수는 함수 안에서만 쓰이고 함수가 끝나면 메모리에서 사라진다고 배웠었죠?
Pass by Reference는 값이 아닌 주소값을 전달합니다.
지역변수가 아닌 메모리의 주소값을 직접 전달했기 때문에, 주소값에 들어있는 내용을 변경하면 함수가 끝나도 변경된 상태로 남아있게 됩니다.
(Pass 대신 Call이라는 용어를 사용하기도 합니다. Call by Value, Call by Reference처럼!!)
아래 예시는 Pass by Value와 Pass by Reference의 가장 대표적인 예인 swap함수입니다.
두 변수의 값을 바꿔주는 함수인데,
만약 매개변수를 일반 변수로 받으면 함수 안에서는 바뀌어도 함수 밖의 변수는 변화가 없지만
Reference 변수로 받으면 실제로 값이 바뀌게 됩니다.
Pass by Pointer (Call by Pointer)도 가능합니다.
매개변수로 주소값을 받고, 그 주소값의 참조 연산자를 이용하여 주소값에 위치한 값에 접근하여 값을 바꿉니다.
Pass by Reference와 같은 메커니즘으로 작동하기 때문에, 편리한 것을 사용하시면 되겠습니다.
(저는 Pass by Reference를 더 선호합니다. 이해하기 편하잖아요!)
4. 고차 함수
고차 함수(Higher-order Function)는 하나 이상의 함수를 매개변수로 가지거나, 함수를 결과로 반환하는 함수입니다.
함수를 매개변수로 가지기 위해서는 함수 포인터가 필요합니다.
함수 포인터는 함수의 주소를 가진 포인터 변수를 의미합니다.
함수 포인터는 리턴형 (*함수 포인터명)(); 형식으로 만들 수 있습니다.
아래 예시는 add라는 함수를 만들고, main함수 내에서 int형 결과값을 가지는 func라는 함수 포인터를 만들었습니다.
이 함수 포인터 func에 add의 주소값을 넣어줍니다.
add라는 함수의 주소값은 add로 접근할 수 있습니다. (괄호 없이 함수명만 쓰면 주소값을 반환합니다!)
이제 func라는 이름으로 add라는 함수를 사용할 수 있게 되었습니다!
아래 예시는 evaluate라는 함수의 매개변수로 함수 포인터를 받는 경우입니다.
매개변수의 순서를 보면 첫 번째 매개변수는 함수 포인터, 나머지 두 변수는 int형 변수입니다.
그리고 이 int형 변수를 이용하여 함수 포인터에 있는 함수를 작동시키는 구조입니다.
함수 포인터에는 함수의 주소가 들어가야 하기 때문에 main함수 내에서 add와 multiply의 주소값을 넣었다는 것을 확인하시면 되겠습니다!
최대한 쉽게 설명해드리려고 노력했습니다..
사실 몇번을 봐도 이해가 잘 안될 수 있는 부분이 포인터와 레퍼런스 부분이기 때문에
몇 번이고 보시고, 다른 자료들도 확인해 보시면서 익숙해 지시는 것이 제일 중요합니다.
&와 *를 이용한 메모리 조작이 C++의 꽃이니까요!
그렇다면 다음 포스팅에서는 연속적인 데이터를 다루기 위한 방법에 대해서 알아보도록 하겠습니다!
읽어주셔서 감사합니다 :)
최근댓글