目次
1. C 언어에서 인수의 기본
인수란
인수는 함수가 호출될 때 외부에서 함수에 전달되는 데이터입니다. 인수를 이용함으로써 함수는 다양한 값을 입력으로 받아들여, 그에 기반한 처리를 수행할 수 있습니다. C 언어에서 인수 사용법을 마스터하는 것은 프로그램의 재사용성과 유연성을 높이기 위해 필수적입니다.실인수와 형인수
함수를 호출하는 측에서 제공되는 값을 실인수, 함수 정의 내에서 받아들이는 값을 형인수라고 부릅니다. 예를 들어,PrintScore(score);
에서는 score
가 실인수이며, void PrintScore(int score)
의 score
가 형인수입니다. 함수를 올바르게 사용하기 위해서는 실인수와 형인수의 차이를 이해하는 것이 중요합니다.2. 실인수와 형인수의 차이
실인수
실인수는 함수를 호출할 때 실제로 전달되는 값입니다. 예를 들어,PrintScore(100);
에서는 100
이 실인수입니다. 실인수는 함수에 전달되어 해당 함수 내부에서 사용됩니다.형인수
형인수는 함수 정의에서 받는 데이터의 임시 이름입니다. 형인수는 함수 내부에서 실인수의 값을 참조하지만, 함수 외부에서 그 값을 변경할 수 없습니다. 예를 들어,void PrintScore(int score)
의 score
가 형인수입니다.3. 인수 전달 방법
값 전달
값 전달은 실제 인수의 값이 형식 매개변수에 복사되는 방법입니다. 이 경우 함수 내부에서 형식 매개변수의 값을 변경해도 호출자의 실제 인수에는 영향을 주지 않습니다. 아래 예제를 살펴보세요.void LevelUp(int lv) {
lv++;
}
int main() {
int level = 1;
LevelUp(level);
printf("Level: %dn", level); // 출력: Level: 1
}
이 예에서는 LevelUp
함수 내부에서 lv
가 증가하지만, main
함수의 level
에는 영향을 주지 않습니다. 값 전달의 장점은 호출자의 데이터를 보호할 수 있다는 것이지만, 큰 데이터를 전달할 때는 메모리 사용량이 증가한다는 점에 유의해야 합니다.포인터 전달
포인터 전달에서는 실제 인수의 주소가 형식 매개변수에 전달됩니다. 이 방법을 통해 함수 내부에서 실제 인수의 값을 직접 변경할 수 있습니다.void LevelUp(int *plv) {
(*plv)++;
}
int main() {
int level = 1;
LevelUp(&level);
printf("Level: %dn", level); // 출력: Level: 2
}
이 예에서는 LevelUp
함수 내부에서 직접 level
의 값이 변경됩니다. 포인터 전달의 장점은 함수에서 여러 값을 변경·반환할 수 있다는 것이지만, 부적절한 포인터 조작은 버그나 메모리 누수의 원인이 될 수 있으므로 신중하게 다루어야 합니다.4. 인수의 수와 반환값의 조합
인수 있음·반환값 없음
인수가 있고, 처리 결과를 반환하지 않는 함수의 예입니다. 예를 들어,void PrintScore(int score)
와 같이, 점수를 표시하기 위해 인수를 받아들이고 아무것도 반환하지 않는 함수입니다.인수 없음·반환값 있음
인수를 받지 않고, 처리 결과를 반환하는 함수의 예입니다. 예를 들어,int GetCurrentScore()
는 현재 점수를 계산해서 반환하는 함수입니다.인수 있음·반환값 있음
인수를 받아들이고, 처리 결과도 반환하는 함수의 예입니다.int Add(int a, int b)
와 같이, 두 개의 숫자를 받아 그 합계를 반환합니다. 이러한 함수는 유연성이 높아 다양한 상황에서 활용됩니다.5. 재귀 호출과 인수
재귀 호출이란
재귀 호출은 함수가 자신을 호출하는 방법입니다. 문제를 작게 나누어 해결할 때 효과적이지만, 올바르게 제어하지 않으면 스택 오버플로우를 일으킬 가능성이 있습니다.재귀 호출의 예
아래는 인수를 이용해 숫자를 2로 나누는 재귀 호출의 예입니다.int funcA(int num) {
if(num % 2 != 0) {
return num;
}
return funcA(num / 2);
}
int main() {
int result = funcA(20);
printf("Result: %dn", result); // 출력: Result: 5
}
이 예에서는 funcA
함수가 자신을 호출하고, 인수를 사용해 반복 처리를 수행합니다. 재귀 호출은 같은 처리를 여러 번 반복할 경우 간단하게 기술할 수 있지만, 종료 조건을 적절히 설정하지 않으면 무한 루프에 빠질 수 있으므로 주의가 필요합니다.6. 함수 형태 매크로와 인수
함수 형태 매크로란
함수 형태 매크로는 인자를 갖는 매크로로, 컴파일 시에 코드가 치환됩니다. 이를 통해 실행 시 성능을 향상시킬 수 있습니다.함수 형태 매크로의 예
다음은 배열의 요소 개수를 얻기 위한 함수 형태 매크로입니다。#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
int main() {
int arr[10];
printf("Array size: %dn", ARRAY_SIZE(arr)); // 출력: Array size: 10
}
함수 형태 매크로는 컴파일 전에 코드가 치환되므로 실행 시 오버헤드가 없습니다. 또한, 타입 검사가 이루어지지 않기 때문에 임의의 데이터 타입에 대응할 수 있지만, 신중하게 사용하지 않으면 예상치 못한 동작을 일으킬 가능성이 있습니다.7. C 언어 표준 라이브러리의 함수와 인자
표준 라이브러리 함수 활용
C 언어에는 표준 라이브러리로 많은 함수가 제공되어 있으며, 이들 함수는 인자를 이용해 다양한 처리를 수행합니다. 예를 들어,printf
함수는 가변 인자를 받아 지정된 포맷에 따라 데이터를 표시합니다.표준 라이브러리 함수 예시
아래는printf
함수를 사용한 예시입니다.printf("Name: %s, Age: %dn", "Alice", 30); // 출력: Name: Alice, Age: 30
이 예시에서는 printf
함수가 문자열과 숫자를 표시하기 위해 인자를 이용하고 있습니다. 표준 라이브러리 함수를 활용함으로써 코드의 가독성과 효율성이 향상됩니다.8. 요약
가변 인자 활용
C 언어에는 함수에 전달하는 인자의 수를 유연하게 변경할 수 있는가변 인자가 있습니다. 이는 함수 정의에서 생략 기호(...
)를 사용하여 지정합니다. 가변 인자를 사용하면 인자의 수가 정해져 있지 않은 경우에도 함수를 만들 수 있습니다。printf
함수는 그 대표적인 예로, 포맷 문자열에 따라 다른 수의 인자를 받습니다。가변 인자 예시
다음은 가변 인자를 사용하여 여러 정수를 받아 그 합을 계산하는 함수의 예시입니다。#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
int main() {
printf("Sum: %dn", sum(4, 1, 2, 3, 4)); // 출력: Sum: 10
}
이 예시에서는 sum
함수가 여러 정수를 받아 그 합을 반환합니다。va_list
、va_start
、va_arg
、va_end
와 같은 매크로를 사용하여 가변 인자를 다룰 수 있습니다。주의점
가변 인자를 사용할 때는 전달되는 인자의 타입과 수에 주의가 필요합니다。함수 호출 측과 정의 측에서 인자의 수나 타입이 일치하지 않을 경우, 예상치 못한 동작이나 프로그램 충돌을 일으킬 가능성이 있습니다。
실용적인 사용 사례와 인자 활용
인자의 효과적인 사용법
인자를 효과적으로 활용하면 코드의 가독성과 재사용성이 향상됩니다。예를 들어, 여러 함수에서 동일한 데이터를 처리할 경우, 그 데이터를 전역 변수로 다루는 것보다 인자를 사용해 함수에 전달하는 것이 좋습니다。이를 통해 함수의 독립성이 높아지고, 다른 코드에 미치는 영향을 최소화할 수 있습니다。메모리 효율과 성능
큰 데이터를 인자로 전달할 경우, 포인터 전달을 이용하면 메모리 사용량을 절약할 수 있습니다。예를 들어, 큰 배열이나 구조체를 함수에 전달할 때 값 전달을 사용하면 데이터 전체가 복사되지만, 포인터 전달에서는 주소만 전달되므로 메모리 사용량을 줄일 수 있습니다。코딩 베스트 프랙티스
함수를 만들 때는 필요한 인자의 수와 타입을 신중하게 설계하는 것이 중요합니다。불필요한 인자를 전달하면 함수 사용이 복잡해지고 버그의 원인이 됩니다。반대로, 함수가 필요로 하는 모든 데이터를 인자로 명시적으로 전달함으로써 코드의 명확성과 유지보수성이 향상됩니다。9. 인수와 관련된 고급 기술
콜백 함수
콜백 함수는 함수를 인수로 다른 함수에 전달하고, 그 함수 내부에서 호출하는 방법입니다. 이를 통해 유연한 처리 구현이 가능해지며, 특히 이벤트 기반 프로그램이나 비동기 처리에서 많이 사용됩니다.#include <stdio.h>
void executeCallback(void (*callback)(int)) {
callback(10);
}
void printValue(int val) {
printf("값: %dn", val);
}
int main() {
executeCallback(printValue); // 출력: Value: 10
}
이 예에서는 printValue
함수를 콜백으로 전달하고, executeCallback
함수 내부에서 실행하고 있습니다.함인터
함수 포를 사용하면 함수를 변수처럼 다룰 수 있습니다. 이를 통해 함수를 인수로 전달하거나 실행 시에 다른 함수를 호출하는 것이 가능해집니다. 이는 유연하고 동적인 코드를 작성할 때 매우 유용합니다.#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int (*operation)(int, int) = add;
printf("결과: %dn", operation(2, 3)); // 출력: Result: 5
}
이 예에서는 add
함수를 함수 포인터 operation
에 할당하고, 변수처럼 함수를 호출하고 있습니다.10. 함수의 인수와 메모리 관리
동적 메모리와 인수
C 언어에서는malloc
와 free
함수를 사용하여 동적으로 메모리를 할당할 수 있습니다. 함수에 인수로 동적으로 할당된 메모리 포인터를 전달할 때는 메모리 관리에 주의해야 합니다.#include <stdlib.h>
#include <stdio.h>
void allocateMemory(int **ptr, int size) {
*ptr = (int *)malloc(size * sizeof(int));
}
int main() {
int *arr;
allocateMemory(&arr, 5);
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 출력: 1 2 3 4 5
}
free(arr); // 메모리 해제
}
이 예에서는 allocateMemory
함수로 동적으로 메모리를 할당하고, 그 포인터를 인수로 전달하고 있습니다. 메모리 관리가 적절히 이루어지지 않으면 메모리 누수가 발생할 가능성이 있으므로 주의가 필요합니다.