함수와 포인터

라니·2023년 3월 23일
0

C language

목록 보기
3/3
post-thumbnail

💡이번에는 함수의 인자 전달, 함수의 호출방식 등에 대해서 알아보자

함수 인자 전달

  • 함수의 인자 전달 기본 방식은 복사
  • 함수 호출 시 전달되는 값을 매개 변수를 통해서 전달 받는데, 이때에 값의 복사가 실행됨




함수 호출 방식

Call-By-Value (값에 의한 호출)

  • call by value의 기본 호출 방식은 값의 복사이다.

    #include <stdio.h>
    void sub (int v);
    
    int main (void)
    {
    	int i= 100;
      	sub(i);
      	printf("i=%d\n", i);
      	return 0;
    }
    void sub (int v)
    {
    	v = 200;
    }
    /*
    <결과>
    i= 100
    */

Call-By-Reference (참조에 의한 호출)

  • call by value와 반대되는 개념

  • 변수의 복사본이 함수로 전달되는 것이 아닌, 원본의 주소값을 통해 직접 전달

  • 함수의 호출 방식으로 함수를 호출하면서 주소값을 전달

  • 전달된 주소가 가리키는 원본 변수의 조작이 함수 내에서 직접 가능

    #include <stdio.h>
    void sub (int v);
    
    int main (void)
    {
    	int i= 100;
      	sub(&i);
      	printf("i=%d\n", i);
      	return 0;
    }
    void sub (int *v)
    {
    	*v = 200;    //본 예제에서는 return값이 없어서 전역에선 바뀌지 않는다
    }
    /*
    <결과>
    i= 100
    */

잘못된 포인터의 사용

  • 예시 ) swap() 함수

  • swap함수 내에서 포인터를 사용하더라도 swap의 지역 변수를 가리키기 때문에 main함수 값에 영향을 주지 않음

    #include <stdio.h>
    void swap(int a, int b);
    
    int main(void) 
    {
    	int val1 =10, val2 = 20;
        swap(val1, val2);
        printf("val1, vla2 : %d, %d\n", val1, val2);
        return 0;
    } 
    void swap(int a, int b) 
    {
        int temp;
        int *pa, *pb;
        pa = &a;
        pb = &b;
        temp = (*pa);
        (*pa) = (*pb);
        (*pb) = temp;
        printf("a, b : %d, %d \n", a, b);
    }
    /* 결과
    a, b = 20, 10
    val1, val2 = 10, 20
    */

Call-By-Value와 Call-By-Reference정리

  • 호출한 함수 내에서 변수를 단순히 읽기만 하는 경우에는 Call-By-Value로 충분
  • 외부에서부터 전달받은 변수의 값을 변경하여 외부로 내보내고 싶은 경우 Call-By-Value를 사용하면 제한이 생김
  • 함수의 반환(Return)을 이요하여 하나의 값만을 외부로 반환할 수 있음
  • 호출한 함수 내에서 연산에 의해 변화된 값을 반영하여 외부로 내보내고 싶은 변수가 많은 경우에는 Call-By-Reference를 사용

scanf("입력 받을 문자의 서식", 변수의 주소)
→ 사용자의 입력값을 받는 함수

//ex)
scanf("%d, %d", &num1, &num2); //입력받는 형식이 "%d, %d"이므로 10, 20와 같이 입력해야 함
scanf("%d %d", &num1, &num2); //입력받는 형식이 "%d %d"이므로 10 20와 같이 입력해야 함
  • scanf 함수 호출시 변수에 &를 붙이는 이유?
    • scanf 함수로 main에 있는 val 변수에 값을 저장한다고 하자.
    • scanf 함수 내에서 main 함수에서 선언된 지역 변수 val에 접근하기 위해서는 해당 변수의 주소를 알아야한다.
    • 따라서 scanf 함수를 호출하면서 값이 채워질 지역 변수 val의 주소값을 인자로 전달하는 것이다.
    • 요약 : Call-By-Reference를 이용해야 여러개의 변수에 값을 저장할 수 있기 때문!

