[C언어 기초] #07. 함수

함수와 포인터

✅ 정리할 내용

  • 함수의 사용
  • 배열을 매개변수로 사용하기
  • 함수의 호출 방식

📌 함수를 선언하는 법

#include <stdio.h>

int getSum(int n1, int n2);

int main() {

	int a = 10;
	int b = 20;
	int result = getSum(a,b);

	printf("%d\n",result);

	return 0;
}

int getSum(int n1, int n2){
	return n1 + n2;
}

이렇게 main함수 위에 int getSum(int a, int b); 처럼 함수의 내용을 제외한
"반환형식" "함수이름" "매개변수" ;를 선언해주면 된다.

함수의 원형
반환형식 함수이름(매개변수);
ex) int getSum(int n1, int n2);

  • int형 함수
    int형 값을 return해야 한다.
    그래서 return n1+n2;라고 해서 n1+n2를 반환한다.

    반환된 n1+n2는
    int result = getSum(a, b);를 통해 result에 대입한다.

  • 매개변수는?
    int n1와 int n2 두 개이다.
    그래서 main함수에서도 a와 b를 보내주었다.
    근데 매개변수는 n1, n2인데 왜 a와 b를 보내준 것일까?

    결론부터 말하자면 크게 상관없다.
    왜냐하면 n1과 n2는 getSum안에만 존재하는 변수이기 떄문이다.

    매개 변수는 단지 "값만" 전달하는 역할을 한다.


    📌 배열을 매개변수로

    매개변수로 배열을 사용할 수 있다.

 #include <stdio.h>
 
 int getSum(int arr[]);
 
 int main() {
 	int arr[5] = {1, 2, 3, 4, 5};
	printf("sum : %d\n", getSum(arr));
    
	return 0;
 }
 
 int getSum(int arr[]){
 	int sum = 0;
 	
 	for(int i = 0; i < sizeof(arr) / sizeof(int); i++){
 	sum += arr[i];
   	}
    	return sum;
 }
 
 // 출력 결과
 sum : 1             
 

분명 15가 나와야 할 것 같은데 1이 나왔다.

sizeof(arr)이 4이기 때문이다.
(sizeof(arr)는 int형 배열이고, 크기가 5니까 20이 나와야 하는데?)

sizeof 연산자
✔ 배열이 차지하는 전체 공간과 요소의 개수는 sizeof연산자를 활용하면 간단하게 구할 수 있다.
✔ 배열의 크기를 구할 때는 전체 공간을 요소의 크기로 나눠준다.
sizeof(arr) / sizeof(int)
ex) int arr[5] = {1, 2, 3, 4, 5} 이라고 가정하면,
int형은 4바이트(요소의 크기)이고
arr전체 공간은 5이다.
sizeof(arr);는 20(4X5)이며,
따라서 요소의 개수는 5개이다.

여기서 필요한 개념이 바로 포인터이다.

getSum함수의 매개변수로 int arr[] 가 들어있다.
그럼 당연히 배열이 다 넘어올 것 같지만 사실 포인터가 넘어온다.

포인터가 넘어오는 이유 : 메모리 관련 문제
C언어에서는 아무리 int arr[]을 매개변수로 써도
컴퓨터는 int* arr을 넘긴 것으로 이해를 한다.
포인터와 배열은 주소값을 이용한다는 측면에서 동일하다.

그럼 저 예시를 다시 고쳐보면 이렇게 된다.

#include <stdio.h>

int getsum(int arr[], int size); // 수정 부분

int main() {

	int arr[5] = {1, 2, 3, 4, 5};
  	int *ptr = arr; // 수정 부분
      
	printf("sum : %d\n", getSum(ptr, sizeof(arr) / sizeof(int))); // 수정 부분
  
  	return 0;
}

int getSum(int arr[], int size) {

	int sum = 0;
  
  	for(int i = 0; i < size; i++) {
      		sum += arr[i];
        }
        return sum;
}

// 출력 결과
sum : 15

이렇게 main함수에서 배열의 크기를 미리 구한 후 넘겨주면 해결이 된다.

int getSum(int arr[])int getSum(int* arr)과 같다.
즉, 함수에서 배열을 매개변수로 사용하려면 ( ) 안에서 매개변수 이름 뒤에 [ ]를 붙이거나 매개변수를 포인터로 지정해 준다.


📌 함수의 호출 방식

#include <stdio.h>

void swap(int num1, int num2);

int main() {

	int num1 = 5;
	int num2 = 10;

	printf("변경전\n");
	printf("num1 : %d\n", num1);
	printf("num2 : %d\n\n", num2);

	swap(num1, num2);

	printf("변경후\n");
	printf("num1 : %d\n", num1);
	printf("num2 : %d\n", num2);

	return 0;
}

void swap(int num1, int num2) {
	int temp = num1;
	num1 = num2;
	num2 = temp;
}

