C# 05장. 메소드와 인자
학습 목표 메소드를 이해하고 만들 수 있다 효과적인 메소드 호출의 방법을 이해한다 중첩 메소드와 재귀 메소드를 이해한다 메소드와 변수와의 관계를 이해한다 메소드에 인자를 전달하여 호출할 수 있다 메소드 오버로딩을 이해한다.
목차 메소드의 정의와 호출 메소드와 변수 메소드 인자 전달하기 메소드 오버로딩
1. 메소드의 정의와 호출 메소드(method)란? 정해진 작업을 수행하기 위해 그룹으로 묶어, 이름을 붙인 명령문의 집합을 메소드라 한다. 접근지정자 리턴형 함수이름(인자 리스트) { 명령1; 명령2; …… return 리턴 값; } static void Main(string[] args) { Console.WriteLine("Hello…?"); }
메소드 1. 메소드의 정의와 호출 접근지정자 : 함수를 호출할 수 있는 범위를 지정한다. 리턴형 : 함수가 돌려주는 값의 형식을 지정한다. 함수이름 : 함수를 호출할 때 사용하는 함수의 이름 인자 리스트 : 인자 리스트란 함수에게 실행 전에 전달되는 변수를 의미하며, 변수의 형식과 실제 값이 전달된다. 명령문 : 실제 함수가 실행하는 문장 리턴 값 : 함수가 종료될 때 되돌려주는 값으로 위에 선언한 리턴형에 맞는 형식의 값이어야 한다. 리턴 값은 없을 수도 있으며 이때의 리턴형은 void로 선언한다
using System.Collections.Generic; using System.Text; 1. 메소드의 정의와 호출 메인 함수의 해석 using System; using System.Collections.Generic; using System.Text; namespace ConsoleApplication1 { class Program static void Main(string[] args) Console.WriteLine("Hello..?"); } static : 접근 지정자 void : 리턴형(리턴값 없음) Main : 함수명 (string[] args) : 인자목록 Console.WriteLine(“Hello…?”) : 명령문 static Main()함수가 정적 메소드란 의미
1. 메소드의 정의와 호출 메소드 실행하기 using System; namespace ConsoleApplication { public class Example static void MethodTest() Console.WriteLine("여기는 MethodTest 입니다."); } static void Main(string[] args) Console.WriteLine("여기는 Main 메소드입니다."); MethodTest(); System.Console.WriteLine("MethodTest 메소드를 호출하였습니다.");
메소드의 호출 1. 메소드의 정의와 호출 같은 클래스 내에서의 호출 : 메소드명(); 다른 클래스 내에서의 호출 : 클래스명.메소드명(); 즉, 다른 클래스내의 메소드를 사용하기 위해서는 클래스명 + 점연산자(.) + 메소드명()
1. 메소드의 정의와 호출 메소드 호출 using System; namespace MethodExample { public class A public static void MethodA() System.Console.WriteLine("MethodA() in class A"); } public class B public static void Main(string[] args) A.MethodA(); 클래스 A의 MethodA() 호출
중첩 메소드(nested method) 1. 메소드의 정의와 호출 메소드를 호출할 경우, 호출된 메소드 내에서 또 다른 메소드를 계속 호출해서 사용하는 메소드 중첩 메소드를 사용할 때는 메소드끼리 서로를 계속 호출하여, 프로그램이 종료되지 않는 무한루프에 빠지지 않도록 조심해야 한다
1. 메소드의 정의와 호출 중첩 메소드 사용 using System; namespace NestedMethodExample { public class NestedMethod public static void MethodA() System.Console.WriteLine("메소드 A입니다."); } public static void MethodB() MethodA(); System.Console.WriteLine("메소드 B입니다."); public static void Main(string[] args) MethodB();
1. 메소드의 정의와 호출 중첩 메소드 사용 F11 이용하여 순서 확인하기
재귀 메소드 1. 메소드의 정의와 호출 자기자신을 호출하는 메소드 로서, 같은 반복된 작업이 필요한 경우를 구현한 메소드 (예제) 재귀메소드를 이용하여 N!(factorial) 구하기 N-팩토리얼 = N * (N-1) * (N-2) * (N-3) * ……. * 1
1. 메소드의 정의와 호출 재귀메소드 사용(팩토리얼 구하기) using System; namespace RecursionMethod { public class RecursionMethod public static ulong Factorial(ulong number) if (number <= 1) return 1; else return number * Factorial(number - 1); } public static void Main(string[] args) ulong nfact = Factorial(5); Console.WriteLine("5 * 4 * 3 * 2 * 1 = " + nfact);
지역변수(local variables) 2. 메소드와 변수 지역변수(local variables) 지역 변수란 메소드 내에서 선언된 변수 메소드가 실행될 때 변수를 저장하기 위한 메모리가 생성된다. 선언된 메소드 내부에서만 사용이 가능하다. 메소드의 실행이 종료될 때 메모리가 해제된다. 변수를 선언한 후, 초기 값을 부여하는 초기화가 꼭 필요하다
2. 메소드와 변수 지역변수 예제 namespace Var1 { using System; public class LocalVar public static void Main(string[] args) int localVar = 10; int unInitVar; Console.WriteLine(localVar); Console.WriteLine(unInitVar); //에러 발생! } 지역변수를 초기화 하지 않음 메소드 내에서 사용하는 모든 지역 변수는 초기화 하여야 함.
2. 메소드와 변수 클래스 변수 클래스 내에 하나만 존재하며, 클래스 내의 모든 개체가 사용할 수 있는 변수 (static 키워드 사용) 클래스가 로딩될 때 변수를 저장하기 위한 메모리를 생성한다. 클래스 이름을 이용하여 접근한다. 모든 클래스 내의 인스턴스(개체)가 공유한다. 값을 지정하지 않은 경우에 자동으로 0으로 초기화한다
2. 메소드와 변수 클래스 변수 사용 예제 using System; public class Example { public static int classvari = 0; public Example() classvari++; } public static void Main(string[] args) Example e1 = new Example(); Example e2 = new Example(); Console.WriteLine(Example.classvari);
인스턴스 변수 2. 메소드와 변수 using System; public class Example { 클래스 멤버로 선언되어 객체가 생성될 때마다 메모리가 배정되는 변수 using System; public class Example { public int vari = 0; public Example() vari++; } public static void Main(string[] args) Example e1 = new Example(); Example e2 = new Example(); Console.WriteLine(e1.vari); Console.WriteLine(e2.vari);
3. 메소드 인자 전달하기 메소드를 호출할 때는 메소드명과 ()기호로 둘러 쌓인 인자 목록을 사용 인자 목록을 이용해서 호출하는 쪽에서 메소드로 인자 값을 넘겨 메소드 에서 이를 사용할 수 있게 한다. 인자로 사용하는 변수의 형식에 따라 인자는 값형 변수, 참조형 변수로 나눌 수 있으며, 인자 전달 방법은 이러한 인자의 형식에 따라 달라진다.
int Sum(int x, int y) { int c = x + y; return c; } 3. 메소드 인자 전달하기 인자 전달 방법 1 값에 의한 전달(인자가 값형 변수일 때) int a = 3; int x = a =3; 값 복사에 의한 전달 int b = 5; int y = b = 5; Sum(a, b) int Sum(int x, int y) { int c = x + y; return c; }
3. 메소드 인자 전달하기 인자 전달 방법 1 값에 의한 전달(인자가 값형 변수일 때) namespace Param1 { using System; public class ParamValue public void Increase(int n) n++; Console.WriteLine("호출 후 n : {0} ", n); } public static void Main(string[] args) int i = 10; ParamValue pv = new ParamValue(); Console.WriteLine("호출 전 i : {0} ", i); pv.Increase(i); Console.WriteLine("호출 후 i : {0}", i);
public class ParamTest { public static void Increase(ParamRef varRef) 3. 메소드 인자 전달하기 인자 전달 방법 2 값에 의한 전달(인자가 참조형 변수일 때) namespace Param2 { using System; public class ParamRef { public int myVal = 10; } public class ParamTest { public static void Increase(ParamRef varRef) varRef.myVal++; Console.WriteLine("호출 후 varRef.myVal : {0}", varRef.myVal); } public static void Main(string[] args) ParamRef pr = new ParamRef(); Console.WriteLine("호출 전 pr.myVal : {0}", pr.myVal); ParamTest.Increase(pr); //pr을 인자로 Increase() 메소드 호출 Console.WriteLine("호출 후 pr.myVal : {0}", pr.myVal); 1. varRef ==> (매개변수) ParamRef.varRef <==풍선 도움말 2. myVal ==> int ParamRef.myVal <== 풍선 도움말 3. Increase() 메소드를 통해 인자로 넘어온 ParamRef의 클래스형 변수 varRef의 값을 1 만큼 증가 시킨다. 4. 참조형 변수인 varRef는 인자인 pr 이 저장된 메모리를 참조한다. 5. varRef.myVal이 1만큼 증가하면 pr.myVal도 1 증가 인자 : ParamRef 클래스형 변수 varRef ParamRef 클래스형 변수 pr를 생성 pr은 특정 값을 포함한 변수가 아닌 ParamRef 클래스를 참조하는 참조형 변수
int Sum( ref int x , ref int y) { int z = x + y; return z; } 3. 메소드 인자 전달하기 인자 전달 방법 3(방법 2와 같은 원리) 참조에 의한 전달(인자가 값형 변수일 때) 전달하는 인자의 변수명 앞에 ref 키워드를 사용 Sum(ref a, ref b); int a = 3 int b = 5 참조 매개변수 int Sum( ref int x , ref int y) { int z = x + y; return z; }
3. 메소드 인자 전달하기 인자 전달 방법 3(방법 2와 같은 원리) 참조에 의한 전달(인자가 값형 변수일 때) 전달하는 인자의 변수명 앞에 ref 키워드를 사용 namespace Param3 { using System; public class ParamValue public void Increase(ref int n) n++; } public static void Main(string[] args) int i = 10; ParamValue pv = new ParamValue(); Console.WriteLine("호출 전 : {0}", i); pv.Increase(ref i); Console.WriteLine("호출 후 : {0}", i);
인자로 사용할 변수가 참조형 변수이고, 전달 방식도 참조에 의한 전달방식 3. 메소드 인자 전달하기 인자 전달 방법 4 참조에 의한 전달(인자가 참조형 변수일 때) 인자로 사용할 변수가 참조형 변수이고, 전달 방식도 참조에 의한 전달방식 namespace Param4 { using System; public class ParamRef public int myVal = 10; } public class ParamTest public static void Increase(ref ParamRef varRef) varRef.myVal++; public static void Main(string[] args) ParamRef pr = new ParamRef(); Console.WriteLine("호출 전 : {0}", pr.myVal); ParamTest.Increase(ref pr); Console.WriteLine("호출 후 : {0}", pr.myVal);
3. 메소드 인자 전달하기 인자 전달 방법 5 출력인자 방식 ; 메소드를 호출할 때 사용하는 인자 값을 호출 받는 메소드의 실제 인자에게 넘겨주는 방식 ; 키워드 : out ; 참조방식에 의한 전달과 같은 동작을 하지만, 호출받은 메소드로부터는 아무런 값도 받지 않는다. 즉, 호출 받은 메소드의 결과 값의 리턴형은 void이다. ; 메소드는 보통 return문에 의해 값 하나만을 돌려주므로, 값 여러 개를 돌려 받고 싶은 경우에 출력인자 방식을 사용한다. 예제 ?
참조로 값을 넘길 때 참조할 대상을 초기화할 필요는 없 다. 3. 메소드 인자 전달하기 인자 전달 방법 5 출력인자 방식 out 키워드 참조에 의한 전달을 할 때 사용하는 키워드 참조로 값을 넘길 때 참조할 대상을 초기화할 필요는 없 다. ref 와 out 키워드 ref : 참조할 변수는 반드시 초기화되어 있어야 한다. out : 참조할 변수가 반드시 초기화될 필요는 없다. out 키워드 사용하는 경우 함수로부터 값을 얻어낼 때 주로 사용한다. 그렇기 때문에 초기화를 할 필요가 없는 것이다.
3. 메소드 인자 전달하기 출력인자 방식의 인자 전달 namespace Param5 { using System; public class ParamValue public void Increase(out int n) n = 11; } public static void Main(string[] args) int i; // n 이 항상 11인 것을 호출할 경우에 초기화 필요없다. ParamValue pv = new ParamValue(); pv.Increase(out i); Console.WriteLine("호출후 값 : {0}", i);
3. 메소드 인자 전달하기 인자 전달 방법 6 가변길이 인자 방식 가변길이 인자 방식이란, 호출하는 메소드에 지정하는 인자 목록의 길이가 고정적이지 않고 상황에 따라 변화하는 호출을 지원하는 인자 가변길이 인자 방식의 특징 params 키워드를 사용해서 정의한다. params 키워드를 사용해서 전달된 가변 길이 인자는 값에 의한 전달 방식으로 인식되며, 메소드의 인자 값이 메소드 호출 쪽의 인자 값으로 전달된다.
3. 메소드 인자 전달하기 가변길이 인자 방식 인자 전달 namespace Param6 { using System; public class VariableLength public int VarMethod(params int[] arr) int sum = 0; for (int i = 0; i < arr.Length; i++) sum = sum + arr[i]; } return sum; public static void Main(string[] args) int result; VariableLength vl = new VariableLength(); result = vl.VarMethod(10, 20); // 인자 2개 Console.WriteLine(result); result = vl.VarMethod(1, 2, 3, 4); // 인자 4개
4. 메소드 오버로딩 클래스 하나 안에서 같은 이름의 메소드를 여러 개 선언 메소드 구분 규칙 static void testMethod{ ... } static void testMethod(int n) { static void testMethod(int if, int j) { public static void Main(string[] args) { testMethod(3);
4. 메소드 오버로딩 namespace Overloading { using System; public class Overloading public void PrintValue(int i) Console.WriteLine("하나의 정수가 인자인 메소드"); } public void PrintValue(int i, int j) Console.WriteLine("두개의 정수가 인자인 메소드"); public void PrintValue(double f) Console.WriteLine("하나의 실수가 인자인 메소드"); public static void Main(string[] args) Overloading mo = new Overloading(); mo.PrintValue(3); mo.PrintValue(2.1); mo.PrintValue(3, 4);
요약 메소드란 클래스에 소속된 함수로서 그룹으로 묶여진 명령문의 집 합이다. 메소드의 호출은 메소드명과 ()로 둘러쌓인 인자 목록으로 구분해 서 호출한다. 중첩 메소드란 호출 받은 메소드로서 또 다른 메소드를 호출 하는 것이다. 이때 무한루프에 빠지지 않도록 조심해야 한다. 재귀 메소드란 자기 자신을 스스로 호출하는 메소드로, 반드시 종 료 조건이 암시되어야 한다. 지역 변수란 메소드 내부에서 선언된 변수로서 반드시 초기화한 후에 사용해야 한다.
요약 클래스 변수는 클래스 내에 단 하나만 존재하며, 모든 클래스 내의 객 체가 공유해서 사용할 수 있는 변수다. static 키워드로 지정된다. 인스턴스 변수는 클래스 멤버로 정의된 변수이며, 인스턴스가 생성될 때마다 메모리를 배정받는다. 모든 메소드에서 공유하는 변수다. 인자의 전달 방식에는 값에 의한 전달 방식, 참조에 의한 전달 방식, 출력인자 방식, 가변길이 인자 방식 등이 있다. 메소드 오버로딩이란 하나의 클래스 내에 같은 이름의 메소드 여러 개를 정의해서 사용하는 것을 말하며, 인자 목록이 서로 달라야 호출 할 때 구분된다. 서로 다른 클래스에 존재하는 같은 이름의 메소드는 메소드 오버로딩이 아니다.
값과 참조(보충 자료) 값과 참조타입의 차이는 데이터가 저장되는 메모리상의 위치임 값과 참조타입의 차이는 데이터가 저장되는 메모리상의 위치임 값 타입 : 크기가 작고 고정적이기 때문에 스택에 생성됨 참조 타입 : 크고 가변적이기 대문에 동적으로 관리되는 힘영역에 생성됨
참조 타입 : 반드시 new 연산자로 메모리를 할당 받아 초기화 해야 한다 값과 참조(보충 자료) 값 타입 : 선언 즉시 사용 가능 참조 타입 : 반드시 new 연산자로 메모리를 할당 받아 초기화 해야 한다 int value ; value = 3 ; // 가능 int[] ar ; ar [] = 4 ; // 에러 value 는 선언문에 의해 데이터를 저장할 수 있는 4바이트의 메모리를 확보 하므로 바로 값을 대입하거나 읽을 수 있다. ar 은 정수형의 배열로 선언했는데 이 선언문으로는 배열 요소를 저장할 수 있는 메모리를 확보하지 못한다. 선언만 한 참조 타입은 배열을 가리킬 수 있는 참조자 일 뿐이며 null로 초기화 되므로 아직 데이터를 저장할 수 없다. ar 참조 변수는 존재 하지만 ar[3] 이라는 배열 요소는 존재하지 않는다. ar = ne int[10]; 이 문장을 정의하여 힙에 충분한 크기의 메모리를 할당해야 한다.
데이터 저장에 사용된 기억 장소 소멸 시기가 다르다. 값 타입 : 변수를 선언한 메서드가 종료될 때 자동으로 소멸 값과 참조(보충 자료) 데이터 저장에 사용된 기억 장소 소멸 시기가 다르다. 값 타입 : 변수를 선언한 메서드가 종료될 때 자동으로 소멸 참조 타입 : 더 이상 참조하는 변수가 없을 때 가비지 컬렉터에 의해 소멸된다. static void Method() { int value = 3; int[] ar = new int [10]; } value : 지역 변수로 선언되었고, Method기 리턴하기 직전에 소멸된다. ar : 지역변수이므로 Method기 리턴되면 소멸되지만 ar이 가리키던 배열은 힙에 그대로 남아 있다. 배열을 참조하는 변수는 사라지지만 배열 자체는 여전히 남아 있다. 이 배열을 삭제하는 것은 가비지 컬렉터이다.
참조 타입의 대입 : 참조자가 하나 더 늘어남(메모리가 추가로 할당되는 것이 아님) 값과 참조(보충 자료) 값 타입과 참조 타입의 대입 값 타입의 대입 : 복사가 됨 참조 타입의 대입 : 참조자가 하나 더 늘어남(메모리가 추가로 할당되는 것이 아님) using System; class CSTest { static void Main() int value = 3, vcopy; vcopy = value; vcopy = 4; Console.WriteLine("value={0},vcopy={1}", value, vcopy); int[] ar, arcopy; ar = new int[] { 1, 2, 3, 4, 5 }; arcopy = ar; arcopy[1] = 1234; Console.WriteLine("ar[1]={0},arcopy[1]={1}", ar[1], arcopy[1]); }
ar 1 2 3 4 5 arcopy null ar 1 3 4 5 arcopy int[] ar, arcopy; 값과 참조(보충 자료) int[] ar, arcopy; ar = new int[] { 1, 2, 3, 4, 5 }; arcopy = ar; arcopy[1] = 1234; ar 1 2 3 4 5 arcopy null ar 1 1234 3 4 5 arcopy
참조 타입 : 힙상의 번지를 비교하기 때문에 내용이 완 전히 같더라도 위치가 다르면 같지 않은 것으로 평가 값과 참조(보충 자료) 변수를 비교하는 방법 값 타입 : 기억된 데이터로 비교 참조 타입 : 힙상의 번지를 비교하기 때문에 내용이 완 전히 같더라도 위치가 다르면 같지 않은 것으로 평가 using System; class CSTest { static void Main() int value = 3, vcopy = 3; Console.WriteLine("값 타입의 경우 : " + (value == vcopy ? "같다" : "다르다")); int[] ar = { 1, 2, 3, 4, 5 }; int[] arcopy = { 1, 2, 3, 4, 5 }; Console.WriteLine("참조 타입의 경우 : " + (ar == arcopy ? "같다" : "다르다")); }
string은 참조 타입인데 예외적으로 동작함 값과 참조(보충 자료) 구조체 : 값 타입 클래스 : 참조 타입 string은 참조 타입인데 예외적으로 동작함 using System; class CSTest { static void Main() string s1 = "텔레토비"; string s2 = s1; s2 = "마시미로"; Console.WriteLine("s1={0}, s2={1}", s1, s2); string s3 = "로보트 태권 V"; string s4 = "로보트 태권 V"; Console.WriteLine("문자열의 경우 : " + (s3 == s4 ? "같다" : "다르다")); } 문자열은 참조 타입임에도 값 타입처럼 동작한다.
값과 참조(보충 자료) s1의 사본 s2를 만들어