사자자리
[C언어] 6주차 함수의 활용 본문
함수의 인수 전달 방법
값에 의한 전달
- 함수를 호출할 때 넘겨주는 인수의 값을 함수 정의에 있는 매개변수로 복사해서 전달하는 방식
#include <stdio.h>
void swap(int x, int y){
int temp;
temp = x;
x = y;
y = temp;
}
int main(){
int a = 10;
int b = 20;
printf("swap 전의 a = %d, b = %d\n", a, b);
swap(a, b);
printf("swap 후의 a = %d, b = %d\n", a, b);
}
<실행 결과>
swap 전의 a = 10, b = 20
swap 후의 a = 10, b = 20
포인터에 의한 전달
- 변수의 값을 복사해서 전달하는 대신, 변수의 주소를 전달하는 방식
#include <stdio.h>
void swap(int *x, int *y){ //매개변수를 포인터형으로 선언
int temp;
temp = *x;
*x = *y; //매개변수가 가리키는 곳에 처리 결과를 저장
*y = temp;
}
int main(){
int a = 10;
int b = 20;
printf("swap 전의 a = %d, b = %d\n", a, b);
swap(&a, &b); //변수의 주소를 인수로 전달
printf("swap 후의 a = %d, b = %d\n", a, b);
}
<실행 결과>
swap 전의 a = 10, b = 20
swap 후의 a = 20, b = 10
배열의 전달
- 배열은 항상 포인터로 전달한다.
- 함수 안에서는 일반 배열인 것처럼 인덱스를 사용한다.
- 함수를 호출할 때는 [ ] 없이 배열명만 인수로 넘긴다.
- 함수 안에서 배열의 크기가 필요할 때, 배열의 크기도 인수로 전달한다.
- 특정 원소의 주소를 전달하면 배열의 일부분만 인수로 전달할 수 있다.
#include <stdio.h>
void printArray(int *arr, int size){ //배열은 항상 포인터로 전달한다.
for (int i = 0; i < size; i++){ //함수 안에서 배열의 크기가 필요할 때, 배열의 크기도 인수로 전달한다.
printf("%d ", arr[i]); //배열을 포인터 변수로 전달했지만, 일반 배열인 것처럼 인덱스를 사용한다.
}
printf("\n");
}
int getSum(int arr[], int size){ //int arr[]과 int *arr은 같은 의미다.
int total = 0;
for (int i = 0; i < size; i++){
total += arr[i];
}
return total;
}
int main(){
int x[5] = {10, 20, 30, 40, 50};
int y[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
printf("x 배열: ");
printArray(x, 5); //함수를 호출할 때는 []없이 배열명만 인수로 넘긴다.
printf("x 배열의 합계: %d\n", getSum(x, 5));
printf("y 배열: ");
printArray(y, 10);
printf("y 배열의 합계: %d\n", getSum(y, 10));
printf("배열의 일부분만 전달하기: ");
printArray(y + 2, 5); //특정 원소의 주소를 전달하면 배열의 일부분만 인수로 전달할 수 있다.
return 0;
}
<실행 결과>
x 배열: 10 20 30 40 50
x 배열의 합계: 150
y 배열: 1 2 3 4 5 6 7 8 9 10
y 배열의 합계: 55
배열의 일부분만 전달하기: 3 4 5 6 7
- 배열이 함수 안에서 변경되지 않을 때는 const를 지정할 수 있다.
void printArray(const int *arr, int size); //arr이 가리키는 배열을 변경할 수 없고 읽을 수만 있다.
void printArray(const int arr[], int size); //두 문장은 같은 의미다.
구조체의 전달
- 구조체를 인수로 갖는 함수를 선언할 때, 포인터로 전달하는 것이 좋다.
#include <stdio.h>
typedef struct point{
int x, y;
} POINT;
//구조체를 값으로 전달하는 경우
void printPoint(POINT p){
printf("%d, %d\n", p.x, p.y);
}
//구조체를 포인터로 전달하는 경우
void printSwapPoint(POINT *p){
int temp;
temp = p->x;
p->x = p->y;
p->y = temp;
printf("%d, %d\n", p->x, p->y);
}
int main(){
POINT p1 = {10, 20};
printPoint(p1); //값으로 전달
printSwapPoint(&p1); //포인터로 전달
return 0;
}
<실행 결과>
10, 20
20, 10
- 구조체가 함수 안에서 변경되지 않을 때는 const를 지정할 수 있다.
void printPoint(const POINT *p);
재귀함수(recursive function)
- 자기 자신을 다시 호출하는 함수
- 문제 해결을 위한 알고리즘을 단순화한다.
#include <stdio.h>
int factorial(int n){
if (n < 2) return 1;
return n * factorial(n - 1);
}
int main(){
int num;
scanf("%d", &num);
printf("%d! = %d\n", num, factorial(num));
return 0;
}
<실행 결과>
5
5! = 120
- 재귀 함수를 호출하면 함수가 여러 번 반복적으로 호출되므로, 오버헤드가 크다.
- 따라서 재귀함수보다 반복문으로 구현하는 것이 성능 면에서는 좋다.
- 재귀 함수 호출 시, 함수 호출의 깊이가 너무 깊어지지 않도록 주의한다.
기억 부류(storage class)
- 변수나 함수를 선언할 때 사용되는 키워드
- 변수나 함수의 저장 위치와 사용 범위를 결정한다.
- 변수나 함수의 선언 시, 맨 앞에 지정한다.
- 변수의 디폴트 기억 부류는 auto이고, 함수의 디포트 기억 부류는 extern이다.
auto
- 지역 변수의 디폴트 기억 부류
- 전역 변수에는 지정할 수 없다.
- auto 지역 변수는 선언된 위치에서 자동으로 생성되고 선언된 블록을 빠져나갈 때 자동으로 해제된다.
#include <stdio.h>
int main(){
auto int a = 10;
int b = 20; //auto를 생략해도, b는 auto 변수이다.
}
register
- 변수를 메모리가 아닌 CPU의 레지스터에 할당한다.
- 변수를 레지스터에 할당하면, 변수에 좀 더 빠르게 접근할 수 있다.
- 보통 루프 제어 변수를 register 변수로 선언한다.
#include <stdio.h>
int main(){
int sum = 0;
register int i;
for (i = 0; i < 11; i++) sum += i;
printf("%d", sum);
return 0;
}
- register 변수를 선언해도, 변수가 레지스터에 할당되지 않을 수 있다.
- register 변수에 대해서 주소 구하기 연산자를 사용할 수 없다.
register int i;
printf("%p", %i); //컴파일 에러
extern
- 프로그램의 한 소스 파일(print.c)에 선언된 전역 변수(num1)를 extern을 통하여 다른 소스 파일(main.c)에서도 사용할 수 있다.
static
- 정적 지역 변수: 함수가 리턴해도 해제되지 않고 남아있다가, 다음 함수 호출에 다시 사용된다.
#include <stdio.h>
void testStatic(void){
int LocalVar = 0; //지역 변수
static int StaticLocalVar = 0; //정적 지역 변수
printf("LocalVar = %d, StaticLocalVar = %d\n", ++LocalVar, ++StaticLocalVar);
}
int main(){
for (int i = 0; i < 5; i++) testStatic();
return 0;
}
<실행 결과>
LocalVar = 1, StaticLocalVar = 1
LocalVar = 1, StaticLocalVar = 2
LocalVar = 1, StaticLocalVar = 3
LocalVar = 1, StaticLocalVar = 4
LocalVar = 1, StaticLocalVar = 5
- 문자열을 역순으로 만들어서 리턴하는 함수
#include <stdio.h>
#include <string.h>
char *Reverse(const char *str){
static char result[100]; //정적 지역 변수 선언
int len = strlen(str);
int i = 0;
for (i = 0; i < len; i++){
result[i] = str[len - i - 1];
}
result[i] = '\0';
return result; //result를 정적 지역 변수로 선언해서, 함수가 리턴해도 해제되지 않는다.
}
int main(){
char name[] = "Regulus Black";
char *result = NULL;
result = Reverse(name);
printf("%s", result);
return 0;
}
<실행 결과>
kcalB sulugeR
- 정적 전역 변수: 다른 소스 파일에서 전역 변수에 접근하지 못하도록 제한한다.
일반 지역 변수 | 정적 지역 변수 | 전역 변수 | 정적 전역 변수 | |
선언 위치 | 함수 안 | 함수 안 | 함수 밖 | 함수 밖 |
생성 시점 | 변수 선언 시 | 프로그램 시작 시 | 프로그램 시작 시 | 프로그램 시작 시 |
해제 시점 | 함수 리턴 시 | 프로그램 종료 시 | 프로그램 종료 시 | 프로그램 종료 시 |
사용 범위 | 함수 안 | 함수 안 | 프로그램 전체 | 선언된 소스 파일 |
초기화하지 않으면 | 쓰레기 값 | 0으로 초기화 | 0으로 초기화 | 0으로 초기화 |
'C언어 > C언어 이론' 카테고리의 다른 글
[C언어] 7주차 동적 메모리 할당 (0) | 2022.06.26 |
---|---|
[C언어] 7주차 포인터의 활용 (0) | 2022.06.26 |
[C언어] 6주차 구조체 (0) | 2022.05.27 |
[C언어] 5주차 포인터 (0) | 2022.05.20 |
[C언어] 5주차 배열과 문자열 (0) | 2022.05.20 |