19. 함수 사용하기
함수는 코드의 재사용성을 높이기 위해 특정 작업을 수행하는 코드 블록입니다. 이번 강의에서는 함수를 활용하여 반복되는 코드를 효율적으로 관리하는 방법을 알아보겠습니다.
> // 함수(Function): 반복해서 사용하도록 만들어진 하나 이상의 문을 포함하는 코드 단위(블록)
- 함수는 하나 이상의 문(statement)을 포함하는 코드 블록으로, 반복적으로 사용할 수 있습니다.
- 함수는 특정 작업을 수행하는 코드 블록이며, 이름, 매개변수(parameters), 본문(body), 그리고 반환문(return statement)으로 구성됩니다.
함수 소개
프로그래밍을 하다 보면 종종 동일한 유형의 코드가 반복됩니다. 이런 코드를 매번 작성하는 것은 비효율적이며 오류가 발생할 가능성도 높습니다. 함수를 사용하면 이런 문제를 해결할 수 있습니다.
함수는 특정 작업을 수행하는 코드 블록으로, 재사용을 목적으로 합니다. 함수는 입력값을 받아 처리하고 결과값을 반환하는 코드입니다. 함수는 프로그램 내에서 독립적으로 작동하는 모듈 또는 단위로 간주됩니다. 예를 들어, C언어에서 main 함수는 프로그램의 시작점을 나타내는 특수한 함수이며, printf()는 콘솔에 출력하는 함수입니다. 참고로, 과거 프로그래밍 문헌에서는 함수를 "루틴(Routine)", "서브 프로시저(Sub Procedure)", 또는 "서브 루틴(Sub Routine)" 등으로도 표현했습니다.
입력, 처리, 출력
함수는 일련의 작업들을 수행하는데 중심적인 역할을 하는데, 특히 입력을 받아 처리하고, 결과를 출력하는 과정에 있어서 중요합니다. 아래 그림은 이 과정을 간략히 도식화한 것으로, 함수가 처리 과정을 담당하는 이름이 있는 코드 블록으로 구성되어 있음을 보여줍니다.
그림: 입력, 처리, 출력
여기서 입력은 함수가 처리할 데이터를 제공하는 단계, 처리는 이 데이터를 사용하여 특정 작업을 수행하는 단계, 그리고 출력은 처리된 결과를 반환하는 단계로 구성됩니다. 함수를 통해 이 세 가지 주요 단계를 효율적으로 관리할 수 있습니다. 함수는 다음 그림의 처리를 담당하는 부분을 따로 이름있는 코드 블록으로 지정하는걸 말합니다.
함수의 종류: 내장 함수와 사용자 정의 함수
내장 함수(built-in function)는 프로그래밍 언어가 제공하는 미리 정의된 함수로, 문자열 처리, 날짜 및 시간 계산, 수학 연산, 형 변환 등 다양한 기능을 포함합니다. 내장 함수들은 종종 API(Application Programming Interface) 또는 라이브러리(library)의 일부로 제공됩니다.
반면, 사용자 정의 함수(user-defined function)는 프로그래머가 필요에 따라 직접 생성하여 사용하는 함수입니다.
함수 정의하고 사용하기
함수를 생성하는 것을 "정의(define)"라고 하며, 만들어진 함수를 실행하는 것을 "호출(call)"이라고 합니다. 함수를 정의하고 호출하는 데는 소괄호가 사용됩니다.
기본적인 함수 정의 형태는 다음과 같습니다:
함수이름()
{
// 함수 본문
}
함수를 호출하는 방법은 다음과 같이 세 가지 형태로 표현할 수 있습니다:
함수이름();
함수이름(매개변수);
결과값 = 함수이름(매개변수);
함수를 만들고 사용하는 내용을 그림으로 표현하면 다음과 같습니다.
그림: 함수 정의 후 호출
C언어에서는 사용자 정의 함수를 main 함수 앞에 정의하는 것이 일반적입니다. 하지만 함수 원형(prototype)을 사용하면 main 함수 뒤에 함수를 정의할 수도 있습니다.
main 함수에서 sub 이름으로 만들어진 함수를 호출하는 내용을 그림으로 표현하면 다음과 같습니다.
그림: 함수 실행 순서
함수 만들고 호출하여 사용하기
이번에는 함수의 가장 기본적인 모양을 만들고 사용해보겠습니다. 참고로 다음 코드의 Show()
메서드는 Main()
메서드 밑에 코드를 작성해도 상관 없습니다.
코드: FunctionDemo.cs
// FunctionDemo.cs
using System;
class FunctionDemo
{
//[1] Show 메서드(함수)
static void Show()
{
Console.WriteLine("Hello World");
}
// Main 메서드(함수)
static void Main()
{
Show(); //[2] 호출
}
}
Hello World
위 코드는 [1]
번 코드 영역에 Show()
이름의 함수를 만들고 이를 Main()
메서드의 [2]
번에서 호출해 보는 내용입니다. Show()
함수와 같은 형태를 가장 간단한 형태의 함수로 매개 변수(Parameter)도 없고 반환값(Return Value)도 없는 형태입니다. 잠시 후에 매개 변수와 반환값에 대해 알아봅니다.
함수 선언(Function declaration)
함수를 만드는 작업을 함수 선언이라고 합니다.
함수 만들고 반복 사용하기
함수를 만드는 목적 중 하나는 반복 사용에 있습니다. 함수를 만들고 여러 번 호출해서 사용하는 방법을 알아보겠습니다. main 함수를 포함해서 최소한의 코드로 표현했습니다.
코드: function_call.c
//[?] 함수(Function): 반복하여 사용하도록 하나의 이름으로 만들어 놓은 코드의 집합
#include <stdio.h>
//[1] 함수 만들기(정의, 선언)
hi()
{
puts("안녕하세요.");
}
int main(void)
{
//[2] 함수 사용하기(호출): 여러 번 호출
hi(); hi(); hi();
return 0;
}
안녕하세요.
안녕하세요.
안녕하세요.
이번 코드에서는 hi
이름으로 함수를 만들고 이를 main
함수에서 3번 호출해서 사용하는 내용입니다. C 언어 프로그래밍에서 함수 선언은 함수를 호출하기에 앞서서 코드가 위치해야합니다. 함수의 첫번째 사용 목적 중 하나는 반복 사용에 있습니다. 한번 코드로 만들어 놓은 함수를 여러 번 호출하여 사용할 수 있습니다.
19.7 매개 변수와 반환값
함수를 만들어 놓고 동일한 기능을 하는 함수만을 사용하지는 않습니다. 호출할 때마다 조금씩 다른 기능을 적용하고자할 때에는 함수의 매개 변수(Parameter)를 달리하여 호출할 수 있습니다. 함수에게 어떤 값을 처리하라고 넘겨주는 값은 문자열, 숫자 등 모든 데이터 타입을 사용할 수 있습니다. 이를 가리켜 인수(Argument), 인자, 파라미터(Parameter), 매개 변수 등으로 부르는데 C 언어를 배우는 시점에서는 모두 같은 개념으로 보면 됩니다.
19.7.1 함수의 매개 변수 선언
매개 변수(인자, 인수, 파라미터)는 함수에게 어떠한 정보를 넘겨주는 데이터를 나타냅니다. 이러한 매개 변수는 콤마 기호를 기준으로 여러 개를 설정할 수 있습니다.
19.7.2 매개 변수(인자, 파라미터)가 없는 함수
매개 변수도 없고 반환되는 값도 없는 함수 형태는 가장 단순한 형태의 함수로서, 함수 이름 뒤에 따라오는 괄호에 인자로 아무 값도 지정하지 않는 모양을 말합니다. 앞서서 사용해 본 함수 중에서 우리가 만든 hi 함수와 같이 빈 괄호만 사용하는 함수 형식을 나타냅니다.
19.7.3 매개 변수가 있는 함수
특정 함수에게 한 개 이상의 인자값을 전달하는 방식을 말하며 정수형, 실수형, 문자형, 문자열형 등 여러 가지 데이터 타입을 인자값으로 전달할 수 있습니다.
19.7.4 반환값이 있는 함수(결괏값이 있는 함수)
함수의 처리 결과를 함수를 호출한 쪽으로 반환하고자 할 때에는 return
키워드를 사용하여 데이터를 돌려줄 수 있습니다. 참고로, 반환값이 있는 함수를 펑션(Function)이라고도 부르고, 반환값이 없는 함수를 서브 프로시저(Sub Procedure)라고도 부릅니다.
19.8 매개 변수가 있는 함수
이번에는 매개 변수(Parameter)가 있는 함수를 만들고 사용해보겠습니다.
코드: function_parameter.c
//[?] 매개 변수(Parameter)가 있는 함수 만들고 호출하기
#include <stdio.h>
// 매개 변수가 있는 함수
void show_message(char* message)
{
puts(message); // 넘어온 매개 변수의 값을 출력
}
int main(void)
{
show_message("매개 변수"); // show_message 함수에 "매개 변수" 문자열 전달
show_message("Parameter"); // show_message 함수에 "Parameter" 문자열 전달
return 0;
}
매개 변수
Parameter
함수의 괄호 안에는 매개 변수를 선언할 수 있는데, showMessage(char* message)
형태로 함수 호출시 문자열을 받아서 message
변수에 저장합니다. 함수를 호출할 때 동일한 데이터 타입을 전달해야 합니다. 함수의 매개 변수는 콤마 기호를 구분으로 하나 이상을 줄 수 있습니다. 참고로, main
함수와 showMessage
함수 앞에는 반환값이 없다는 의미의 void
키워드를 추가했지만 생략해도 됩니다.
19.9 반환값이 있는 함수
함수의 여러 가지 특징 중 하나인 반환값(Return Value)은 함수에서 어떤 처리를 진행 후 그 결과를 다시 함수를 호출한 부분으로 되돌려 주는 것을 말합니다. 되돌려주는 값은 매개 변수와 마찬가지로 C 언어의 모든 데이터 타입으로 줄 수 있습니다. 반환값이 있는 함수를 만들 때에는 반환값이 없다는 의미의 void
키워드 자리에 반환되는 데이터 타입을 기술하면 됩니다. 반환값이 없는 함수는 void
로 지정하거나 생략이 가능합니다. 즉, 지금까지 사용한 C 언어의 기본 코드인 main
함수는 반환값이 생략하거나 void
또는 int
로 반환값을 설정할 수 있습니다.
19.9.1 문자열 반환값이 있는 함수 만들고 사용하기
문자열 데이터를 반환하는 함수를 만들고 호출해보겠습니다. 참고로, 문자열 리터럴을 담고 반환 시켜줄 수 있는 문자열 데이터 타입은 char*
키워드를 사용했습니다.
코드: return_value.c
// 반환값이 있는 함수 만들고 호출하기
#include <stdio.h>
char* get_string()
{
return "반환값(Return Value)"; // return 키워드로 단순 문자열 반환
}
int main(void)
{
// get_string 함수 호출 후 반환된 반환값을 return_value 변수에 저장
char* return_value = get_string();
printf("%s\n", return_value);
return 0;
}
반환값(Return Value)
get_string
함수를 호출하면 return
키워드에 의해서 "반환값(Return Value)" 문자열이 함수를 호출한 부분으로 반환이 됩니다. 이 반환된 문자열을 return_value
변수에 담아서 main
함수에서 사용하는 내용입니다.
19.9.2 정수형 반환값이 있는 함수 만들고 사용하기
이번에는 int 형식의 반환값이 있는 함수를 사용해보겠습니다.
코드: function_return_value.c
// 반환값이 있는 함수
#include <stdio.h>
int SquareFunction(int x) // 입력: 매개 변수도 있고
{
int r = x * x; // 처리: 함수의 본문
return r; // 출력: 반환값도 있는
}
int main(void)
{
int r = SquareFunction(2); // 함수 호출 및 반환값 받기
printf("%d\n", r); // 4
return 0;
}
4
매개 변수 x
로 정수형 데이터가 넘어오면 그 값을 2번 곱해서 그 결괏값을 함수를 호출한 main
함수 영역으로 되돌려주는 내용입니다. 입력(Input), 처리(Process), 출력(Output)이 있는 전형적인 함수의 유형으로 이러한 함수 스타일은 앞으로 계속해서 사용하게 될 것입니다.
19.10 두 수의 합을 구하는 함수
다음 코드는 2개의 실수 데이터를 받아서 그 합을 구한 후 그 값을 결괏값으로 되돌려주는 함수입니다.
코드: get_sum_two_number.c
#include <stdio.h>
// 두 수의 합을 구하는 함수
double get_sum(double x, double y)
{
double r = x + y;
return r;
}
int main(void)
{
double result = get_sum(3.0, 0.14);
printf("%lf\n", result); // 3.14
return 0;
}
3.140000
get_sum()
함수는 double
타입 2개를 받아서 더한 후 그 결과를 다시 main
함수로 돌려주는 형태입니다.
반환값이 있는 함수 반복 설명
반환값이 있는 함수는 C 언어에서 가장 기본적인 개념 중 하나입니다. 이번 아티클에서는 C 언어에서 반환값이 있는 함수의 개념과 사용법에 대해 알아보겠습니다. 또한, 예시 코드를 통해 어떻게 반환값이 있는 함수를 작성하고 호출하는지 살펴보겠습니다.
반환값이 있는 함수란?
반환값이 있는 함수는, 함수가 실행된 결과 값을 반환하는 함수를 의미합니다. 이러한 함수는 함수의 반환형에 따라, 반환할 값의 데이터 타입과 형식을 명시할 수 있습니다. 반환형으로는 int, float, double, char 등의 데이터 타입이 사용됩니다.
아래는 반환값이 있는 함수의 형식입니다.
<반환형> <함수명>(<매개변수>) {
// 실행 코드
return <반환값>;
}
반환값이 있는 함수는 다음과 같은 형식으로 작성됩니다. 함수명, 매개변수, 반환형 등의 구성 요소는 반환값이 없는 함수와 동일합니다. 하지만 함수 내부에서 계산된 결과 값을 return 키워드를 사용하여 반환하는 것이 반환값이 있는 함수의 특징입니다.
반환값이 있는 함수 예시
다음은 반환값이 있는 함수의 예시 코드입니다.
#include <stdio.h>
int sum(int num1, int num2) {
return num1 + num2;
}
int main(void) {
int result;
result = sum(5, 5);
printf("5 + 5 = %d\n", result);
return 0;
}
위 코드에서는 반환값이 있는 함수 sum을 정의하고 호출하고 있습니다. sum 함수는 두 개의 정수 값을 입력받아 덧셈을 계산하고, 계산된 결과 값을 반환합니다.
sum 함수의 반환형은 int이므로, 반환할 값의 데이터 타입과 형식을 명시해주어야 합니다. 반환값은 return 키워드를 사용하여 반환하며, 반환되는 값은 sum 함수의 반환형과 일치해야 합니다.
main 함수에서는 sum 함수를 호출하고, 반환된 값을 result 변수에 저장하고 출력하는 예시 코드입니다.
전체 코드와 실행 결과는 다음과 같습니다.
코드: function_return_value_sum.c
#include <stdio.h>
void hi(void) {
printf("안녕\n");
}
void hello(char message[]) {
printf("%s\n", message);
}
int sum(int num1, int num2) {
return num1 + num2;
}
int main(void) {
int result;
// [1] 매개변수도 없고 반환값도 없는 경우
hi();
hi();
// [2] 매개변수는 있고 반환값이 없는 경우
hello("안녕하세요.");
hello("반갑습니다.");
// [3] 매개변수도 있고 반환값도 있는 경우
result = sum(5, 5);
printf("%d\n", result);
return 0;
}
안녕
안녕
안녕하세요.
반갑습니다.
10
결론
반환값이 있는 함수는 C 언어에서 매우 중요한 개념 중 하나입니다. 반환값이 있는 함수를 사용하면 함수의 실행 결과 값을 다른 변수에 저장하거나, 다른 함수의 인자 값으로 사용할 수 있습니다. 함수의 반환형과 일치하는 데이터 타입의 값을 반환하며, return 키워드를 사용하여 반환합니다. 반환값이 있는 함수는 C 언어에서 매우 자주 사용되는 개념이므로, 반드시 익혀두어야 합니다.
19.11 함수 원형
함수 선언은 반드시 main
함수 앞에 위치해야 합니다. 하지만, 함수 원형(prototype)을 사용하여 함수에 대한 시그니처를 main
함수 앞에 위치하고 실제 함수 본문은 main
함수 뒤에 올 수 있습니다.
다음 코드는 say
함수가 main
함수 뒤에 오는 형태라서 say
함수에 대한 정보를 알 수가 없어서 에러가 발생합니다.
코드: function_prototype.c
에러 발생 코드
#include <stdio.h>
int main(void)
{
say();
return 0;
}
void say(void)
{
printf("안녕하세요.\n");
}
사용자 정의 함수가 main
함수 앞에 오지 않는 경우에는 반드시 사용자 정의 함수의 함수 시그니처를 main
함수 앞에 선언해 주어야 합니다. 이것을 함수 원형이라고 합니다. 함수 원형을 선언 후 main
함수 뒤에서 함수 본문을 정의해주면 정상적으로 함수 호출이 이루어집니다.
코드: function_prototype.c
정상 실행 코드
#include <stdio.h>
//[1] 함수 원형 선언
void say();
int main(void)
{
say();
return 0;
}
//[2] 함수 본문 정의
void say(void)
{
printf("안녕하세요.\n");
}
안녕하세요.
C 언어에서는 반드시 main
함수 앞에 함수 원형 또는 함수 본문에 대한 정의가 와야 합니다. 다만, 강의에서는 특별한 경우가 아니면 지면을 아끼기 위해서 함수 원형 보다는 함수 내용이 main
함수 앞쪽에 위치할 예정입니다.
19.12 함수 선언 형식과 관련 용어 정리
이쯤에서 함수(함수) 관련 용어를 정리해 보겠습니다. 앞으로도 계속 다룰 내용이기에 한번 정도 읽고 넘어가도 됩니다. 다음 코드 조각은 main
함수의 가장 자세한 모양입니다.
int main(int argc, char *argv[])
{
return 0;
}
- main 함수 선언 형식: 함수는 위 코드와 같은 구조를 가지는데, 함수의 모양은 서로 다른 모습으로 보여질 수 있는데, 이를 함수 시그니처(Signature)라고 부릅니다.
- void: 함수의 반환 형식이 오는 자리이며
void
키워드는 반환값이 없다는 것을 나타냅니다. 이는 함수 수행 결과 어떤 값을 반환하고자 할 때 반환하고자 하는 데이터의 형식을 말합니다. - main: 함수의 이름을 나타내며 함수 이름은 영문 소문자로 시작합니다. 강의에서는 사용자 정의 함수는 영문 대문자로 표현을 많이 합니다.
- int argc, char *argv[]: 매개 변수(Parameter) 영역이며 함수에 어떤 값을 넘겨주고자 할 때 또는 넘겨받고자 할 때 이를 잠시 보관해 놓는 그릇 역할을 하는 매개체가 되는 변수(배열)를 나타냅니다. 매개 변수는 콤마(,) 기호를 구분으로 0개 이상을 둘 수 있습니다.
main
함수에서는 다른 함수와 달리int argc, char *argv[]
를 사용하는데 이는 다른 말로 명령줄 인수(Command Line Argument)라고 하며 예전 운영체제인 도스(DOS) 시절에 주로 사용하던 방식으로, 어떤 실행 파일(EXE 파일)에게 인수(Parameter) 값을 넘겨줄 때, 그 넘겨져 온 인수 값을 가리켜 명령줄 인수(매개 변수)라고 하는데, 이를 프로그램에서 받으려면 C 언어에서는main
함수의 매개 변수로 받아 사용합니다. - 블록({}) : 함수의 실행 범위(Scope)를 나타내며 함수의 블록 내에서 선언된 변수는 해당 함수가 종료되면 소멸됩니다.
19.13 함수를 사용하여 큰값과 작은값 또는 절댓값 구하기
매개 변수도 있고 반환값도 있는 함수를 사용하여 두 수 중에서 큰 값과 작은 값을 구해 보도록 하겠습니다.
코드: max_min_function.c
// 함수를 사용하여 큰 값과 작은 값 구하기
#include <stdio.h>
// max 함수: 두 수 중에서 큰 수를 반환시켜주는 함수
int max(int x, int y)
{
return (x > y) ? x : y; // 3항 연산자로 큰 수 구하기
}
// min 함수: 두 수 중에서 작은 수를 반환시켜주는 함수
int min(int x, int y)
{
// if else 문으로 작은 수 구하기
if (x < y)
{
return x; // 작은 값
}
else
{
return y;
}
}
int main(void)
{
printf("%d\n", max(3, 5)); // 5
printf("%d\n", min(-3, -5)); // -5
return 0;
}
5
-5
max
함수는 2개의 정수를 받아서 그 중에서 큰 수를 반환해줍니다. min
함수는 2개의 정수를 받아서 그 중에서 작은 수를 반환해줍니다.
절댓값을 반환하는 함수 만들기
다음 코드를 사용하여 절댓값을 구할 수 있습니다.
코드: function_abs.c
#include <stdio.h>
//[?] 절댓값을 구하는 함수 만들기
int get_abs(int num)
{
return (num < 0) ? -num : num;
}
int main(void)
{
int num = -21;
int abs = get_abs(num);
printf("%d의 절댓값: %d\n", num, abs);
return 0;
}
-21의 절댓값: 21
절댓값 계산 함수 구현하기
C 언어에서 정수의 절댓값을 쉽게 구할 수 있는 간단한 함수를 만드는 방법을 알아보겠습니다. 이 함수는 정수를 매개변수로 받아 해당 정수가 음수인 경우 양수로 변환하여 반환합니다.
코드: function_absolute_value.c
#include <stdio.h>
// 정수의 절댓값을 반환하는 함수
int calculate_absolute_value(int num)
{
// 입력받은 정수가 0 또는 양수이면 그대로 반환, 음수이면 양수로 변환하여 반환
return (num < 0) ? -num : num;
}
int main(void)
{
// 테스트를 위한 정수 값
int num = -21;
// calculate_absolute_value 함수를 사용하여 절댓값 구하기
int abs_value = calculate_absolute_value(num);
// 결과 출력
printf("%d의 절댓값: %d\n", num, abs_value);
return 0;
}
-21의 절댓값: 21
이 예제에서는 C 언어로 정수의 절댓값을 계산하는 간단한 함수를 만들었습니다. 함수 calculate_absolute_value는 하나의 정수 매개변수를 받습니다. 함수 내부에서 삼항 연산자를 사용하여, 입력 값이 음수인지 확인하고 음수라면 양수로 변환하여 반환합니다. 만약 양수거나 0이라면 입력 값 그대로 반환합니다. 메인 함수에서는 -21이라는 값을 변수 num에 저장하고 calculate_absolute_value 함수를 호출하여 절댓값을 구한 뒤, 화면에 출력합니다. 이를 통해 calculate_absolute_value 함수가 제대로 동작하는 것을 확인할 수 있습니다.
19.15 재귀 함수
함수에서 함수 자기 자신을 호출하는 것을 재귀(Recursion) 또는 재귀 함수라고 합니다.
19.15.1 재귀 함수 사용하기
이번에는 재귀 함수를 사용해보겠습니다. 반복문에서 만들어 본 팩토리얼 문제를 재귀 함수를 사용하여 다시 만들어보겠습니다. 재귀 함수 예제는 코드로 이해하기가 어려우니 부록의 "디버거 사용하기"를 참고하여 F10
번 또는 F11
번을 여러 번 눌러가면서 하나씩 코드를 실행해 보는 걸 권장합니다.
코드: recursion_demo.c
// 재귀 함수(Recursion)
#include <stdio.h>
// 3항 연산자를 사용한 factorial 구하기
int fact(int n)
{
return (n > 1) ? n * fact(n - 1) : 1;
}
// 재귀 함수를 사용한 factorial 함수 만들기: 단, 재귀함수는 tree 데이터 구조 탐색에 유리
int factorial(int n)
{
// 종료
if (n == 0 || n == 1)
{
return 1;
}
// 재귀 호출
return n * factorial(n - 1);
}
// 단순한 factorial은 이 방법이 좋음
int factorial_for(int n)
{
int result = 1;
for (int i = 1; i <= n; i++)
{
result *= i; // ((((1 * 1) * 2) * 3) * 4)
}
return result;
}
int main(void)
{
// 재귀 호출을 사용하여 factorial을 구하기: 4! = 4 * 3 * 2 * 1 = 24
printf("%d\n", 4 * 3 * 2 * 1); // 24
printf("%d\n", factorial_for(4)); // 24
printf("%d\n", factorial(4)); // 24
printf("%d\n", fact(4)); // 24
return 0;
}
24
24
24
24
fact
함수와 factorial
함수는 둘 다 함수 내에서 자기 자신을 호출합니다. 이러한 과정을 통해서 숫자 4
를 넘겨주면 4 * 3 * 2 * 1
을 만들어주는 형태로 팩토리얼을 구할 수 있습니다.
재귀 호출은 스택(Stack) 메모리에 저장되는 형태로 실행이 됩니다. 너무 많은 재귀 처리는 스택 오버플로(Stack Overflow) 에러가 발생하기 쉽습니다. 그러기에 많은 양의 데이터 처리를 위한 코드 작성시에는 재귀 호출보다는 반복문 등으로 풀어 쓰는게 훨씬 좋습니다.
19.15.2 재귀 함수를 사용하여 n의 m제곱을 구하는 Power 기능 구현하기
이번에는 재귀를 사용한 2의 n제곱 패턴 구하기 프로그램을 만들어보겠습니다.
코드: RecursionPower.c
// 재귀(Recursion)를 사용한 2 ^ n 승 패턴 구하기
#include <stdio.h>
int MyPower(int num, int cnt)
{
if (cnt == 0)
{
return 1;
}
return num * MyPower(num, --cnt); // 2 * (2 * (1))
}
int main(void)
{
printf("%d\n", MyPower(2, 2)); // 2 * 2 * 1 = 4
return 0;
}
4
MyPower() 함수에 MyPower(2, 2) 형태를 전달하면 2의 2승을 구해줍니다. 또한 MyPower(2, 10) 형태를 전달하면 2를 총 10번 곱해서 2의 10승을 구해줍니다.
19.16 함수 범위(Function Scope), 전역변수와 지역변수
main 함수 밖에서 선언된 변수를 전역 변수(Global Variable)라고 하고 함수 안에서 선언된 변수를 지역 변수(Local Variable)라고 합니다. 이때 동일한 이름으로 변수를 전역 변수와 함수내의 지역 변수로 선언할 수 있는데, 함수 내에서는 함수 범위내에 있는 지역 변수를 사용하고 함수 범위내에 선언된 변수가 없으면 전역 변수 내에 선언된 변수를 사용합니다. 이번에는 함수의 범위를 알아보겠습니다. 코드: FunctionScope.c
// Function Scope: 함수 범위, 전역 변수와 지역 변수
#include <stdio.h>
char* message = "전역 변수";
void ShowMessage()
{
char* message = "지역 변수";
printf("%s\n", message); // 지역 변수
}
int main(void)
{
ShowMessage(); // 지역 변수
printf("%s\n", message); // 전역 변수
return 0;
}
지역 변수
전역 변수
main 함수와 동일한 레벨에 char* message = “전역 변수”; 형태로 문자열 변수를 선언할 수 있습니다. 이렇게 main 함수 밖에서 선언하는 변수는 main 함수와 ShowMessage() 함수에서 모두 사용할 수 있는 전역 변수가 됩니다. 다만, ShowMessage() 함수에서는 동일한 이름의 message 변수를 선언하고 사용하기에 전역 변수가 아닌 함수 내에서 선언된 지역 변수가 사용됩니다. 지금까지 우리가 선언하고 사용해 온 모든 변수는 지역 변수에 해당됩니다.
19.17 main 함수와 명령줄 인수
Visual Studio를 사용하여 C 언어 콘솔 응용 프로그램 프로젝트를 생성하면 main 함수에 문자열 배열이 매개 변수로 포함된 int main(int argc, char *argv[]) 형태로 만들어집니다. main 함수의 매개 변수인 char *argv[]도 문자열 배열인 것을 이제는 알 수 있습니다. argv 배열은 명령 프롬프트로부터 실행 파일명 뒤에 오는 문자열을 배열로 받아서 사용할 수 있는 기능을 제공합니다. 이를 명령줄 인수(Command Line Arguments 또는 Command Line Parameters) 또는 애플리케이션 인수라고 하는데 명령 줄에서 넘어오는 매개 변수를 하나씩 받아서 사용할 수 있습니다. 예를 들어, 도스 명령어 중에서 dir.exe . 처럼 dir.exe 명령어 뒤에 오는 옵션 문자열들을 명령줄 인수라 합니다.
코드: ApplicationArgument.c
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("애플리케이션 인수 개수: %d\n", argc);
printf("애플리케이션 이름: %s\n", argv[0]);
return 0;
}
애플리케이션 인수 개수: 1
애플리케이션 이름: D:\C\C\C\Debug\ApplicationArgument.exe
19.18 명령줄 인수로 문자열 데이터 2개 입력받기
처음으로 main 함수에 매개 변수로 명령줄 인수를 사용해보겠습니다. 지금까지는 main 함수에 아무런 매개 변수를 넣지 않았지만, int main(int argc, char* argv[]) 형태로 매개 변수를 지정하였습니다.
코드: ApplicationArgument.c
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("argc: %d\n", argc);
for (int i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n", i, argv[i]);
}
return 0;
}
이번 예제는 C 드라이브의 C 폴더에 CommandLineArgument 이름으로 C 언어 프로젝트를 생성했다고 가정하고 설명하겠습니다. 코드: CommandLineArgument.c
#include <stdio.h>
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
C:\C\CommandLineArgument>cd debug
C:\C\CommandLineArgument\Debug>CommandLineArgument.exe
CommandLineArgument.exe
C:\C\CommandLineArgument\Debug>CommandLineArgument.exe ABC DEF
CommandLineArgument.exe
ABC
DEF
C:\C\CommandLineArgument\Debug>CommandLineArgument.exe "안 녕" "하세요."
CommandLineArgument.exe
안 녕
하세요.
C:\C\CommandLineArgument\Debug>
코드를 작성 후 Ctrl + F5를 눌러 실행하면 다음 샘플 결과처럼 실행파일명만 출력됩니다. C:\C\CommandLineArgument\Debug\CommandLineArgument.exe
문자열 배열인 argv 배열을 for 문을 사용하여 데이터가 있는만큼 반복해서 문자열을 하나씩 뽑아서 출력하는 구문입니다. 명령줄 인수는 도스 창으로 불리는 명령 프롬프트 또는 터미널에서 실행 파일 뒤에 추가적으로 문자열을 전달할 때 이를 공백을 기준으로 문자열 배열로 받는 역할을 합니다. 만약, 현재 프로젝트를 실행했을 때 실제 실행 파일이 위치하는 경로로 명령 프롬프트로 이동한 후 다음과 같이 CommandLineArgument.exe Hello World를 지정하면 “Hello”와 “World”가 각각 argv[1]와 argv[2]에 저장됩니다. 그리고 argc 를 요청하면 파일명을 포함하여 3개의 요소가 있으므로 3을 반환합니다.
C:\C\CommandLineArgument\Debug>CommandLineArgument.exe Hello World
Hello
World
명령줄 인수는 큰 따옴표를 사용하여 공백을 포함한 문자열을 받을 수 있습니다. 다음과 같이 “안녕 Hello”처럼 입력하면 이 값은 args[0]에 저장됩니다.
C:\C\CommandLineArgument\Debug>CommandLineArgument.exe "안녕 Hello" World
안녕 Hello
World
19.19 Visual Studio 프로젝트 속성에서 명령줄 인수 제공받기
Visual Studio에서는 직접 명령 프롬프트(cmd.exe)로 이동하여 명령줄 인수를 테스트하지 않고 Visual Studio에서 옵션으로 바로 설정할 수 있는 기능을 제공해 줍니다. 3단계에 걸쳐서 Visual Studio에서 명령줄 인수 값을 지정하는 방법을 살펴보겠습니다. (1) 앞서 작성한 코드를 다시 살펴봅니다. 코드: CommandLineArgument.c
#include <stdio.h>
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
(2) Visual Studio에서 CommandLineArgument 프로젝트에 우클릭 버튼을 클릭한 후 속성을 클릭하여 속성 창을 엽니다. 다음 그림과 같이 속성 창이 열리면 디버그 탭을 선택합니다. 다음 그림과 같이 디버깅 탭의 Command Arguments(명령줄 인수) 영역에 안녕하세요 반갑습니다 문자열을 입력합니다.
(3) Visual Studio에서 Ctrl + F5를 눌러 프로젝트를 실행합니다. 프로젝트를 실행하면 argv[1]에 “안녕하세요”가 저장되고 argv[2]에 “반갑습니다”가 저장된 후 for 문에 의해서 argv 배열의 값을 각각 출력합니다.
C:\C\CommandLineArgument\Debug\CommandLineArgument.exe
안녕하세요
반갑습니다
이와 같이 3단계를 거치면 직접 명령 프롬프트로 이동하지 않고도 명령줄 인수를 손쉽게 테스트할 수 있습니다.
지금까지 우리가 사용해 온 main 함수는 매개 변수(파라미터)로 문자열 배열을 받습니다. 이 문자열 배열은 명령 프롬프트에서 C 언어 프로그램 실행시 뒤에다가 특정 문자열을 지정해서 추가적인 기능을 구현하도록 하는데 이 문자열을 받는 기능을 합니다. C 언어에서 명령줄 인수는 char* argv[]로 받습니다. argv는 원하는 이름으로 바꿔서도 무관합니다. 명령 프롬프트에서 C 언어 콘솔 응용 프로그램 실행시 공백을 기준으로 argv[1], args[2], ... 순서로 문자열 값을 받습니다. 또한, argc 매개 변수로 배열의 요소수를 알아낼 수 있습니다. 우리가 [명령줄인수]라는 이름으로 프로그램을 만들었다면 아래와 같이 호출할 수 있습니다. C:\C 언어\명령줄인수 안녕하세요 반갑습니다 또만나요 명령줄 인수에 공백을 기준으로 전달된 값은 다음과 같이 각각의 배열의 요소가 생성되고 초기화 됩니다. args[1] => 안녕하세요 args[2] => 반갑습니다. args[3] => 또만나요
19.20 퀴즈
다음 중 함수의 반환값이 없음을 의미하는 키워드를 고르세요. a. int b. void c. static d. not 정답: b void 키워드는 반환값이 없을 때 사용합니다.
정수형 매개 변수가 2개이고 반환값이 정수형인 함수를 선언할 때 올바른 코드를 고르세요. a. float Add(float a, float b) b. void Add(int a, int b) c. int Add(int b, float b) d. int Add(int a, int b)
정답: d int Add(int a, int b) 형태로 함수를 선언하면 int 형식의 매개 변수가 2개이고 반환값도 int 형식인 함수가 만들어집니다.
19.21 연습문제: 곱셈 함수 만들기
다음 소스 코드를 완성하여 31.40이 출력되게 만드세요. 코드: FunctionPractice.c
//[?] 곱셈 함수 만들기
#include <stdio.h>
// 함수 원형
double Multiply(double a, double b);
int main(void)
{
double result = 0;
result = Multiply(3.14, 10.0);
printf("결과: %.2lf\n", result);
return 0;
}
// 함수 본문
double Multiply(double a, double b)
{
return a * b;
}
31.40
<정답> double Multiply(double a, double b) { return a * b; } </정답> <해설> Multiply() 함수는 매개 변수로 2개의 double 변수를 전달합니다. 그리고 곱셈 기능을 구현해야 하므로 내부적으로는 2개의 변수를 곱한 후 그 결괏값을 double 형식으로 호출한 곳으로 되돌려준 후 result 변수에 저장 후 사용하는 형태입니다. </해설>
19.22 거듭제곱 함수 만들기
코드: power.c
//[?] 거듭제곱 함수 만들기
#include <stdio.h>
int pow(int a, int b)
{
int r = 1; // 1로 초기화
int i = 0;
for (i = 0; i < b; i++)
{
r *= a; // r = r * a;
}
return r; // a ^ b
}
int main(void)
{
int r = 0;
r = pow(2, 10);
printf("2의 10승: %d\n", r); // 1024
r = pow(2, 20);
printf("2의 20승: %d\n", r); // 1048576
return 0;
}
2의 10승: 1024
2의 20승: 1048576
19.23 장 요약
함수는 C 언어 프로그래밍에서 가장 중요한 요소 중 하나입니다. 그러다보니, 이번 강의는 내용이 많았는데요. 앞으로 이번 장의 내용은 계속해서 반복해서 나올 예정입니다. 함수를 사용하여 반복되는 코드와 중복되는 코드를 줄여 효율성을 높일 수 있습니다.