//출력 결과
변경전
num1 : 5
num2 : 10

변경후
num1 : 5
num2 : 10

swap 함수를 살펴보면,
먼저 temp에 num1을 저장한다.
그리고 num1에는 num2값을 대입하고,
num2에는 temp값을 대입한다.
이렇게 되면 num1과 num2값이 바뀌어야 한다.

하지만 이상하게도 바뀌지 않았는데, 그 이유는 함수의 호출 방식에 의해서이다.

1) Call by Value

함수를 통해 단순히 값(Value)만 전달하는 호출방식이다.

지금까지 다룬 모든 함수가 바로 이 방식을 통해 호출(Call)된다.

그 말은 즉,
swap내에 있는 num1, num2와
main함수 내에 있는 num1, num2가 다르기 때문에
아무리 swap함수 내에서 값을 바꾼다고 해도, 실제로 main함수에는 아무런 영향이 없음을 의미한다.

2) Call by Reference

함수를 통해 값이 아닌 주소값을 전달하는 호출방식이다.
위와는 다른 개념이다.
주소값을 전달한다는 것은 그 변수 자체에 접근을 하겠다는 것을 의미한다.

그리고 이를 사용하기 위해서는
바로 포인터를 사용하는 것이다.

그럼 위의 예시를 다시 수정하면 다음과 같다.

#include <stdio.h>

void swap(int* num1, int* num2);

int main() {
	int num1 = 5;
    	int num2 = 10;
        
        printf("변경전/n");
        printf("num1 : %d\n", num1);
	printf("num2 : %d\n\n", num2);

	swap(&num1, &num2);

	printf("변경후\n");
	printf("num1 : %d\n", num1);
	printf("num2 : %d\n", num2);

	return 0;
}

void swap(int* num1, int* num2) {
	int temp = *num1;
    	*num1 = *num2;
        *num2 = temp;
}

// 출력 결과
변경전
num1 : 5
num2 : 10

변경후
num1 : 10
num2 : 5

위의 예시는 메모리 주소를 이용해서 접근하므로,
num1, num2의 데이터 값에 직접적으로 영향을 준다.

swap의 매개변수는 int* num1, int* num2이다.
이 둘은 포인터 변수로서, 주소값을 넘겨받을 수 있다.

그래서 main함수에서 swap(&num1, &num2);를 한 것이다.
이것은

int a = 10;
int* ptr = &a;

위의 코드와 같은 원리이다.

그럼 이제 swap함수 내부에는 main함수의 num1의 주소값을 가진 num1과
main함수의 num2의 주소값을 가진 num2가 있다.

따라서,

int temp = *num1;
*num1 = *num2;
*num2 = temp;

를 통해서 그 주소값이 가리키는 값 자체를 바꿔버린 것이다.

배열의 요소값 바꾸는 예제

#include <stdio.h>

// 배열의 요소값을 바꾸는 예제
int swap(int arr[], int first, int second);

int main() {
	int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	swap(arr, 0, 1);

	printf("%d %d", arr[0], arr[1]);

	return 0;

}

int swap(int arr[], int first, int second) {
	int temp;

	temp = arr[first];
	arr[first] = arr[second];
	arr[second] = temp;

}

🎯 함수 문제

1) 팩토리얼 함수 만들기

정수 N을 입력받고, N팩토리얼을 구하는 int형 함수를 만들고 값을 출력해보아라.

(N팩토리얼) = N X N-1 X N-2 X ... X 2 X 1

#define _CRT_SECURE_NO_WARNINGS    
#include <stdio.h>

int _factorial(int N);

int main() 
{
	int N;
	scanf("%d", &N);

	int result = _factorial(N);
	printf("%d의 팩토리얼 : %d", N, result);

	return 0;
}

int _factorial(int N)
{
	int result = 1;

	for (int i = 1; i <= N; i++) {
		result *= i;
	}
	return result;
}

2) 가장 큰 값 찾기

크기가 10인 배열을 입력받은 뒤, 배열 내의 최대값을 구하는 함수를 만들어 보아라.
[조건]

  • 배열 선언 후, 포인터를 활용
  • 함수는 "void"형으로 선언
#define _CRT_SECURE_NO_WARNINGS    
#include <stdio.h>

// 가장 큰 값 찾기
void getMax(int arr[], int arrSize, int* maxValue);

int main() {
	int result;

	int arr[10] = { 0,};

	for (int i = 0; i < 10; i++) {
		scanf("%d", &arr[i]);
	}
	
	int* ptr = arr;

	getMax(ptr, 10, &result);

	printf("최대값 : %d", result);

	return 0;

}

void getMax(int arr[], int arrSize, int * maxValue) {
	int temp = 0;

	for (int i = 0; i < arrSize; i++) {
		if (arr[i] > temp) {
			temp = arr[i];
		}
	}
	*maxValue = temp;
}

좋은 웹페이지 즐겨찾기