C언어 4일차-2

정혜창·2024년 12월 16일

독학

목록 보기
11/28
post-thumbnail

아래의 내용은 혼자 공부하는 C언어 -서현우(개정판, 2023) 을 토대로 공부한 내용입니다.

함수

  • 여러가지 함수 유형

함수 원형은 반환형 함수명(매개변수)로 이루어진다고 배웠다. 하지만 언제나 함수에 반환형과 매개변수가 있는 것은 아니다. 단순히 키보드 입력값을 확인하고 양수를 반환하는 함수라면 매개변수가 필요없다. 혹은 화면을 위아래로 나눠 주는 줄(----)을 여러 개 출력한다고 생각해보자. 이때는 굳이 반환형을 고민할 필요가 없다.


1. 매개변수가 없는 함수

우선 매개변수가 없는 함수를 살펴보자. 앞서 예로 들었던 키보드로 수를 입력하면 양수를 반환하는 함수를 만든다고 할 때 호출한 함수로부터 값을 받을 필요가 없으므로 매개변수도 필요 없다. 이때 함수의 매개변수 자리에는 void를 사용한다.

  • 매개변수가 없는 함수 (예제)
#include <stdio.h>

int get_num(void);					// 함수 선언

int main(void)
{
	int result;
    
    result = get_num();				// 함수 호출, 반환값은 result에 저장
    printf("반환값 : %d\n", result); // 반환값 출력
    
    return 0;
}

int get_num(void)					// 매개변수가 없고 반환명만 있다.
{
	int num;						// 키보드 입력값을 저장할 변수
    
    printf("양수 입력 : ");			// 입력 안내 메시지
    scanf_s("%d", &num);				// 키보드 입력
    
    return num;						// 입력 값 반환
}

메인 함수가 끝나고 나온 행이 함수 원형이다

int get_num(void)			// 매개변수가 없고 반환형만 있다.

괄호 안에 void를 넣어 매개변수가 없음을 표시한다. 괄호만 사용해도 매개변수가 없다는 사실을 표시할 수 있지만, void를 넣어 매개변수가 없음을 명시적으로 표현하는 것이 좋다. get_num 함수는 매개변수가 필요 없지만, 키보드로 입력받은 값을 호출한 함수로 반환하므로 반환형(int)은 있어야 한다. 따라서 반환하는 문장(return num;)도 필요하다.

호출하는 문장을 살펴보자

result = get_num();

get_num 함수는 매개변수가 없다. 당연히 호출할 때 인수가 없다. 그런데 왜 get_num, get_num(void)로 작성하지 않는걸까? void는 함수 정의나 선언에서 사용되며 호출할 때는 쓰지 않는다. 따라서 그냥 괄호만 쓴다. 괄호조차 없다면 함수를 호출하는 문장이 아닌 그냥 함수의 이름으로만 인식하므로 반드시 괄호는 사용해야 한다.


2. 반환값이 없는 함수

함수는 기능에 따라 형태가 결정된다. 데이터를 받아서 단지 화면에 출력하는 함수라면 반환값이 필요없다.

  • 반환값이 없는 함수 (예제)
#include <stdio.h>

void print_char(char ch, int count);	// 함수 선언

int main(void)
{
	print_char('@', 5);					// 문자와 숫자를 주고 함수 호출
    
    return 0;
}

void print_char(char ch, int count)		// 매개변수는 있으나 반환형 없다
{
	int i;
    
    for (i = 0; i < count; i++)			// i는 0 ~ count-1 까지 증가
    {									// count번 반복
    	printf("%c", ch);				// 매개변수 ch에 받은 문자 출력
    }
    
    return;
}

여기서의 함수원형은 마찬가지로 main함수 뒤에 나오는 문장이다.

void print_char(char ch, int count)

문자와 숫자를 받아야 하므로 매개변수는 있지만 반환형은 없기때문에 void를 사용한다.
도한 반환값이 없으므로 return문은 값 없이 단독으로 사용한다.

return;

return의 역할이 값을 돌려주는 일인데, 돌려줄 값이 없으므로 자연스럽게 혼자 쓰인다. 심지어 return문 자체를 생략하는 것도 가능하다. return문은 함수 마지막 뿐만이 아니라 함수 어디서든 사용될 수 있으며 실행 중간에 돌아간다면 함수 중간에 return을 사용하여 함수를 끝낼 수도 있다.


