Chapter 2-2. 코드의 흐름 제어 : 함수, ref, out
카테고리: C Sharp
태그: C Sharp Programming
인프런에 있는 Rookiss님의 강의 Part1: C# 기초 프로그래밍 입문 를 듣고 정리한 필기입니다. 😀
👱♀️ 함수
Call by Value
- Call by Value 👉
a
의 값을 매개변수 AddOne 함수 중괄호 안에서만 수명을 가지는number
에 넘겨준다. 즉,a
의 값을 복사하여number
에게 넘겨준 것 뿐이라number
값이 변해도a
값에는 전혀 변화가 없다. 따라서 0 이 출력된다.number
는a
와 동일한 값을 가진 것 뿐인 별개의 메모리를 가진다.class Program { static void AddOne(int number) { number = number + 1; } static void Main(string[] args) { int a = 0; Program.AddOne(a); Console.WriteLine(a); // 0 출력 } }
Call by Reference
- Call by Reference 👉
a
의 값이 아닌a
메모리 자체를 AddOne 함수 중괄호 안에서만 수명을 가지는number
와 공유한다. 따라서number
값이 변하면a
값도 변한다. 그래서a
를 출력하면 1이 출력될 것이다. 둘은 동일한 메모리를 참조한다.class Program { static void AddOne(ref int number) { number = number + 1; } static void Main(string[] args) { int a = 0; Program.AddOne(ref a); Console.WriteLine(a); // 1 출력 } }
class Program
{
static void AddOne(ref int number)
{
number = number + 1;
}
static int AddOne2(int number)
{
return number + 1;
}
static void Main(string[] args)
{
int a = 0;
Program.AddOne(ref a);
a = Program.AddOne2(a);
Console.WriteLine(a); // 2 출력
}
}
Program.AddOne(ref a);
1️⃣ 이 방법은 원본 a
를 바꿀 수 있는 특성을 가진다. 사본 생성 과정이 없는 것은 효율적이지만 원본을 꼭 변경시킨다는 점도 있다. 따라서 경우에 따라 효율성이 결정될 것이다.
a = Program.AddOne2(a);
2️⃣ 디자인 상으론 이 방법이 더 좋다. 원본 a
를 바꾸지 않으면서 b = Program.AddOne2(a)
이렇게 다른 변수에도 리턴시킬 수도 있다. 단 입력 크기가 아주아주 커서 사본 생성에 부담이 따를 때엔 이 방법은 좋지 않을 듯 하다.
디폴트 매개 변수 in C#
class Program
{
static int Add(int a, int b, int c = 0, float d = 1.0f, double e = 3.0)
{
return a + b + c;
}
static void Main(string[] args)
{
Program.Add(1, 2, d:2.0f);
}
}
- 매개 변수
c
,d
,e
는 인수를 넘기지 않더라도 각각의 디폴트 값으로 설정된다. - C++ 에선 인수를 넘길 때 꼭 매개 변수와 대응되게 자리를 맞춰주어야 했지만 C# 에선 위와 같이
d
매개변수에 대해선 인수를 따로 넘겨주고 싶다면d:2.0f
와 같이 넘길 수 있다.
👱♀️ ref & out
ref
ref
는 Call by Reference 로 받기 위한 키워드다.
- 자료형 보다도 앞에 쓰인다.
ref int a
- 매개 변수는
&
타입이라도 인수에까지&
을 붙일 필요는 없었던 C++ 문법과는 다르게 C# 에선 넘겨주는 ✔인수까지 꼭ref
를 붙여주어야 한다. 매개 변수가ref int number
로 선언되어 있다면 인수도 마찬가지로 꼭ref a
로 넘겨주어야 한다.
class Program
{
static void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
static void Main(string[] args)
{
int num1 = 1;
int num2 = 2;
Program.Swap(ref num1, ref num2);
Console.WriteLine(num1); // 2 출력
Console.WriteLine(num2); // 1 출력
}
}
out
ref
라는 똑같다. Call by Reference. 매개 변수에 저장을 강제하는ref
라고 생각하면 된다.
- 매개 변수가
ref
인 경우- 매개 변수에 값을 저장(write)하지 않고 그저 읽기(read)만 하더라도 문법적 오류 전혀 없다.
- 즉 매개변수를 call by reference 로 인수의 메모리를 참조하기로 해놓고는 아무런 사용도 안해도 문제가 전혀 없다.
- [함수 외부] <-> [함수 내부] 양방향으로 통신하기 위해서 데이터 참조를 주고 받기 위한 개념
읽기
+쓰기
가능. 사용하지 않아도 됨.
- 함수 내부/외부 사이에 데이터를 빠르게 넘겨주기 위해 사용.
- 반드시 초기화가 되어 있는, 메모리가 비어 있지 않은 변수에만
ref
를 사용할 수 있다. 초기화 되지 않은 변수에ref
붙이며 컴파일 오류가 난다. 함수 내부에서 그냥 읽기만 할 수도 있기 때문에 런타임 에러의 위험이 생길 수 있음.
- 매개 변수에 값을 저장(write)하지 않고 그저 읽기(read)만 하더라도 문법적 오류 전혀 없다.
- 매개 변수가
out
인 경우- 매개 변수에 어떤 값을 저장(write)하는 활동이 전혀 없다면 컴파일 오류를 발생시킨다. 반드시 참조 매개변수를 함수 내부에서 write 시켜야 한다. 단순 읽기만 해서는 안된다.
- call by reference 매개 변수가 참조 중인 메모리의 사용을 강제하기 때문에
ref
와 달리 초기화를 전혀 하지 않은 변수를 인수로서out
매개 변수에 넘기는 것이 가능하다.- 함수가 끝나면 넘겨준 인수에도 Call by Reference를 통해 어떤 값이 반드시 저장될 것이라는게 보장되기 때문이다.
out
이 이를 강제해서 !
- 함수가 끝나면 넘겨준 인수에도 Call by Reference를 통해 어떤 값이 반드시 저장될 것이라는게 보장되기 때문이다.
- [함수 내부]에서 작업한 최종 결과물을 [함수 외부] 쪽으로 넘겨주는 일방적 통행 (
out
이름 답게!)- 함수 내부에서 값을 바꿔서 외부에 전달. 참조 중인 외부 메모리에도 영향을 끼침.
- 반드시
쓰기
과정이 필요
- 함수 내에서의 로직으로 매개 변수 write을 진행한 최종 데이터를 함수 외부로 넘겨주기 위한 용도로 사용.
이렇게 out
이 붙은 매개 변수에 아무런 값도 저장하지 않는다면 이렇게 컴파일 오류가 뜬다. out
매개변수에 저장을 강제함! ref
였으면 아무런 문제가 없다. 아래와 같이 out
매개 변수에 값을 저장하면 오류가 사라진다.
class Program
{
static void Divide(int a, int b, out int result, out int result2)
{
result = a / b;
result2 = a % b;
}
static void Main(string[] args)
{
int num1 = 10;
int num2 = 3;
Program.Divide(10, 3, out num1, out num2);
Console.WriteLine(num1); // 3 출력
Console.WriteLine(num2); // 1 출력
}
}
ref
와 마찬가지로 인수에도 모두 out
을 붙여주어야 한다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기