배열을 함수의 인자로 전달할 때

  • 배열의 경우 일반 변수처럼 값 전체를 복사하는 방법을 사용할 수 없다.

  • 따라서 배열의 주소를 넘겨서 접근하도록 유도하는 방법을 사용한다.

    #include <stdio.h>
    void fct(int *arr2);
    
    int main(void) 
    { 
    		int arr1[2] = {1, 2};
    		fct(arr1); //배열의 주소를 전달 (배열이름이 포인터)
    		printf("arr1[0] : %d \n", arrr1[0]);
    		printf("arr1주소 : %d \n", arr1);
    		return 0;
    }
    void fct(int *arr2)
    {
    		printf("arr2[0] : %d \n", arr2[0]);
    		printf("arr2주소 : %d \n", arr2);
    		arr2[0] = 3;
    }
    /* <결과
    arr2[0] : 1
    arr2주소 : 1245020
    arr1[0] : 3
    arr1주소 : 1245020
    */
  • 배열 전달시 주의점

    • 배열의 주소만 전달하기 때문에 배열의 크기를 알 수가 없다.

    • 배열의 주소를 인자로 전달할 경우 주소와 함께 크기를 보내는 것이 좋다.

      //배열의 총합 출력하기
      #include <stdio.h>
      int ArrAdder(int *pArr, int n);
      int main(void) 
      { 
      	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
      	int sumArr;
      	sumArr = ArrAdder9arr, sizeof(arr)/sizeof(int));
      	printf ("배열의 총합 : %d\n", sumArr);
      	return 0;
      } 
      int ArrAdder(int *pArr, int n)
      {
      	int sum = 0;
      	int i;
      	for(i=0; i<n; i++) sum+=pArr[i];
      	return sum;
      }
      /* 
      <결과>
      배열의 총합 : 55
      */
      //배열의 최대값 출력하기
      #include <stdio.h>
      int MaxVal(int pArr[], int n); /*int prr[] 과 int *pArr은 완전히 같은 선언이다.
      								 둘 다 int형 포인터 변수이지만 int pArr[]는 매개 변수에서만 선언 가능하다.
                                     	 int pArr[]을 함수 내부에서 선언 하려면 초기화가 필요 하다. */
      
      int main(void) 
      { 
      	int arr[10] = {4,8,3,7,2};
      	int maxA;
      	maxA = MaxVal(arr, sizeof(arr)/sizeof(int));
      	printf ("최대 값 : %d\n", maxA);
      	return 0;
      }
      
      int MaxVal (int pARr[], int n) 
      {
      	int max, i;
      	max = pArr[0];
      	for (i=1; i<n; i++)
        		if (max < pArr[i])
        			max = pARr[i];
      	return max;
      }
      /* 
      <결과>
      최대 값 : 8 
      */



더블 포인터에 의한 Call-By-Reference

잘못 구현된 Call-By-Reference

#include <stdio.h>
void pswap (int *p1, int *p2);
int main() 
{
	int A = 10, B = 20;
	int *pA, *pB;
	pA = &A;
	pB = &B;
	printf("함수 호출전\n");
	printf("pA : %d\n", *pA);
	printf("pB : %d\n", *pB);
	pswap(pA, pB);
	printf("\n함수 호출 후\n");
	printf("pA : %d\n", *pA);
	printf("pB : %d\n", *pB);
	return 0;
}

void pswap (int *p1, int *p2) 
{
	int *temp;
	temp = p1;
	p1 = p2;
	p2 = temp;
}

/*
<결과>

함수 호출전
pA : 10
pB : 20

함수 호출후
pA : 10
pB : 20
*/
  • 위 예시에서 pswap함수는 pApB의 주소값을 복사에 의해 전달 받았을 뿐이다.
  • p1, p2가 서로 값을 바꾸어도 지역변수이기 때문에 pA, pB는 기존의 값을 그대로 유지하게 된다.



제대로 구현된 Call-By-Reference

#include <stdio.h>
void pswap (int **p1, int **p2);
int main() 
{
	int A = 10, B = 20;
	int *pA, *pB;
	pA = &A;
	pB = &B;
	int *p1, *p2;
	p1 = &pA;
	p2 = &pB;
	printf("함수 호출전\n");
	printf("pA : %d\n", *pA);
	printf("pB : %d\n", *pB);
	pswap(p1, p2);
	printf("\n함수 호출 후\n");
	printf("pA : %d\n", *pA);
	printf("pB : %d\n", *pB);
	return 0;
}

void pswap (int **p1, int **p2) 
{
	int *temp;
	temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
/* <결과>

함수 호출전
pA : 10
pB : 20

함수 호출후
pA : 20
pB : 10
*/
profile
강아지를 좋아합니다🐶

0개의 댓글