3. 매개변수와 반환값이 모두 없는 함수

매개변수와 반환값이 모두 없는 함수도 있다. 예를 들어 일정한 문자열을 여러 번 출력하는 함수라면 매개변수와 반환값이 모두 필요없다. 이때는 함수의 매개변수와 반환형에 모두 void를 쓴다

  • 반환값과 매개변수가 모두 없는 함수 (예제)
#include <stdio.h>

void print_line(void);			// 함수 선언

int main(void)
{
	print_line();				// 함수 호출
    printf("학번		이름		전공		학점\n");
    print_line();				// 함수 호출
    
    return 0;
}

void print_line(void)
{
	int i;
    
    for(i = 0; i < 55; i++)		// 55번 반복해서 '-'출력
    {
    	printf("-");
    }
    printf("\n");
    return;						// return문 없이 해도됌.
}

4. 재귀호출 함수

함수는 보통 다른 함수를 호출하는데 재귀호출 함수(recursive call function)는 자기 자신을 호출한다. 간단하게 apple을 출력하는 재귀호출 함수를 살펴보자

  • 재귀호출 함수 (예제)
#include <stdio.h>

void fruit(void);

int main(void)
{
	fruit();
    
    return 0;
}

void fruit(void)
{
	printf("apple\n");
    fruit();
}

이 코드는 정의 함수 정의에서 계속해서 자기의 함수를 호출하므로 영원히 'apple'이 반복해서 출력되는 결과가 나온다. 결국 메모리를 모두 사용하게 되면서 메모리 부족을 강제 종료된다. 이처럼 중간에 종료되는 건 정상적인 종료가 아니다. 따라서 정상적으로 종료하기 위해 반복 고리를 끊을 수 있는 조건식을 반드시 포함해야 한다. 세 번만 호출되도록 수정해보자.

  • 세 번 실행되는 재귀호출 함수 (예제)
#include <stdio.h>

void fruit(int count);

int main(void)
{
	fruit(1);				// 처음 호출 하므로 1을 인수로 준다.
    
    return 0;
}

void fruit(int count)		// 호출 횟수를 매개변수에 저장
{
	printf("apple\n");
    if (count == 3) return;		// 호출 횟수가 3번이면 반환하고 끝낸다
    fruit(count + 1);			// 재호출할 때 호출 횟수 1증가
}

5. 재귀호출과 반복문의 차이점

여기서 '재귀호출 대신 그냥 반복문을 사용해도 되지 않을까?' 라는 의구심이 든다. 이번엔 재귀호출과 반복문의 차이를 알아보자. 다음은 위의 예제에서 한 줄만 새로 추가한 코드이다.

  • 세 번 실행되는 재귀호출 함수 2 (예제)
#include <stdio.h>

void fruit(int count);

int main(void)
{
	fruit(1);				// 처음 호출 하므로 1을 인수로 준다.
    
    return 0;
}

void fruit(int count)		// 호출 횟수를 매개변수에 저장
{
	printf("apple\n");
    if (count == 3) return;		// 호출 횟수가 3번이면 반환하고 끝낸다
    fruit(count + 1);			// 재호출할 때 호출 횟수 1증가
    printf("jam\n");			//<--- 새로 추가한 코드
}

if문 옆에 있는 return문이 최초 호출한 main 함수로 돌아간다면 printf("jam\n");은 절대 실행되지 않을 것이다. 그러나 예상과 달리 실행결과는 jam이 두번이나 출력이 된다.
재귀호출 함수의 경우 최초 호출한 곳이 아니라 이전에 호출했던 곳으로 돌아간다.

결국 재귀호출은 하나의 함수에서 코드를 반복 실해하는 듯하지만, 실제로는 새로운 함수를 실행하는 것과 같다. 재귀호출 함수는 경우에 따라 복잡한 반복문을 간단히 표현할 수 있으나 코드 읽기가 쉽지 않고 반복 호출되면서 메모리를 사용하므로 제한적으로 쓰는 것이 좋다.

profile
Unreal 1기

0개의 댓글