jam 블로그

[C] 14. 포인터와 함수에 대한 이해 본문

개발 및 관련 자료/C

[C] 14. 포인터와 함수에 대한 이해

kid1412 2013. 5. 12. 19:36
728x90

I. 함수의 인자로 배열 전달하기

  • 함수의 인자 전달 방식

    • 인자 전달의 기본 방식은 복사이다.
  • 배열을 함수의 인자로 전달하는 방식
  1. #include <stdio.h>
    void fct(int *arr2);
  2. int main()
    {
     int arr1[2] = {1,2};
     fct(arr1);
     printf("%d\n",arr1[0]);
     return 0;
    }
  3. void fct(int *arr2)
    {
     printf("%d\n",arr2[0]);
     arr2[0] = 3;
    }
  •  fct함수를 호출 하면서 배열의 이름을 인자로 전달하는데 이때 배열의 이름 즉, 배열의 주소를 전달하는 것이다.
  1. #include <stdio.h>
  2. int ArrAddr(int *pArr, int n);
  3. int main(void)
    {
     int arr[10] = {1,2,3,4,5,6,7,8,9,10};
     int SumOfArr;
  4.  SumOfArr = ArrAddr(arr,sizeof(arr)/sizeof(int));
     printf("배열의 총합 : %d\n",SumOfArr);
  5.  return 0;
    }
  6. int ArrAddr(int *pArr, int n)
    {
     int sum = 0;
     int i;
     for (i =0;i<n;i++)
     {
      sum += pArr[i];
     }
     return sum;
    }
  • 위의 소스는 배열과 함수 호출의 관계를 잘 알려준다. (배열에 있는 각 요소들의 합을 계산해서 그 결과를 반환하는 함수를 정의한 예제이다.)

 

  • 배열을 인자로 전달받는 함수의 또 다른 선언
  1. #include <stdio.h>
  2. int MaxVal(int pArr[],int n);
  3. int main()
    {
     int arr[10] = {4,8,3,7,2};
  4.  int max;
  5.  max = MaxVal(arr, sizeof(arr)/sizeof(int));
  6.  printf("최대값 : %d\n",max);
     return 0;
    }
  7. 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;
    }
  •  위의 소스는 최대값을 구하는 소스이다.

    • int pArr[]는 무엇일까?  이것은 *pArr와 같은 것이다. 다만 저렇게 선언 한 것은 배열을 전달 했다고 명확하게 보여주려고 한 것 뿐이다.

II. Call-By-Value와 Call-By-Reference

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

    •  Call-By-Value는 기본 호출 방식이 값의 복사이다.
  1.  #include <stdio.h>
  2. void swap(int a,int b);
  3. int main(void)
    {
     int val1 = 10;
     int val2 = 20;
  4.  swap(val1,val2);
  5.  printf("val1 : %d\n",val1);
     printf("val2 : %d\n",val2);
  6.  return 0;
    }
  7. void swap(int a,int b)
    {
     int temp = a;
     a = b;
     b= temp;
  8.  printf("a : %d\n",a);
     printf("b : %d\n",b);
    }
  •  위의 소스를 보면 swap으로 바꾸어도 값만 복사해서 바꾼거라 메인에서 출력하면 고대로 이다.

    • 그래서 메인에서도 바꾸려면 Call-By-Regerence를 쓰면 된다.
  • Call-By-Reference(참조에 의한 호출)

    • 원래 C에서는  Call-By-Reference의 개념은 없다고 하네요. 그렇게 보이게 하려고 소스를 짠거라는 군요
  1. #include <stdio.h>
  2. void swap(int *a,int *b);
  3. int main(void)
    {
     int val1 = 10;
     int val2 = 20;
  4.  swap(val1,val2);
  5.  printf("val1 : %d\n",val1);
     printf("val2 : %d\n",val2);
  6.  return 0;
    }
  7. void swap(int &a,int &b)
    {
     int temp = *a;
     *a = *b;
     *b = temp;
  8.  printf("a : %d\n",a);
     printf("b : %d\n",b);
    }
  • 위의 소스는 Call-By-Value와 다른 점은 주소값을 사용했다는 점이다.

    • 주소값으로 교환을 하기 때문에 main에서도 바뀌어 보인다.

 

  • 이제는 알 수 있다! scanf 함수 호출시 &를 붙이는 이유

    • scanf 함수 내에서 지역 변수에 접근하기 위해서는 해당 변수의 주소를 알아야 하기 때문에 &를 붙인다.
    • 다만 문자열 일때는 배열 이름 이나 포인터는 배열의 주소를 나타내므로 붙일 필요가 없다.

