6강 · 제5장 · 137~152쪽 · 약 70분

함수와 기억 클래스(1)

함수의 개념·표준함수·사용자 정의 함수(정의·원형·호출·return)와 값에 의한 전달을 교재 예제 5-1~5-7로 익힙니다. (교재 제5장 137~152쪽)

학습 목표

  • 함수가 모듈이며 C 프로그램은 함수의 호출로 실행됨을 설명한다
  • 표준함수와 사용자 정의 함수를 구분하고, 헤더(#include)와 라이브러리(링크)의 역할을 말한다
  • 함수 헤더·몸체·원형·호출·return의 형식과 위치를 쓴다
  • 실매개변수와 형식매개변수를 구분하고, 값에 의한 전달에서 원본이 바뀌지 않는 이유를 설명한다
  • 교재 예제 5-1~5-7을 실행하고 인자를 바꿔 결과를 예측한다

왜 이 강이 필요한가?

1~5강은 거의 모든 일을 main 안에 적었습니다. 프로그램이 커지면 그 한 덩어리는 읽고 고치기 어려워집니다.
C는 일을 함수로 쪼개 두고, 필요할 때 호출하는 구조적 프로그래밍 언어입니다.

이 강은 교재 제5장(함수와 기억 클래스) 의 137~152쪽이며, LMS 강의내용 순서와 같습니다.

  1. 함수의 개념 — 모듈, 독립성, main의 역할
  2. 표준함수 — 헤더·라이브러리, math.h·string.h·ctype.h (예제 5-1, 5-2)
  3. 사용자 정의 함수 — 정의·원형·호출·return, 값에 의한 전달 (예제 5-3~5-7)

지역·전역 변수와 기억 클래스(auto/static/extern/register)는 7강입니다.

본문의 C 예제는 코드 아래에 실행 칸이 붙습니다. scanf가 필요한 예제는 같은 변환 명세를 쓰는 sscanf로 교재 입력값을 보여 줍니다. 진짜 키보드는 맨 아래 종합 실습의 「표준 입력」 칸이나 상단 「코드연습」 에서 연습하세요.

사이트 표기는 1강과 같이 int main(void) 입니다. 교재의 void main()·#pragma warning은 Visual C++ 기준입니다.


1. 함수의 개념

함수는 수학의 함수처럼, 특정 작업(기능)을 수행하도록 설계된 독립적인 프로그램입니다.
C 프로그램은 이런 함수들이 모여 만들어지고, 정해진 순서대로 호출되며 실행됩니다.

큰 일을 몇 개의 모듈(module) 로 나누고, 모듈마다 함수를 작성한 뒤 호출하는 식이 기본입니다.

모듈로 나눈 함수의 장점

  • 프로그램 수정이 쉽다
  • 재사용으로 코드 중복을 줄인다
  • 기능이 한눈에 보여 유지 관리가 쉽다

C의 함수는 모두 동등합니다. main이 다른 함수를 부를 수 있고, 사용자 함수끼리도 부를 수 있으며, 자기 자신을 부를 수도 있습니다(재귀 — 제5장 후반·예제 프로그램).
또 함수는 서로 독립입니다. 어떤 함수를 호출한다는 것은 실행을 그쪽으로 잠시 옮긴다는 뜻이지, 호출한 쪽의 안쪽 처리를 마음대로 건드린다는 뜻이 아닙니다.

C에서 쓰는 함수는 크게 둘입니다.

종류의미예
표준함수언어(구현)가 미리 제공하는 함수printf, scanf, sqrt, strlen
사용자 정의 함수프로그래머가 직접 정의하는 함수sum, max, swap

모듈은 프로그램의 한 조각입니다. 함수 하나일 수도, 여러 함수와 변수의 묶음일 수도, 파일 하나일 수도 있습니다. 핵심은 한 기능을 가진 독립 단위라는 점입니다. 모듈을 연결해 하나의 프로그램을 만드는 방식을 모듈화 프로그래밍이라고 합니다.

main의 역할을 다시 생각해 보세요. C 프로그램에는 main이 반드시 하나 있습니다. 실행은 항상 main에서 시작합니다. 표준함수·사용자 함수는 main(또는 다른 함수)이 불러 주어야 돌아갑니다. 5.3절에서 형식을 자세히 봅니다.


2. 표준함수

언어가 자체적으로 제공하는 함수를 표준함수라고 하며, 표준 라이브러리에 실려 있습니다. 수는 매우 많습니다.

  • 원형(prototype) — 헤더 파일(.h)에 선언
  • 실체(구현) — 라이브러리 파일에 수록되고, 링크 때 프로그램에 결합 (1강 복습)

그래서 표준함수를 쓰려면 원형이 있는 헤더를 #include 해야 합니다. 예: sqrt의 원형은 <math.h>.

헤더들어 있는 함수(대표)
stdio.h입출력 printf, scanf, getchar, putchar / 파일 fopen, fclose, …
string.h문자열 strlen, strcpy, strcmp, strcat, …
math.h수학 sqrt, sin, cos, pow, ceil, floor, exp, …
ctype.h문자 판별 isalpha, isdigit / 변환 tolower, toupper
stdlib.h변환 atoi / 난수 rand, srand / 정수 절댓값 abs

교재 표의 conio.h(getch 등)는 MS-DOS/Windows 콘솔용이라 맥·이 사이트 실행기에는 없습니다.
교재는 abs()를 math.h 쪽에 묶어 두었지만, 정수 abs는 stdlib.h, 실수 절댓값은 fabs(math.h)입니다. 아래 예제 5-1은 둘 다 include 합니다.

2.1 예제 5-1 — 수학 표준함수

ceil(x)는 x 이상의 최소 정수, floor(x)는 x 이하의 최대 정수(교재 표현: x 미만의 최대 정수에 해당하는 값으로 12.34 → 12).
pow(x, y)는 x의 y제곱, abs(x)는 절댓값입니다.
ceil·floor·pow의 반환형은 double이라, 교재처럼 int 변수에 넣을 때 여기서는 (int)로 잘랐습니다.

이 예제 실행

실행 결과가 여기에 표시됩니다.

교재 실행 결과: abs(-5) = 5, ceil(12.34) = 13, cos(10) ≈ -0.839, exp(2) = 7, floor(12.34) = 12, sqrt(2) ≈ 1.414, pow(4,2) = 16.
j를 3으로 바꾸면 pow와 sqrt가 어떻게 바뀌는지 실행해 보세요.

2.2 예제 5-2 — 문자열·문자 판별

strlen(s)는 널을 제외한 길이, isalpha는 영문자, isdigit는 십진 숫자인지 봅니다. 교재 입력 KNOU1234567890-#*?$ → 알파벳 4, 숫자 10, 기타 5.

이 예제 실행

실행 결과가 여기에 표시됩니다.

isalpha/isdigit에 (unsigned char)를 씌운 것은, char가 음수일 수 있어 표준이 그렇게 쓰라고 권하기 때문입니다. 교재 코드에는 없습니다.


3. 사용자 정의 함수

main 안에 표준함수만 나열하면, 블록이 길어질수록 읽고 고치기 어렵습니다. 짧은 단위 프로그램으로 나누어 함수를 정의하는 것이 사용자 정의 함수입니다.

3.1 함수의 정의

함수가 하는 일을 적은 코드가 정의입니다.

반환자료형  함수명(자료형 매개변수1, 자료형 매개변수2, …)   ← 함수 헤더
{
    /* 지역 변수 선언과 실행 문장 */                    ← 함수 몸체
}

반환 자료형

  • 호출한 쪽으로 되돌려 줄 값의 형
  • 생략하면 옛 규칙에서 int로 간주 (지금은 반드시 적을 것)
  • 돌려줄 값이 없으면 void (생략 불가)

함수명 — 변수 이름 규칙과 같습니다. 하는 일이 보이게 짓습니다.

매개변수

  • 호출한 쪽과 불린 쪽 사이에 자료를 주고받기 위한 변수. 함수 안에서는 보통 변수처럼 씁니다.
  • 여러 개면 콤마(,)로 구분합니다.
  • 없으면 void — 이 사이트는 int main(void), void test(void)처럼 적습니다. 교재는 ()와 (void)를 같다고 하지만, 현대 C에서 빈 ()는 “인자 미지정”에 가깝습니다.

몸체는 중괄호로 시작하고 끝납니다. 그 안에 이 함수만의 지역 변수와 문장을 둡니다.

사용자 함수 정의 예 (sum). 실행하면 10 + 20 = 30이 나옵니다.

이 예제 실행

실행 결과가 여기에 표시됩니다.

main을 int로 두면 return 0;이 정상 종료를 운영체제에 알리는 관례입니다. 교재처럼 void main()이면 반환값이 없습니다.

3.2 원형 · 호출 · 정의의 위치

함수를 쓰려면 보통 세 조각이 필요합니다.

  1. 원형 선언 — 컴파일러에게 “이런 모양의 함수가 있다”고 미리 알림
  2. 호출 — 이름과 인자를 적어 실행을 넘김
  3. 정의 — 실제 몸체

이 예제 실행

실행 결과가 여기에 표시됩니다.

호출하면 제어가 그 함수로 이동하고, 함수가 끝나면 호출한 다음 문장으로 돌아옵니다.

3.3 함수의 원형 선언

변수와 같이 함수도 쓰기 전에 선언되어야 합니다. 컴파일러는 호출 모양과 헤더를 비교합니다.

  • 인자 개수가 매개변수와 다르면 오류
  • 자료형이 다르면 형변환을 시도하거나 오류

main을 파일 앞쪽에 두거나 여러 파일로 나누면, 호출 시점에 정의가 아직 없을 수 있습니다. 그때 원형이 필요합니다. 형식은 정의의 헤더 뒤에 세미콜론(;) 입니다. 원형에서 매개변수 이름은 있어도 되고 없어도 되고, 달라도 됩니다.

int sum(int, int);
int sum(int a, int b);
int sum(int x, int y);

위 셋은 같은 원형입니다. 보통 main 앞에 둡니다.

교재 5-3 — 정의가 main보다 앞이면 원형이 없어도 됩니다.

이 예제 실행

실행 결과가 여기에 표시됩니다.

교재 5-4 — 정의가 main 뒤이면 원형이 필요합니다. 실행 결과는 5-3과 같이 sum = 30.

이 예제 실행

실행 결과가 여기에 표시됩니다.

입문에서는 원형을 위에 두고 정의는 main 아래에 모으는 습관을 권합니다.

3.4 함수의 호출과 return

함수는 부프로그램이라 누가 부르지 않으면 실행되지 않습니다. 호출은 함수명과 넘길 값을 적는 것입니다.

(1) 매개변수

이름어디에 있나무엇
실매개변수(argument)호출하는 쪽넘기는 값. 상수·변수·수식
형식매개변수(parameter)정의(헤더)받아서 쓰는 변수. 자료형 + 이름

자료형과 개수가 일치해야 합니다. 형이 다르면 형변환, 개수가 다르면 컴파일 오류인 경우가 많습니다.

(2) return

  • 형식: return 수식; 또는 return (수식);
  • 기능: 함수를 끝내고, 결과와 제어를 호출한 쪽으로 넘깁니다.
  • 함수 안 여러 곳에 둘 수 있고, 하나라도 실행되면 그 함수는 종료입니다.
  • 반환값의 형과 함수의 반환형은 맞추세요.
  • void이면 return; 이거나 생략합니다.

예: return 0;, return x;, return (x + y * z);, return sum(10, 20);

교재 5-5 — max/min과 return (입력 2020 2022):

이 예제 실행

실행 결과가 여기에 표시됩니다.

max 안에서 return이 실행되는 순간 함수가 끝나고, 그 값이 printf의 인자가 됩니다.

교재 5-6 — 호출만 하기 / 결과를 변수에 담기 / 식 안에서 바로 쓰기:

이 예제 실행

실행 결과가 여기에 표시됩니다.

실행 결과: 안내 문장, sum from 30 to 40 = 385, sum from 100 to 200 = 15150.
sum(10, 20)의 반환값을 쓰지 않으면 계산은 하지만 화면에 안 나옵니다.

3.5 값에 의한 자료 전달 (call by value)

호출할 때와 돌아올 때, 실매개변수와 형식매개변수 사이에 자료가 어떻게 오가는지가 중요합니다. 방법은 둘입니다.

방법무엇이 넘어가나함수가 끝나면
값에 의한 전달 (call by value)값의 복사형식매개변수를 바꿔도 실매개변수(원본)는 그대로
참조에 의한 전달 (call by reference)주소같은 기억 장소를 가리키므로 원본도 바뀔 수 있음

C의 기본은 값에 의한 전달입니다. 값은 여러 개 넘길 수 있지만, 복사본을 바꿔도 원본은 돌아오지 않습니다. 돌려받는 값은 보통 return 하나입니다.

교재 5-7 — swap이 호출한 쪽의 a, b를 바꾸지 못하는 이유:

이 예제 실행

실행 결과가 여기에 표시됩니다.

실행 결과: 호출 전 3, 5 → 함수 안 5, 3 → 호출 후 다시 3, 5.
x, y는 a, b와 다른 기억 공간입니다. 복사를 바꾼 것뿐입니다.

주소를 넘기면 원본을 바꿀 수 있습니다(scanf가 &변수를 받는 이유, 3강). 형식은 포인터(*)이고 8~9강에서 본격적으로 다룹니다. 교재 5-8은 7강 이후 복습해도 됩니다.


4. 지금 실습할 것

아래는 5-5·5-6·5-7을 한 파일에 모은 종합 실습입니다. 「표준 입력」에 두 정수를 넣고 실행하세요. 예: 2020 2022 또는 30 40.

  1. 그대로 실행해 max/min/sum_range 확인
  2. 입력 순서를 바꿔 max·min이 따라가는지 보기
  3. sum_range(10, 20)처럼 호출만 하고 결과를 안 담으면 출력이 없음을 본문과 맞추기
  4. swap 전후 값이 같은 이유를 값에 의한 전달로 설명
  5. (선택) sum_range의 for를 while로 바꿔 보기 (5강)

코드 실습 (C)

실행 결과가 여기에 표시됩니다.

확인 퀴즈

1. C에서 사용하는 함수를 크게 둘로 나누면?
2. sqrt()의 원형이 선언된 헤더로 바른 것은?
3. 함수 원형 선언이 하는 일은?
4. 원형 선언이 없어도 되는 경우는?
5. return문의 역할로 바른 것은?
6. int sum(int a, int b)를 sum(10, 20)으로 호출할 때 10과 20은?
7. 예제 5-7처럼 swap(a, b)를 값으로 호출한 뒤 a, b는?
8. void형 함수에서 값을 돌려줄 필요가 없을 때 return은?
9. 예제 5-6에서 sum(10, 20); 만 호출하고 반환값을 쓰지 않으면?
10. 정수 절댓값 함수 abs()를 쓰려면 포함하는 헤더로 가장 알맞은 것은?

스스로 점검