argument/parameter, 리턴값

함수
특정한 작업을 하도록 만들어진 독립적인 단위 모듈
큰 프로그램 하나를 여러 개의 함수로 분할하여 구현하는 구조적 프로그래밍(structured programming) 방식의 기본
전달인자(argument) : 함수에 입력되는 것
매개변수, 파라미터 (parameter) : 받은 전달인자
반환값, 리턴값(return value) : 함수에서 출력되는 것
C 프로그램의 기본 틀
콘솔 기반 C 프로그램은 main() 함수로 시작
- main()함수는 콘솔 기반 C 프로그램의 시작점(entry point)
- 하나의 프로그램에 반드시 하나 존재
리턴값이 없는 함수나 매개변수가 없는 함수는 그 위치에 비어 있다는 뜻의 "void"를 씀
매개변수 리스트에 쓰는 "void"는 생략할 수 있지만 리턴형에 쓰는 "void"는 생략 불가
리턴값 없음 : 상수 앞 void
매개변수 없음 : 괄호 안 void
| int main(void) { 코드 작성 return 0; } |
리턴형 함수이름(매개변수 리스트) { // 함수의 시작 코드 작성 0을 리턴함. 문장 끝에는 “ ;”을 씀 } // 함수의 끝 |
함수의 입력과 출력
입력
- 매개변수(parameter), argument
출력
- 반환값(return value), 리턴값
- 함수가 돌려주는 결과 값
void
- 리턴값이 없으면 리턴형 쓰는 자리에 void
- 매개변수가 없으면 매개변수 쓰는 자리에 void
- 이 경우는 생략 가능하지만 C언어에서는 생략하지 않는 것이 좋음
- C++에서는 일반적으로 생략
C 표준 라이브러리 함수
| 분류 | 예 |
| 입출력 함수 | printf, scanf, puts, gets_s, putchar, getchar |
| 문자열 함수 | atoi, strcmp, strcpy, strlen, strcat |
| 문자 함수 | isalnum, isalpha, iscntrl, tolower, toupper |
| 수학 함수 | sin, cos, tan, abs, pow, log, sqrt |
| 날짜와 시간 관련 함수 | asctime, clock, difftime, localtime, time |
| 메모리 관련 함수 | calloc, free, malloc, realloc |
| 유틸리티 함수 | exit, qsort, rand, srand, system |
C11부터 buffer overflow 문제로 gets 함수가 삭제되고 버퍼의 크기를 설정하는 gets_s 함수가 추가됨. GCC와 Clang은 gets_s 함수를 아직 제공하지 않음
입출력 함수
| 함수명 | 기능 |
| fclose | 파일을 닫음 |
| feof | 파일의 끝인지 검출 |
| ferror | 파일의 읽기, 쓰기에서 에러가 있었는지 확인 |
| fflush | 스트림에 할당되어 있는 버퍼 삭제 |
| fgetc | 스트림으로부터 한 문자를 읽어옴 |
| fgetpos | 스트림의 현재 파일 포인터를 조사 |
| fgets | 스트림으로부터 문자열을 읽어옴 |
| fopen | 파일을 연다 |
| fprintf | 스트림으로 서식화된 출력 |
| fputc | 스트림에 한 문자 출력 |
| fputs | 문자열을 스트림으로 출력 |
| fread | 파일로부터 읽어옴 |
| freopen | 개방되어 있는 스트림을 다른 이름으로 대체 |
| fscanf | 파일로부터 서식화된 입력 |
| fseek | 파일 포인터 새롭게 설정 |
| fsetpos | 현재의 파일 포인터 새롭게 설정 |
| ftell | 현재 파일 포인터 조사 |
| fwrite | 스트림으로 출력 |
| getc | 스트림으로부터 문자 하나를 읽음 |
| getchar | 키보드에서 문자 하나를 읽어옴 |
| gets_s | 키보드에서 하나의 문자열을 읽어옴 |
| perror | 시스템 에러 메시지를 화면에 출력 |
| printf | 화면에 서식화된 출력 |
| putc | 스트림에 문자 하나를 출력 |
| putchar | 화면에 문자 하나를 출력 |
| puts | 화면에 문자열 출력 |
| remove | 파일 삭제 |
| rename | 파일 이름 바꿈 |
| rewind | 파일의 시작점으로 파일 포인터 이동 |
| scanf | 키보드로부터 서식화된 입력을 받음 |
| sprintf | 화면이 아닌 문자열 형태로 서식화된 출력 |
| sscanf | 키보드가 아닌 문자열에서 서식화된 입력을 받음 |
문자열 함수
| 함수명 | 기능 |
| atof | 문자열을 double형으로 바꿈 |
| atoi | 문자열을 integer형으로 바꿈 |
| atol | 문자열을 long형으로 바꿈 |
| memchr | 특정 문자가 최초로 발생된 번지를 찾음 |
| memcmp | 두 개의 메모리 블럭 비교 |
| memcpy | 메모리끼리 복사 - 직접 카피 |
| memmove | 메모리끼리 복사 - 임시 저장 후 카피 |
| memset | 특정 메모리를 문자로 채움 |
| strcat | 두 문자열을 연결 |
| strchr | 문자열 내에 특정 문자가 있는지 검사 |
| strcmp | 두 개의 문자열 대소 비교 |
| strcoll | setlocale함수에 지정된 비교 방식으로두 개의 문자열 비교 |
| strcpy | 문자열을 복사 |
| strcspn | 문자열에 특정 문자열이 들어있지 않은 문자들이 연속한 길이 |
| strerror | 에러 코드의 텍스트 버전 생성 |
| strncat | 문자열끼리 지정한 길이만큼 덧붙임 |
| strncmp | 문자열의 대소 비교 |
| strncpy | 문자열을 정해진 길이만큼 복사 |
| strpbrk | 하나의 문자열 내의 문자가 다른 문자열에 하나라도 있는지 |
| strrchr | 문자열 내에 특정 문자가 있는지 뒤부터 조사 |
| strspn | 문자열 중에서 다른 문자열에 있는 문자들이 연속해있는 길이 |
| strstr | 문자열 내에 다른 문자열이 포함되어 있는지 검사 |
| strtod | 문자열을 double형으로 바꿈 |
| strtok | 문자열에서 token을 찾아냄 |
| strtol | 문자열을 long형으로 바꿈 |
| strtoul | 문자열을 unsigned long형으로 바꿈 |
수학 함수
| 함수명 | 기능 |
| abs | 절대값 |
| acos | 코사인 함수의 역함수 |
| asin | 사인 함수의 역함수 |
| atan | 탄젠트 함수의 역함수 |
| atan2 | atan과 같은데 더 정확함 |
| ceil | double형 변수 x보다 큰 최초의 정수 |
| cos | 코사인 함수 |
| cosh | 쌍곡선 코사인 함수 |
| div | 두 정수를 나누어 몫과 나머지를 구조체로 리턴 |
| exp | 지수 함수 |
| fabs | 부동 소수점의 절대값 |
| floor | double형 변수 x보다 작은 최초의 정수 |
| fmod | 실수를 다른 실수로 나눈 나머지 |
| labs | long형 정수의 절대값 |
| log | 자연 로그 |
| log10 | 상용 로그 |
| modf | 실수를 분해하여 실수부와 정수부로 나눔 |
| pow | x의 y승 |
| sin | 사인 함수 |
| sinh | 쌍곡선 사인 함수 |
| sqrt | 제곱근 |
| tan | 탄젠트 함수 |
| tanh | 쌍곡선 탄젠트 함수 |
날짜, 시간 함수
| 함수명 | 기능 |
| asctime | 구조체에 저장된 시간, 날짜를 문자열로 바꿈 |
| clock | 프로그램이 시작된 후 경과된 clock tick |
| ctime | 시간과 날짜를 문자열로 바꿈 |
| difftime | 두 시간의 차이를 초 단위로 계산 |
| gmtime | GMT 표준 시간으로 바꿈 |
| localtime | time함수에 의해 구해진 시간을 tm구조체에 저장 |
| time | 시스템의 현재시간 조사 |
메모리 관련 함수
| 함수 | 기능 |
| calloc | 0으로 초기화 하면서 동적으로 메모리 할당 |
| free | 동적으로 할당된 메모리 해제 |
| malloc | 동적으로 메모리 할당 |
| realloc | 할당된 메모리의 크기를 변경 |
유틸리티 함수
| 함수 | 기능 |
| abort | 프로그램을 비정상적으로 종료 |
| assert | 논리식이나 정수 값이 거짓이면 프로그램 종료 |
| atexit | 종료 처리 함수 등록 |
| bsearch | 이진 탐색 수행 |
| exit | 프로그램을 정상적으로 종료 |
| getenv | 환경변수를 조사해 문자열로 저장 |
| qsort | quick sort 수행 |
| raise | 프로그램에 신호를 강제적으로 보냄 |
| rand | 난수 발생 |
| signal | 예외 상황이나 raise함수가 호출될 때 프로그램으로 보내지는 신호 |
| srand | 난수 발생기를 초기화 |
| system | DOS명령 수행 |
사용자 정의 함수
직접 만드는 함수
함수명
동사, 모두 소문자와 단어 사이 언더스코어(_)
- add(), add_number(), delete_name(), check_for_errors(), dump_data_to_file()
동사, 의미가 바뀌는 부분은 대문자, 나머지는 소문자(lower camel case)\
- add(), addNumber(), deleteName()
동사, 첫 글자와 의미가 바뀌는 부분은 대문자, 나머지는 소문자(upper camel case)
- AddNumber(), DeleteName()
함수 정의, 호출, 선언
함수 정의
- 함수 만들기
- 이름, 매개변수, 리턴형, 기능
void display(void)
{
printf("안녕");
}
함수 호출
- 함수 사용하기
- 이름, 매개변수
display();
함수 선언
- 함수의 사용법
- 이름, 매개변수, 리턴형
- 컴파일러에게 함수에 대한 정보를 미리 줌
- 함수 정의의 첫번째 줄을 세미콜론으로 끝나는 문장으로 만듦
void display(void);
return문
결과 값을 호출한 함수로 반환
return문을 만나면 함수의 나머지 부분에 상관없이 함수의 실행을 종료하고 호출한 함수로 넘어감
- return(수식이나 값);
- return 다음에 괄호는 생략해도 됨
- return 1;
- return x;
- return (x*2);
- return (x+y);
함수 호출(call)
함수를 만드는 것을 함수를 정의(definition) 한다고 함
함수를 만든(정의) 후 함수를 사용(호출)
함수를 호출할 때는 함수 이름과 괄호 안에 argument를 개수만큼 써야 함
argument가 없을 때는 빈 괄호만 쓰면 됨
- display();
- double_number(3);
- add(2, 3);
- vending(1);
함수의 정의와 선언(원형, prototype)
덧셈기 함수의 정의(구현)
int add(int x, int y) // 함수의 머리(header)
{ // 함수의 본체 시작
return (x+y); // 함수의 본체(body)
} // 함수의 본체 끝
함수의 머리 부분을 다음과 같이 하나의 문장 (세미콜론으로 끝남)으로 만드는 것을 함수 선언 또는 함수 원형(prototype)이라 함
- int add(int x, int y);
- int add(int, int);
- 매개변수 x와 y는 생략할 수 있지만 생략하지 않는 것이 더 좋음
함수 선언이 귀찮다면?
함수 선언문을 한 줄 작성하는 것이 귀찮다면 view()함수의 정의를 main()함수 전에 하면 됨
함수 정의는 선언을 겸하고 있으므로 따로 선언할 필요가 없음
이 방법은 함수들끼리 호출하는 상황에서는 오류를 발생시킬 수 있으므로 권장하지 않음
#include <stdio.h>
void view(void) //함수 정의
{
printf("view함수\n");
}
int main(void)
{
printf("메인 함수 : view호출 전\n");
view(); //함수 호출
printf("메인 함수 : view호출 후\n");
return 0;
}
main()함수의 리턴 값
return문을 만나면 함수의 나머지 부분에 상관없이 함수의 실행을 종료하고 호출한 함수로 넘어감
main()함수의 경우 return문을 만나면 프로그램이 끝남
return문은 하나의 값만 되돌려줌
- 포인터를 사용해야 둘 이상의 값을 return할 수 있음
지금까지 예제에서 main()함수의 리턴 값은 0
main()함수의 리턴 값은 프로그램이 끝나면서 OS에 전달되는 값
- 프로그램이 정상적으로 종료되면 보통 0을 리턴
- 비정상적으로 종료할 때는 1을 리턴하는 것이 관례
stdlib.h 파일을 보면 다음과 같이 정의되어 있음
- #define EXIT_SUCCESS 0
- #define EXIT_FAILURE 1
재귀(recursive) 함수
함수가 함수 내에서 자기 자신을 호출 할 수 있는데 이것을 재귀 호출(recursive call)
재귀 호출을 허용하는 함수를 재귀 함수(recursive function)
구현하고자 하는 작업이 함수 자신을 순환 반복하여 구현되어질 수 있다면 재귀 함수를 이용할 수 있음
재귀 함수는 재귀적 특성의 알고리즘에서 쉬운 문제 해결 방법 제공
함수의 반복 호출로 인한 시간과 메모리 공간의 효율성이 떨어지는 단점
- 스택 오버플로우(stack overflow)에 주의
재귀 함수는 반복문을 이용한 함수로 변환이 가능
피보나치 수열, 하노이탑 문제, 이진 트리 순회(binary tree traversal), 프랙탈 곡선(fractal curve), 이항 계수(binominal coefficient) 등에 사용
매개변수를 전달하는 방법
C 언어에서는 기본적으로 값에 의한 호출(call by value)
실매개변수의 값을 형식매개변수로 전달
- 실매개변수를 형식매개변수로 전달할 뿐 함수 내부에서 형식매개변수가 변경되더라도 실매개변수는 변경되지 않음
형식매개변수가 변하면 실매개변수도 변하게 하려면 포인터를 이용하여 call by address로 구현해야 함
| 값에 의한 호출 (call by value) | 주소에 의한 호출 (call by address) |
| 실매개변수의 값을 형식매개변수로 전달 | 실매개변수의 주소를 형식매개변수로 전달 |
call by address
형식매개변수가 변하면 실매개변수도 변하게 하려면 주소 연산자와 포인터를 이용하여 call by address로 구현해야 함
실매개변수의 주소로 함수를 호출
- c=sum(&a,&b);
call by address에서는 sum()함수의 정의를 다음과 같이 수정
#include <stdio.h>
int sum(int *pa, int *pb);
int main(void)
{
int a = 2, b = 5, c=0;
printf("sum()호출 전 a=%d b=%d c=%d\n", a, b, c);
c = sum(&a, &b);
printf("sum()호출 후 a=%d b=%d c=%d\n", a, b, c);
//4,10,14
return 0;
}
int sum(int *pa, int *pb)
{ //a의 주소가 포인터 pa로 전달됨
*pa = *pa + 2;
*pb = *pb + 5;
return(*pa + *pb);
}
sum() 호출 전 a=2 b=5 c=0
sum() 호출 후 a=4 b=10 c=14
call by value 예
#include <stdio.h>
int sum(int x, int y);
int main(void)
{
int a = 2, b = 5, c=0;
printf("sum()호출 전 a=%d b=%d c=%d\n", a, b, c);
c = sum(a, b);
printf("sum()호출 후 a=%d b=%d c=%d\n", a, b, c); //2,5,14
return 0;
}
int sum(int a, int b)
{
a = a + 2;
b = b + 5;
printf("sum()함수 내 a=%d b=%d a+b=%d\n", a, b, a + b);
return(a + b);
}
sum()호출 전 a=2 b=5 c=0
sum()함수 내 a=4 b=10 a+b=14
sum()호출 후 a=2 b=5 c=14
반복되는 부분은 함수로 구현
두 수를 더하여 출력하는 일을 프로그램을 통해서 3번 반복
프로그램 내에서 반복적으로 사용하는 부분은 따로 함수로 구현해 놓은 후 그 함수를 호출하는 방식으로 프로그램을 작성하는 것이 여러 가지로 유리
#include <stdio.h>
int main(void)
{
int num1=1,num2=2,num3=3;
int num4=4,num5=5,num6=6;
int sum;
sum=num1+num2;
printf("두 수 %d과 %d를 더한 결과는 %d입니다.\n",num1, num2, sum);
sum=num3+num4;
printf("두 수 %d과 %d를 더한 결과는 %d입니다.\n",num3, num4, sum);
sum=num5+num6;
printf("두 수 %d과 %d를 더한 결과는 %d입니다.\n",num5, num6, sum);
return 0;
}
#include <stdio.h>
void add(int x, int y);
int main(void)
{
int num1 = 1, num2 = 2, num3 = 3;
int num4 = 4, num5 = 5, num6 = 6;
add(num1, num2);
add(num3, num4);
add(num5, num6);
return 0;
}
void add(int x, int y)
{
printf("두 수 %d과 %d를 더한 결과는 %d입니다.\n", x, y, x + y);
}
모듈화 프로그래밍 연습 : 모듈화 전
임의의 개수의 수를 입력 받아 합, 평균, 최대값, 최소값을 출력하는 프로그램
우선 모듈화 하지 않고 main()함수에 전체 기능을 모두 구현
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <limits.h> //INT_MIN, INT_MAX가 정의되어 있음
int main(void)
{
int i, num, sum = 0, total, max = INT_MIN, min = INT_MAX;
// max는 int형으로 표현할 수 있는 가장 작은 값 INT_MIN으로 초기화
// min은 int형으로 표현할 수 있는 가장 큰 값 INT_MAX로 초기화
printf("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");
printf("┃ 임의의 개수의 수의 합, 평균, 최대값, 최소값을 구하는 프로그램┃\n");
printf("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");
printf("계산하려는 수는 몇 개입니까=>");
scanf("%d", &total);
for (i = 1; i <= total; i++) {
printf("%d번째 수를 입력하세요=", i);
scanf("%d", &num);
sum += num;
max = (num > max) ? num : max;
min = (num < min) ? num : min;
}
printf("합:%d 평균:%.2f 최댓값:%d 최솟값:%d\n",
sum, (double)sum / total, max, min);
return 0;
}

모듈화 프로그래밍 연습 : 모듈화 후
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <limits.h>
void start(void);//함수 선언
int max_number(int a, int b); //함수 선언
int min_number(int a, int b); //함수 선언
int main(void)
{
int i, num, sum = 0, total;
int max = INT_MIN, min = INT_MAX;
start();//함수 호출
printf("계산하려는 수는 몇 개입니까=>");
scanf("%d", &total);
for (i = 1; i <= total; i++) {
printf("%d번째 수를 입력하세요=", i);
scanf("%d", &num);
sum += num;
max = max_number(num, max);//함수 호출
min = min_number(num, min);//함수 호출
}
printf("합:%d 평균:%.2f 최대값:%d 최소값:%d\n",
sum, (double)sum / total, max, min);
return 0;
}
void start(void)//함수 정의
{
printf("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");
printf("┃ 합, 평균, 최대값, 최소값 ┃\n");
printf("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");
}
int max_number(int a, int b)//함수 정의
{
return((a > b) ? a : b);
}
int min_number(int a, int b)//함수 정의
{
return((a < b) ? a : b);
}

소스를 헤더 파일(.h)과 C 파일(.c)로 나누기
헤더 파일(.h)과 C 파일(.c)로 나누어서 구현
헤더 파일에는 전처리기와 함수 선언
C 파일에는 나머지 소스와 만든 헤더 파일을 포함시킴
다음 소스를 C 파일에서는 제거하고 헤더 파일 score.h에 저장

Header File 추가
솔루션 탐색기의 [헤더파일]-[추가]-[새 항목]

헤더파일 이름: score.h

score.c + score.h
추가된 score.h에 잘라놓았던 소스를 붙여넣기

score.c에 #include "score.h"
솔루션 탐색기의 score.c를 더블 클릭하여 소스 추가
score.h에 저장되어 있는 전처리기와 함수선언을 현재의 소스에 포함시킴
#include "score.h"