III. 포인터와 const 키워드

  • 포인터가 가리키는 변수의 상수화
  1. int a = 10;
  2. const int* p = &a;
  3. *p = 30;   // error
  4. a = 30;
  •  위 소스는 *p를 상수화한 소스인데 즉, *p가 가리키는 변수의 값을 못 바꾸게 한다.

    • 더 자세히 말하면 *p를 통해서 변수의 a의 값을 변경하는 것만 막은 것이다.

 

  • 포인터 상수화
  1. int a = 10;
  2. int b = 20;
  3. int* const p = &a;
  4. p = &b;    //error
  5. *p = 30;   //ok
  •  위 int* const p는 상수값은 바꿀수 있지만 주소값을 못 바꾸게 한다.
  1. int a = 10;
  2. int b = 20;
  3. const int* const p = &a;
  4. p = &b;    //error
  5. *p = 30;     //error
  •  이번에는 const int* const p 이다. 위의 소스들을 합친거라고 보면 된다.

    • 즉, 상수값도 못 바꾸고, 주소값도 못 바꾼다는 것이다.

 

  • const를 사용하는 이유
  1. #include<stdio.h>
  2. float PI = 3.14;
  3. int main()
  4. {
  5. float rad;
  6. PI = 3.07;
  7. scanf("%f",&rad);
  8. printf("원의 넚이 : %f\n",rad*rad*PI);
  9. return 0;
  10. }
  • 위의 소스를 보면 PI를 3.14로 정의 했는데 메인에서 또 다르게 정의를 해버렸다. 이것을 모르고 컴파일 하면 당연히 다른 답이 나오게된다.

    • 지금은 소스가 짧아서 오류를 알기 쉽지만 엄청나게 긴 소스를 보게 되면 알기 힘들 뿐더러 컴파일은 오류메시지를 보여주지 않는다.
    •  위와 같은 실수를 해도 컴파일이 오류를 띄우려면 아래와 같이 하면 된다.
  1. #include<stdio.h>
  2. const float PI = 3.14;
  3. int main()
  4. {
  5. float rad;
  6. PI = 3.07;
  7. scanf("%f",&rad);
  8. printf("원의 넚이 : %f\n",rad*rad*PI);
  9. return 0;
  10. }
  •  이런 식으로 소스를 짜면 PI가 값이 변경 되려고 하면 컴파일이 오류를 알려준다.

문제

14 -1

문제1

사용자로부터 정수를 하나 입력받아서 변수 a에 저장한다. 입력받은 값의 제곱을 계산해서 다시 a에 대입해 주는 프로그램을 구현해 보자. 입력받은 값의 제곱을 계산하는 함수를 독립적으로 구현해서 main 함수가 이를 호출하는 형식으로 구현하기로 하자 (두가지 방법으로 함수를 구현할 수 있다.)

 

문제2

두개의 값을 변경 바꾸는 Call-By-Reference 형식의 swap 함수를 공부하였다. 이번에는 변수 a,b,c가 지니는 값을 다음과같이 변경시키는 swap함수를  구현하라.

 

14 -2

문제1

다음 함수의 정의를 보자. 인자로 전달되는 정보를 참조해서 int형 배열의 전체 요소를 출력하는 함수이다.

void print(const int* arr, int size)

{

int i;

for(i=0;i<size;i++)

printf("%d",arr[i]);

}

위 함수에서 매개 변수 arr 선언시 const 키워드를 사용한 이유는 어디에 있겠는가?

 

문제2

다음 예제는 문제를 지니고 있다 컴파일 하면서 문제점을 찾고, 왜 문제가 되는지 결론을 내가

 #include <stdio.h>

void print(const int* ptr);

int main()
{
 int a = 10;
 int *p = &a;
 print(p);
 return 0;
}
void print(const int* ptr)
{
 printf("%d\n",*ptr);
 int *p = ptr;
 *p = 20;
}

'개발 및 관련 자료 > C' 카테고리의 다른 글

[C] 17. 포인터의 포인터  (0) 2013.05.12
[C] 16. 다차원 배열  (0) 2013.05.12
[C] 13. 포인터와 배열  (0) 2013.05.12
[C] 12. 포인터의 이해  (0) 2013.05.12
[C] 11. 1차원 배열  (0) 2013.05.12
Comments