: 특정 작업을 반복적으로 수행하기 위히 일련의 명령어들을 모듈단위로 모아두고 필요할 때마다 호출해서 사용할 수 있도록 해준다.
1) 코드의 간결성
: 반복되는 소스 코드 부분을 하나의 블록형태로 모아 두고 필요할 떄마다 호출해서 사용하므로 중복을 줄일 수 있고 간단한 호출만으로 실행시킬 수 있기에 코드가 간결해진다.
2) 소스 수정 및 유지보수 용이
: 소스에 대한 수정이 필요한 경우 전체 소스 수정이 아닌 기능이 구현된 함수단위로 수정을 하면 되므로 유지보수에 용이하다.
3) 프로그램의 모듈화
: 연관된 기능별로 함수를 작성해 사용하므로 프로그램의 모듈화가 가능해진다.
: 기본적으로 C언어가 제공하는 함수.
- 비슷한 기능끼리 헤더 파일 (.h)에 선언되어 있으므로 #include 지시자를 이용해 헤더 파일을 코드에 포함시켜 사용한다.
- 라이브러리 함수를 사용할 때는 그 함수를 실행할 때 필요한 인수의 개수와 자료형을 정확히 알고 사용해야 한다.
: 프로그래머가 필요에 의해 직접 함수를 정의해서 사용하는 함수.
1) 함수의 정의
- 크게 머리와 본문으로 구성되며 함수의 머리에는 세미콜론을 사용하지 않는다.
함수 반환형 함수명(매개 변수1, 매개 변수2, ...) { → 함수 머리(header) 함수 내부 변수의 선언; → 함수 본문(body) 함수 내부 명령문; return 반환 값; }
- 함수 반환형(함수의 자료형) : 함수 수행 후 반환할 데이터의 종류
- 함수 반환형을 생략하면 기본형int로 간주해 정수값을 반환할 수 있다. 반환할 값이 없는 경우void를 표기한다.- 함수명
- 정의한 여러 함수를 구별하고 필요할 때 호출하기 위한 이름- 매개 변수
- 함수 호출 시 괄호 안에 넣어지느 변수 또는 값을인수라고 하는데 이떄 인수에 의해 전달받은 값을 함수 내에서 사용하기 위해 선언되는저장 공간을매개 변수라고 한다.
- 매개 변수가 주어진 함수 호출 시 정의된 매개 변수의 개수와 자료형을 일치 시켜 줘야한다.
- 함수 본문
- 실제 함수가 실행하는 동작 구현
- 함수내에 선언된 변수는 함수 안에서만 사용이 가능하며
return명령문은 함수를 종료하며 값을 반환하는 역할을 한다.
2) 함수의 원형
- 함수를 호출할 때 컴파일러는 함수의 정보를 미리 인지하고 있어야 하기 떄문에 함수의 정의는 함수를 호출하기 전에 위치하는 것이 일반적이다.
함수 호출 후 함수의 정의를 할 경우에는 헤더만 미리 명시해 컴파일러에게 함수의 존재를 알려줘야한다. 이를 함수의 원형이라고 한다.- 대부분 main() 함수 전에 위치하는 것이 일반적이며 정의와 다르게 세미콜론(;)이 필요하다. 매개 변수는 자료형과 변수명 또는 자료형만 명시 가능하다.
#include <stdio.h> int add(int x, int y); → add()함수의 원형 int main(void) { int a,b,sum; sum = add(a,b); → main() 함수에서 add() 함수 호출 return 0; } int add(int x, int y) { → add() 함수 정의 int z; z = x + y; return z; }
3) 자료의 전달 방법
- 함수 호출 시 매개 변수를 이용해 데이터를 전달하는 방법은 아래의 2가지로 나뉜다.
값에 의한 전달(call by value)
: 인수의 값을 복사해 매개 변수에 전달하는 방법 == 값 자체를 넘기는 것
- 복사한 값을 함수에 전달하는 것이므로 실제 인수에 영향을 미치지 않는다.
참조에 의한 전달 (call by address)
: 인수의 주소를 전달하는 방법 == 값이 들어 있는 메모리 주소를 넘겨서 함께 공유하는 참조에 의한 전달.
- main() 함수와 호출된 함수는 같은 변수의 주소를 공유하기 떄문에 하나의 변수를 공유하는 것과 같다.
- : 해당 주소의 값을 참조해요! 의미를 가진다.
#include<stdio.h> void Swap(int *x, *y); → 주소를 저장하는 포인터 변수로써 * 붙여 사용 int main(void) { int a = 50, b = 70; printf("Swap 전의 a = %d, b = %d\n", a, b); Swap(&a, &b); → 각 변수의 값이 아닌 "주소"를 전달함 (& : 주소 연산자 사용) printf("Swap 후의 a = %d, b = %d\n", a, b); return 0; } void Swap(int *x, int *y) { → x,y에 저장된 주소를 참조하여 이루어지므로 int temp; main() 함수에 영향을 미치게 된다. temp = *x; *x = *y; *y = temp; } <output> Swap 전의 a = 50, b = 70 Swap 후의 a = 70, b = 50
4) 재귀 함수(순환 함수, recursive function)
: 자기 자신을 호출하여 사용하는 함수
- 반복해서 처리해야 하는 일을 간단하게 표현할 수 있으며 팩토리얼(!) 계산하는 프로그램이 가장 대표적인 예이다.
- 변수가 사용될 수 있는 범위는 변수의 선언 위치에 따라 달라진다.
즉, 변수 선언 위치에 따라 함수 내부 혹은 여러 함수를 포함한 프로그램 전체에서 사용될 수 있다.
1) 지역 변수(자동 변수)
: 함수나 임의의 블록 내부에서 선언된 변수로 자신이 선언된 함수 또는 선언된 블록 내에서만 사용이 가능하다.
- 지역 변수를 초기화하지 않으면 쓰레기값이라 불리는 의미 없는 값이 채워지므로 주의해야한다.
- 이 변수는 해당 구역이 종료되는 시점에 자동으로 메모리를 반납하고 사라진다.
#include<stdio.h> void Swap(int x, y); int main(void) { int a = 50, b = 70; → main() 함수 지역 변수 a, b return 0; } void Swap(int x, int y) { → Swap() 함수 지역 변수 x, y int temp; temp = x; x = y; y = temp; }
2) 전역 변수
: 함수의 외부에서 선언된 변수로 해당 프로그램 내의 모든 함수와 모든 블록에서 접근하여 사용 가능하다.
- 지역 변수와는 저장되는 영역이 다르기 떄문에 선언 후 초기화하지 않아도 자동으로
0으로 초기화가 되고 프로그램 종료시점에 메모리를 반납한다.#include<stdio.h> int Sum(int x, y); int result; → 전역 변수 int main(void) { int a = 50, b = 70; Sum(a, b); printf("두 수의 합 : %d\n", result); return 0; } int Sum(int x, int y) { → 어디서든 사용이 가능하다. result = x + y; return result; }
1) 정적 변수
:static키워드를 사용하며 해당 함수가 종료되더라도 그 내용이 지워지지 않고 프로그램이 종료될 때 까지 값을 유지하는 변수.←→ 선언된 함수 혹은 블록이 종료될 떄 메모리를 반납하고 사라지기에 메모리 공간을 효율적으로 사용할 수 있는 함수인 동적 변수와는 다른 개념이다. auto 키워드를 사용하는데 생략이 가능하다. 지금까지 사용한 모든 변수는 여기에 속한다.
2) 레지스터 변수
일반적인 변수는 주기억장치에 저장이 된다. 주기억장치보다 빠른 CPU 내의 기억장소인레지스터에 저장하면 보다 빠른 처리가 가능하지 않을까?
- 이를 레지스터 변수라하고 변수명 앞에
register로 지정하여 선언한다.- 하지만 가용할 수 있는 레지스터 개수가 한정적이므로 레지스터 변수로 선언했을지라도 사용을 보장하지 못한다. 프로그램 실행동안 메모리를 차지하는 일반 변수를 레지스터 변수로 선언하는 것은 적절하지 못한 것이다.
때때론 여러 개의 파일로 이루어진 프로그램을 하나로 합치는 과정이 필요할 때가 있다. 이런 경우 외부 파일에서 선언된 변수를 공유하고자 할 때 변수명 앞에
extern을 사용해 메모리 영역을 공유할 수 있다.