메서드와 구조체1(2-6)
- C#에서 메서드와 구조체를 정의하고 사용하는 방법 이해
- 메서드를 호출하고 반환값과 매개변수 사용법, 오버로딩 이해
- 구조체를 생성, 필드와 메서드를 사용하는 방법 이해
메서드
- 메서드(Method)는 일련의 코드 블록으로, 특정한 작업을 수행하기 위해 서용되는 독립적인 기능 단위.
- 코드의 재사용성과 모듈화를 위해 사용되며 필요할 때 호출해 실행함
메서드의 역할과 중요성
- 코드의 재사용성
- 메서드를 사용하면 동일한 작업을 반복해서 구현하지 않아도 됨. 필요할 때 메서드를 호출해 작업 수행 가능
- 모듈화
- 메서드를 사용해 코드를 작은 단위로 분리하고 관리할 수 있음. 각 메서드는 특정한 기능을 수행하므로 코드의 구조가 더욱 명확해짐
- 가독성과 유지보수성
- 메서드를 사용하면 코드가 간결해지고 가독성이 좋아짐. 또한 코드 수정이 필요한 경우 해당 메서드만 수정하면 되므로 유지보수가 용이해짐
- 코드의 중복 제거
- 반복적인 작업을 메서드로 묶어서 사용하면 코드 중복을 방지할 수 있음
- 코드의 추상화
- 메서드를 통해 작업 단위를 추상화하고, 메서드 이름을 통해 해당 작업이 어떤 역할을 하는지 파악할 수 있음
메서드의 선언과 호출
메서드의 구조와 문법
[접근 제한자] [리턴 타입] [메서드 이름]([매개변수])
{
}
- 접근 제한자(Access Modifier): 메서드에 접근할 수 있는 범위를 지정함. 주로
public, private, protected 등을 사용
- 리턴 타입(Return Type): 메서드가 반환하는 값의 데이터 타입을 지정함. 반환 값이 없을 경우
void를 사용
- 메서드 이름(Method Name): 메서드를 호출하기 위해 사용하는 이름. 호출할 때 이 이름을 사용
- 매개변수(Parameters): 메서드에 전달되는 입력 값으로, 필요한 경우 0개 이상의 매개변수를 정의할 수 있음
- 메서드 실행 코드(Method Body): 중괄호({}) 안에다 메서드가 수행하는 작업을 구현하는 코드를 작성
public void SayHello()
{
Console.WriteLine("안녕하세요!");
}
public void GreetPerson(string name)
{
Console.WriteLine("안녕하세요, " + name + "님!");
}
public int AddNumbers(int a, int b)
{
int sum = a + b;
return sum;
}
메서드 호출 방법
- 메서드를 호출하기 위해서는 메서드 이름과 필요한 매개변수를 전달해야 함
[메서드 이름]([전달할 매개변수]);
AddNumbers(10, 20);
- 호출 시 전달되는 매개변수는 메서드의 매개변수, 순서, 타입이 일치해야 함
- 메서드는 호출되면 해당 메서드의 실행 코드를 수행하고, 필요한 경우 리턴값이 있다면 반환함
매개변수와 반환값
매개변수의 개념과 활용
- 매개변수는 메서드에 전달되는 입력값. 메서드 내에서 이 값을 활용해 원하는 작업을 수행 가능
- 매개변수는 메서드의 선언부에 정의되며, 필요한 경우 0개 이상의 매개변수를 정의할 수 있음
- 매개변수는 메서드 호출 시 전달되는 값에 따라 동적으로 결정되며, 호출 시에는 해당 매개변수의 값을 전달해야 함
void PrintFullName(string firstName, string lastName)
{
Console.WriteLine("Full Name: " + firstName + " " + lastName);
}
PrintFullName("John", "Doe");
반환값의 개념과 활용
- 반환값은 메서드가 수행한 작업의 결과를 호출자에게 반환하는 값
- 메서드의 리턴 타입에 지정되며, 해당 타입의 값을 반환해야 함
- 메서드 내에서 계산, 조작, 처리한 결과 등을 반환값으로 사용할 수 있음
int AddNumbers(int a, int b)
{
int sum = a + b;
return sum;
}
int result = AddNumbers(10, 20);
Console.WriteLine("Sum: " + result);
- AddNumbers에 int a, int b가 있다. a + b의 값을 sum에다가 넣고, sum을 int로 변환해서 반환함. 그리고 그걸 result에다가 저장하는 출력하는 구조
void 형식과 반환값이 없는 메서드
- void는 메서드의 리턴 타입으로 사용되며, 해당 메서드가 값을 반환하지 않음을 나타냄
- 반환값이 없는 메서드는 호출되면 메서드의 실행 코드를 수행한 후 호출자에게 반환하지 않음
void PrintMessage(string message)
{
Console.WriteLine("Message: " + message);
}
PrintMessage("Hello, World!");
사용 예시
void PrintLine()
{
for (int i = 0; i < 10; i++)
{
Console.Write("=");
}
Console.WriteLine();
}
static void Main(string[] args)
{
PrintLine();
}
- PrintLine 메서드를 void로 불러왔다. 안에는 반복문을 넣어줬다.
- 그리고 Main에 PrintLine를 넣으니 오류가 뜨는데, Main에만 static이 붙어서 그런 것. void PrintLine에도 static을 붙여주면 됨
- 실행해보면 ==========이 출력된다.
static void PrintLine()
{
for (int i = 0; i < 10; i++)
{
Console.Write("=");
}
Console.WriteLine();
}
static void PrintLine2(int count)
{
}
- 두 번째로 PrintLine2를 만들어줬다. 얘는 int count로 받아준다.
- 근데 count를 받아서 뭐 함? 매개변수를 받았으니까 일을 시키자.
static void PrintLine()
{
for (int i = 0; i < 10; i++)
{
Console.Write("=");
}
Console.WriteLine();
}
static void PrintLine2(int count)
{
for (int i = 0; i < count; i++)
{
Console.Write("=");
}
Console.WriteLine();
}
- count만큼 출력하겠다고 코드를 작성할 수 있다.
static void Main(string[] args)
{
PrintLine();
PrintLine2(20);
}
- 출력해 보면 PrintLine2(20)은 ==================== 이렇게 20개가 출력된다.
- 이런식으로 메서드를 매개변수를 활용해 발전시킬 수 있다.
- 나아가서 어떤 문자를 출력할 건지도 정할 수 있다.
static int Add(int a, int b)
{
return a + b;
}
- 세 번째로 간단한 함수를 만들어 보자.
- 매개변수도 준비되어 있고, 반환값도 준비되어 있다.
static void Main(string[] args)
{
PrintLine();
PrintLine2(20);
int result = Add(10, 20);
Console.WriteLine(result);
}
- Add(10, 20)을 result를 통해 출력해 보자.
- Add에 10과 20을 보내게 된다. 근데 이 10과 20이 직접 가는 게 아니라 a에 10을 복사해 주고, b에 20을 복사해 준다.
- 그럼 a와 b가 10과 20을 가지고 있어서 그 값들을 처리해서 진행하게 되는 것
- 그다음 식에 따라 더해진 값 30을 int형으로 변환해서 다시 돌려보내게 되는 것
- 그래서 최종적으로 result에 30이 들어가게 된다.
메서드와 구조체2(2-7)
메서드 오버로딩
오버로딩의 개념과 활용
- 오버로딩: 같은 이름의 메서드들을 다양하게 선언할 수 있는 것
- 메서드 오버로딩은 동일한 이름의 메서드를 다양한 매개변수 목록으로 다중 정의하는 개념
- 매개변수의 개수, 타입, 순서가 다른 여러 메서드를 동일한 이름으로 정의해 메서드 호출 시 매개변수의 형태에 따라 적절한 메서드가 선택되도록 할 수 있다.
- 오버로딩은 메서드의 기능이나 작업은 동일하지만 입력값에 따라 다르게 동작해야 할 때 사용됨
void PrintMessage(string message)
{
Console.WriteLine("Message: " + message);
}
void PrintMessage(int number)
{
Console.WriteLine("Number: " + number);
}
PrintMessage("Hello, World!");
PrintMessage(10);
- PrintMessage 메서드가 두 개 있다. 두 개의 매개변수는 string과 int로 명확히 다름.
- 그렇기 때문에 매개변수를 뭘 주냐에 따라 각각에 해당하는 메서드가 실행됨
- 오버로딩에서는 반환값이 다르다고 해서 오버로딩 되지 않는다. 왜냐면 메서드를 호출하는 입장에서 생각하는 거기 때문에 아직 반환값이 뭔지 모름. 그래서 매개변수만 구분하는데 사용한다. 반환값이 달라도 동일한 메서드로 취급
static int AddNumbers(int a, int b)
{
return a + b;
}
static int AddNumbers(int a, int b, int c)
{
return a + b + c;
}
- 여기서도 두 가지가 다르게 취급되고 있다. 왜냐면 매개변수의 개수가 다름
- 근데 여기서 하나를 추가해 본다면?
static int AddNumbers(int a, int b)
{
return a + b;
}
static float AddNumbers(float a, float b)
{
return a + b;
}
static int AddNumbers(int a, int b, int c)
{
return a + b + c;
}
- 중간에 하나의 메서드를 추가했는데 int 대신 float으로 변경해 줬다.
static void Main(string[] args)
{
int sum1 = AddNumbers(10, 20);
float sum2 = AddNumbers(10.5f, 21.5f);
int sum3 = AddNumbers(10, 20, 30);
}
- 그럼 Main에서 sum2는 자동으로 float 매개변수의 메서드를 따라가게 된다.
static long AddNumbers(int a, int b)
{
return a + b;
}
static int AddNumbers(int a, int b)
{
return a + b;
}
- 그런데 만약 새로운 반환값 long을 주고 메서드를 하나 또 만든다면?
- 먼저 만들어 놓은 두 번째와 동일한 매개변수를 가진 AddNumbers이기 때문에 에러가 뜬다.
- 그러니까 반환값은 아예 취급도 하지 않고, 동일한 매개변수가 있는지만 체크한다는 걸 볼 수 있다. 반환값은 아무 의미 없음
- 오버로딩에 대해서는 항상 매개변수가 달라야 한다는 걸 잊지말자. 매개변수의 개수, 자료형, 순서 등
재귀 호출
재귀 호출의 개념과 동작 원리
- 재귀 호출: 메서드가 자기 자신을 호출하는 것
- 재귀 호출은 문제를 작은 부분으로 분할해 해결하는 방법 중 하나로, 작은 부분의 해결 방법이 큰 문제의 해결 방법과 동일한 구조를 갖고 있는 경우에 적합하다.
- 재귀 호출은 호출 스택에 호출된 메서드의 정보를 순차적으로 쌓고, 메서드가 반환되면서 스택에서 순차적으로 제거되는 방식으로 동작함
static void CountDown(int n)
{
if (n <= 0)
{
Console.WriteLine("Done");
}
else
{
Console.WriteLine(n);
CountDown(n - 1);
}
}
static void Main(string[] args)
{
CountDown(5);
}
- CountDown이라는 함수가 실행돼서 들어가면, n이 0보다 클 경우에는 CountDown에 n - 1을 호출한다. 그럼 결국 0보다 작거나 같아질 때까지 -1이 실행된다는 것. 그럼 이어서 Done이 되고 Main 함수로 돌아가는 것
- 실행해보면 5 4 3 2 1 Done이 출력된다.
- 이렇게 계속 Count를 반복해 호출하는 걸 재귀 호출, 재귀 메서드라고 함
재귀 호출의 활용과 주의점
- 이런 재귀 메서드를 쓸 때 조심해야 할 점이 있다. 방금은 if에 멈춰주는 코드가 있었는데, 이게 없다면 CountDown이 무한히 반복되게 된다.
- 마치 while문에서 조건식 잘못 걸었을 때처럼.. 그럼 호출 스택 오버플로우가 일어나서 터져버린다.
- 그러니 재귀 호출을 사용할 땐 명확히 멈춰주는 구간이 필요하다.
- 즉 재귀 호출은 복잡한 문제를 단순한 방식으로 해결할 수 있는 장점이 있지만, 종료 조건을 명확히 정의해야 하며, 종료 조건을 만족하지 못하면 무한히 재귀 호출이 반복돼 스택 오버플로우 등의 오류가 발생할 수 있다.
- 재귀 호출은 메모리 사용량이 더 크고 실행 속도가 느릴 수 있으므로, 필요한 경우에만 적절히 사용하는 것이 좋음
메서드 활용 사례
메서드를 사용한 코드의 재사용성
- 메서드는 일련의 작업을 수행하는 코드 블럭으로, 반복적으로 사용되는 코드를 메서드로 분리함으로써 코드의 재사용성을 늘릴 수 있다.
- 동일한 작업을 수행하는 코드를 여러 곳에서 사용해야 할 때 해당 작업을 메서드로 정의하고 필요한 곳에서 메서드를 호출해 재사용할 수 있다.
- 이를 통해 중복 코드를 제거하고, 코드의 길이를 줄이고, 코드의 가독성과 유지보수성을 향상시킬 수 있다.
메서드를 활용한 가독성과 유지보수성 개선
- 메서드는 코드의 일부분을 의미 있는 이름으로 추상화하고, 해당 메서드를 호출함으로써 코드의 의도를 명확히 전달할 수 있다.
- 긴 코드를 작은 단위로 분리하여 메서드로 정의하면 코드가 간결해지고 가독성이 향상된다.
- 코드를 작은 단위로 분리해 메서드로 관리하면 유지보수가 용이해진다. 특정 기능을 수정하거나 추가해야 할 때 해당 메서드만 수정하면 되기 때문에 다른 부분에 영향을 주지 않고도 유지보수가 가능하다.
예제
double CalculateCircleArea(double radius)
{
double area = Math.PI * radius * radius;
return area;
}
double CalculateRectangleArea(double width, double height)
{
double area = width * height;
return area;
}
double circleArea = CalculateCircleArea(5.0);
double rectangleArea = CalculateRectangleArea(3.0, 4.0);
Console.WriteLine("원의 넓이: " + circleArea);
Console.WriteLine("사각형의 넓이: " + rectangleArea);
구조체
구조체란?
- 여러 개의 데이터를 묶어서 하나의 사용자 정의 형식으로 만들기 위한 방법
- 구조체는 값 형식(Value Type)으로 분류되며 데이터를 저장하고 필요한 기능을 제공할 수 있다.
- 값 형식 - 어딘가에 대입한다거나 값을 할당할 때 전부 복사가 일어난다는 것
- 구조체는
struct 키워드를 사용해 선언
- 구조체의 멤버는 변수와 메서드로 구성될 수 있다.
struct Person
{
public string Name;
public int Age;
public void PrintInfo()
{
Console.WriteLine($"Name: {Name}, Age: {Age}");
}
}
public string Name 과 public int Age 라고 하는 멤버 변수-필드들이 준비되어 있고, PrintInfo()라고 하는 광고를 출력하는 함수가 준비되어 있다.
구조체의 사용
- 구조체는 변수를 선언해 사용할 수 있다.
- 구조체는 멤버에 접근할 때
. 연산자를 사용한다.
Person person1;
person1.Name = "John";
person1.Age = 25;
person1.PrintInfo();
Person person1; 를 보면, 변수를 int a라고 선언하는 것과 똑같다.
- 우리가 사용하려고 만든 자료형인 것. 그래서 그 자료형 안에 Name과 Age도 저장할 수 있고 PrintInfo()도 실행해 볼 수가 있다.