[C] 데이터 보내주세요.

장세민·2022년 10월 9일
0

📝 TIL

목록 보기
23/40

📌 함수의 데이터 공유 방법

Before Starting

프로그램은 데이터명령으로 이뤄지는데,
컴퓨터는 데이터를 명령으로 처리하기 위해 특정 기능의 명령을 묶어서 함수로 만들어 사용한다.

둘 이상의 함수로 구현된 프로그램은 함수 간에 데이터를 공유하기 위해 다양한 방법을 사용한다.

함수끼리는 데이터를 어떻게 공유하는 지 한 번 알아보자.


📖 값을 복사해서 전달하는 방법

함수를 호출할 때 필요한 데이터를 전달하는 가장 일반적인 방법은
값을 복사해서 전달하는 것이다.

호출된 함수가 반환된 이후에도 호출한 함수에 있는 변수의 값은 변하지 않는다.

  1. # include <stdio.h>
  2.  
  3. void add_ten(int a);
  4.  
  5. int main(void)
  6. {
  7. int a = 10;
  8.  
  9. add_ten(a);
  10. printf("a: %d\n", a);
  11.  
  12. return 0;
  13. }
  14.  
  15. void add_ten(int a)
  16. {
  17. a = a + 10;
  18. }

9행에서 변수 a를 인수로 주고 함수를 호출하는데,

a 값이 복사되어 함수에 전달되며
15행에서 매개변수 a를 위한 저장 공간이 별도로 할당되어 인수로 넘어오는 값을 저장한다.

그런데 실행결과를 보면,

값이 20이 아니라 10이다.
이는 매개변수 a의 메모리 주소에 저장된 값을 main 함수로 넘겨주지 않아서이다.

만약 main 함수의 변수 a가 증가하기를 원한다면

int add_ten(int a);		// 3행. 반환값이 있는 함수로 선언
...
	a = add_ten(a);		// 9행. 증가한 값을 반환하여 main 함수의 변수 a에 대입
...
int add_ten(int a)		// 15행. 반환값이 있는 함수로 정의
...
	return a;		// 17행. 다음 행에 반환 문장 추가

다음처럼 수정해주면 된다.

값을 복사하여 전달하는 방식은 호출하는 함수의 값을 바꿀 필요가 없는 경우에 사용한다.


📖 주소를 전달하는 방법

함수를 호출할 때 포인터 연산으로 처리할 변수의 주소를 넘기는 방법도 있다.
이는 호출된 함수에서 호출한 함수에 있는 변수의 값을 바꿀 수 있다.

  1. # include <stdio.h>
  2.  
  3. void add_ten(int *pa);
  4.  
  5. int main(void)
  6. {
  7. int a = 10;
  8.  
  9. add_ten(&a);
  10. printf("a: %d\n", a);
  11.  
  12. return 0;
  13. }
  14.  
  15. void add_ten(int *pa)
  16. {
  17. *pa = *pa + 10;
  18. }

9행에서 변수 a의 주소가 함수로 전달되며
15행에서는 포인터를 매개변수로 사용하여 받는다.

매개변수 pa에 간접 참조 연산자를 사용하면 main 함수에 있는 a를 사용할 수 있고 값을 바꿀 수도 있다.



📌 두 방법의 장단점

값을 복사해서 전달하는 방식주소를 전달하는 방식
장점원본 데이터 보존 가능원본 데이터 바꿀 때 유용
단점원본 데이터 수정 제한사용법 복잡, 고유 데이터 다룰때 사용 시 문제 가능성



💬 call by value와 call by reference

call by value : 함수를 호출할 때 변수의 값을 복사하여 인수로 주는 방식

# include <stdio.h>
 
void add_ten(int a);
 
int main(void)
{
	int a = 10;
 
	add_ten(a);
	printf("a: %d\n", a);
 
	return 0;
}
 
void add_ten(int a)
{
	a = a + 10;
}

이와 같이 다른 함수에서 변수의 값을 복사하여 인수로 주는 방식이다.

call by reference : 호출 함수의 변수를 피호출 함수에서 매개변수의 이름으로 직접 사용하는 방식

이 방식을 사용하면 하나의 저장공간을 서로 다른 함수에서 2개의 이름으로 쉽게 공유할 수 있다.

그러나 C언어에는 구현하는 문법 형식이 없고,
다만 간접 참조 연산을 통해 call by reference와 비슷한 효과를 낼 수 있지만,

결국 이 방법도 주소 값을 주고받으므로 call by value로 봐야할 것이다.



📖 주소를 반환하는 함수

반환값이 있는 함수는 호출한 함수로 값을 복사해서 반환한다.

지역 변수는 함수가 반환되면 저장 공간이 사라지므로
그 값을 복사하여 반환해야 호출한 함수에서 사용할 수 있다.

그러나 정적 지역 변수전역 변수처럼 변수의 저장공간이 계속 유지된다면 주소를 반환할 수 있다.

  1. # include <stdio.h>
  2.  
  3. int *sum(int a, int b);
  4.  
  5. int main(void)
  6. {
  7. int *resp;
  8.  
  9. resp = sum(10, 20);
  10. printf("두 정수의 합: %d\n", *resp);
  11.  
  12. return 0;
  13. }
  14.  
  15. int *sum(int a, int b)
  16. {
  17. static int res;
  18.  
  19. res = a + b;
  20.  
  21. return &res;
  22. }

호출하는 함수가 주소를 주고 호출하듯이 호출되는 함수도 주소를 반환할 수 있다.

sum 함수는 매개변수에 받은 두 정수를 더한 후 직접 반환하지 않고,
res 변수에 저장하고 res 변수의 주소를 반환한다.

호출한 함수에서는 그 값을 포인터에 저장하고 간접 참조 연산을 언제든지 사용할 수 있다.

이처럼 주소를 반환하는 함수를 만들 때는 주의사항이 있다.

🚨 반환값의 자료형은 반환값을 저장할 포인터의 자료형과 같다.

sum 함수는 int형 변수인 res의 주소를 반환하므로
그 값을 저장할 포인터는 int *형으로 선언해야 하며
sum 함수의 반환형도 int *형이 되어야 한다.

🚨 지역 변수의 주소를 반환하면 안된다.

일반 지역 변수는 함수가 반환되면 저장공간이 회수되므로 언제 재활용될지 알 수 없다.

profile
분석하는 남자 💻

0개의 댓글