C# 종합 문법 2

김정환·2024년 9월 19일
0

조건문

필요한 조건이나 경우에 따라서 다른 방식의 연산을 해주어야 한다.

if

if(조건1){
	// 조건1이 true일때 호출
}
else{
	// 조건1이 false일때 호출
}
if(조건1){
	// 조건1이 true일때 호출
}
else if(조건2){
	// 조건1이 false이면서
    // 조건2가 true일때 호출
}
else{
	// 조건1이 false이면서
    // 조건2가 false일때 호출
}

switch

switch(변수 or 연산식)
{
	case1:
    	//값1이 나온 경우
    	break;	// 스위치문 탈출
    case2:
    	//값2이 나온 경우
    	break;
    case3:
    	//값3이 나온 경우
    	break;
    default:
    	//값1,2,3에 해당하지 않는 경우
    	break;
}

3항 연산

int num = 조건식 ? (true일때) 값 또는 식 : (false일때) 값 또는 식;
// 중첩 및 함수 등의 식 사용 가능.

반복문

어떤 값을 찾는다거나, 특정한 배열에 대해 동일한 작업을 여러번 수행해준다거나 작업을 반복적으로 수행할 때 사용한다.
공통적으로 반복을 제어하는 조건식이 있고, 조건식이 true일때 반복하고 false일때 반복을 멈춘다.

for

  • 초기식, 조건식, 증감식을 사용한 반복문
for(초기식; 조건식; 증감식)
{
	// 조건식이 true일 때 실행되는 코드
}

//무한 반복, 루프
for(;;){}

while

while(조건){
	// 조건식이 true일 때 실행되는 코드
    // false가 되면 자동으로 반복 종료
}

for vs while

  • for문은 반복 횟수를 직관적으로 알 수 있고, 반복 조건을 한 눈에 확인할 수 있다.
  • while 문은 반복 조건에 따라 조건문의 실행 횟수가 유동적이며, 이에 따라 코드가 더 간결할 수 있다.
  • 어떤 반복문을 사용할지는 코드의 흐름에 따라 상황에 맞게 선택한다.

do-while

  • while문과 비슷하지만, 조건식을 검사하기 전에 코드 블록을 한 번 실행한다.
  • 최소한 한번은 실행을 해야하는 경우에 쓰면 좋다.
do{
	// 코드 블럭
}
while(조건식); //조건식이 true이면 do 구분 반복

foreach

  • 배열이나 컬렉션에 대한 반복문을 작성할 때 사용.
string[] arr = {"1","2","3","4","5"};

foreach(string el in arr){
	Console.WriteLine(el);
}

continue, break

continue;
  • 현재 반복을 중지하고 다음 반복으로 넘어간다.
break;
  • 반복문을 중지한다.

배열과 컬렉션

배열

  • 동일한 자료형들에 대한 연속적인 자료구조로 한 번에 모아서 쓸 수 있다.
  • 인덱스로 접근할 수 있다.
  • 선언된 크기만큼의 공간을 메모리에 할당받는다.
// 선언
int[] arr;

// 초기화
arr = new int[3];

// 한줄 선언과 초기화
int[] arr2 = new int[5];

// 접근
arr2[1] = 1;
int a = arr2[3];

// 길이
arr2.Length;

다차원 배열

  • 여러 개의 배열을 하나로 묶어 놓은 배열
  • 행과 열로 이루어진 표 형태와 같은 구조
  • 2차원, 3차원 등의 형태의 배열을 의미
  • C#에서는 다차원 배열을 선언할 때 각 차원의 크기를 지정하여 생성
// 2차원 배열 선언
int [,] arr2D = new int[2, 3]; // 2행 3열

// 초기화
arr2D[0,0]= 1;
arr2D[0,1]= 2;
arr2D[0,2]= 3;
arr2D[1,0]= 4;
arr2D[1,1]= 5;
arr2D[1,2]= 6;

// 선언과 함께 초기화
int[,] arr2D = new int[3, 4] {
	{1,2,3,4},{1,2,3,4},{1,2,3,4}
};

// 3차원 배열
int[,,] arr3D = new int[2,3,4] {
	{{1,2,3,4},{1,2,3,4},{1,2,3,4}},
    {{11,12,13,14},{11,12,13,14},{11,12,13,14}}
};

다차원 배열을 활용한 프로그래밍 방법

  • 복잡한 데이터 구조를 효율적으로 관리할 수 있다.
  • 2차원 배열은 행과 열로 이루어진 데이터 구조를 다루기 적합하다.
  • 3차원 배열은 면,행,열로 이루어진 데이터 구조를 다루기 적합하다.

컬랙션

  • 자료를 모아 놓은 데이터 구조
    • 배열과 비슷한 자료 구조
    • 배열과 다르게 크기가 가변적
    • C#에서는 다양한 종류의 컬렉션을 제공
    • System.Collections.Generic 네임스페이스 추가(using)

List<>

  • List 가변적인 크기를 갖는 배열
List<int> numbers = new List<int>();

numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
numbers.Add(4);

numbers.Remove(2);

foreach(int number in numbers) // 리스트 데이터 출력
{
    Console.WriteLine(number); // 1 3 4
}

Dictionary<>

  • 키(key)- 값(value) 쌍으로 구성된 데이터를 저장
  • 다른 언어에선 map이라고 불린다.
  • 중복된 키를 가질 수 없고, 반드시 키-값의 쌍을 이루어 데이터를 저장한다.
Dictionary<string, int> scores = new Dictionary<string, int>(); // 빈 딕셔너리 생성
scores.Add("Alice", 100); // 딕셔너리에 데이터 추가
scores.Add("Bob", 80);
scores.Add("Charlie", 90);
scores.Remove("Bob"); // 딕셔너리에서 데이터 삭제

foreach(KeyValuePair<string, int> pair in scores) // 딕셔너리 데이터 출력
{
    Console.WriteLine(pair.Key + ": " + pair.Value);
}

Stack<>

  • FILO 형태의 자료구조
  • 마지막에 들어간 데이터가 먼저 나온다.
Stack<int> stack1 = new Stack<int>();  // int형 Stack 선언

// Stack에 요소 추가
stack1.Push(1);
stack1.Push(2);
stack1.Push(3);

// Stack에서 요소 가져오기
int value = stack1.Pop(); // value = 3 (마지막에 추가된 요소)

Queue<>

  • FIFO 형태의 자료구조
  • 먼저 들어간 데이터가 먼저 나온다.
Queue<int> queue1 = new Queue<int>(); // int형 Queue 선언

// Queue에 요소 추가
queue1.Enqueue(1);
queue1.Enqueue(2);
queue1.Enqueue(3);

// Queue에서 요소 가져오기
int value = queue1.Dequeue(); // value = 1 (가장 먼저 추가된 요소)

HashSet<>

  • 중복되지 않은 요소로 이루어진 집합
  • 흔히 말하는 세트(Set)
HashSet<int> set1 = new HashSet<int>();  // int형 HashSet 선언

// HashSet에 요소 추가
set1.Add(1);
set1.Add(2);
set1.Add(3);

// HashSet에서 요소 가져오기
foreach (int element in set1)
{
    Console.WriteLine(element); // 1 2 3
}

배열 vs 리스트

  • 리스트는 동적으로 크기를 조정할 수 있어 배열과 다르게 유연한 데이터 구조를 구현할 수 있다.
    하지만, 리스트를 무분별하게 사용하는 것은 좋지 않은 습관이다.

1. 메모리 사용량 증가 :

리스트는 동적으로 크기를 조정할 수 있어 배열보다 많은 메모리를 사용한다.

따라서, 많은 데이터를 다루는 경우 리스트를 무분별하게 사용하면
메모리 사용량이 급격히 증가하여 성능 저하를 유발할 수 있다.

2. 데이터 접근 시간 증가 :

리스트는 연결 리스트(Linked list)로 구현되기 때문에, 인덱스를 이용한 데이터 접근이 배열보다 느리다.
(배열에 비해 상대적으로 느리다.)

리스트에서 특정 인덱스의 데이터를 찾기 위해서는 연결된 노드를 모두 순회해야 하기 때문이다.
이러한 이유로, 리스트를 무분별하게 사용하면 데이터 접근 시간이 증가하여 성능이 저하될 수 있다.

3. 코드 복잡도 증가 :

리스트는 동적으로 크기를 조정할 수 있기 때문에, 데이터 추가, 삭제 등의 작업이 배열보다 간편하다.

하지만, 이러한 유연성은 코드 복잡도를 증가시킬 수 있다.
리스트를 사용할 때는 데이터 추가, 삭제 등의 작업을 적절히 처리하는 코드를 작성해야 하므로, 코드의 가독성과 유지보수성이 저하될 수 있다.

따라서, 리스트를 무분별하게 쓰는 것은 좋은 습관은 아니다.
데이터 구조를 선택할 때는 데이터의 크기사용 목적을 고려해서
배열과 리스트 중 적절한 것을 선택해야 한다.


메서드와 구조체

메서드 method

  • 일련의 코드 블록으로 특정한 작업을 수행하기 위해 사용되는 독립적인 기능 단위.
  • 쉽게말하면 클래스 내부에 있는 함수를 메서드라고 함.
  • 코드의 재사용성모듈화를 위해 사용되며, 필요할 때 호출하여 실행된다.

메서드의 역할과 중요성

코드의 재사용성

메서드를 사용하면 동일한 작업을 반복해서 구현하지 않아도 된다. (반복된 코드를 줄일 수 있다.)
필요한 메소드를 호출하여 작업을 수행할 수 있다.

모듈화

메서드를 사용하여 코드를 작은 단위로 분리하고 관리할 수 있다.
분리된 메서드는 자신에게 부여된 역할을 수행하고 있어서 코드의 구조가 더 명확해진다.

가독성과 유지보수성

코드가 간결해지고 가독성이 좋아진다.
문제가 생기면 해당 메서드만 수정하면 되므로 유지보수가 용이해진다.

코드의 중복 제거

반복적인 작업을 메서드로 묶어서 코드 중복을 방지한다.

코드의 추상화

메서드로 작업 단위를 추상화하고, 메서드 이름을 통해 해당 작업이 어떤 역할을 하는지 파악할 수 있다.

메서드 선언과 호출

구조

[접근 제한자] [리턴 타입] [메서드 이름]([매개변수])
{
    // 메서드 실행 코드
}

public int Add(int a, int b){
	return a + b;
}
  • 접근 제한자 Access Modifier :
    메서드에 접근할 수 있는 범위를 지정.
    • public : 어디서든 접근 가능
    • private : 내부만 접근 가능
    • protected : 상속받은 것만 접근 가능
  • 리턴 타입 Return Type :
    메서드가 반환하는 값의 타입
    없으면 void
  • 메서드 이름 Name :
    메서드의 이름. 호출할 때 이 이름으로 호출한다.
  • 매개변수 Parameters :
    메서드에 전달되는 입력 값.
    필요한 경우 여러 매개변수를 전달한다.
  • 바디 Method Body :
    {} 안에 메서드가 수행하는 작업을 구현하는 코드

호출

int num = Add(10, 20);
  • 호출 시, 전달되는 매개변수는 메서드의 매개변수의 순서와 타입이 일치해야한다.
  • 호출된 메서드는 매개변수를 이용해서 내부 코드를 실행하고 필요한 경우 값을 리턴한다.

매개변수와 반환값

매개변수

  • 메서드에 전달되는 입력 값.
  • 메서드 내에서 이 값을 활용하여 원하는 작업을 수행
  • 매개변수는 선언부에서 정의되고 필요한 경우 0개 이상의 매개변수를 정의할 수 있다.
  • 매개변수는 메서드 호출 시 전달되는 값에 따라 동적으로 결정되고, 호출 시에는 해당 매개변수의 값을 전달해야한다.

반환값

  • 메서드가 수행한 작업 결과를 반환하는 것이다.

  • 메서드 선언 시 반환값의 타입을 지정할 수 있고, 지정한 타입에 맞게 반환해야한다.

  • void와 같이 반환값이 없는 경우도 있다.

메서드와 오버로딩

오버로드 Overload

  • 동일한 이름의 메서드다양한 매개변수 목록으로 다중 정의하는 개념
  • 매개변수의 개수, 타입, 순서가 다른 여러 메서드를 동일한 이름으로 정의할 수 있다.
    이렇게하면 원하는 형태의 매개변수를 선택해서 사용 가능.
  • 오버로딩은 메서드의 기능은 동일하지만, 매개변수 입력을 다르게 해야할 때 사용할 수 있다.
string val;

void SetValue(string str){
	val = str;
}

void SetValue(int num){
	val = num.toString();
}

재귀 호출

  • 메서드가 자기 자신을 호출하는 것.
  • 재귀 호출은 문제를 작은 부분으로 분리하여 해결하는 방법. 작은 부분의 해결 방법이 큰 부분의 해결방법과 동일한 경우 사용.
  • 호출 스택에 호출된 메서드의 정보를 순차적으로 쌓고, 메서드가 반환되면서 스택에서 순차적으로 제거되는 방식이다.
    즉, 반환되지 않고 무한히 호출된다면 스택이 넘쳐서 오류가 난다.

주의점

  • 재귀 호출은 복잡한 문제를 단순한 방식으로 해결할 수 있다는 장점이 있으나, 종료 조건이 명확해야한다.
  • 종료 조건을 만족하지 못하면 무한히 호출되어 스택 오버플로우가 일어날 수 있다.
  • 재귀 호출은 메모리 사용량이 더 크고 실행 속도가 느릴 수 있으므로 필요한 경우에만 적절히 사용하는 것이 좋다.

메서드 활용

  1. 코드 재사용성 향상
  2. 가독성과 유지보수성 향상

구조체

  • 여러 개의 데이터를 묶어서 하나의 사용자 정의 형식으로 만들기 위한 방법
  • 구조체는 값 형식 (Value Type)으로 분류된다.
    (class 등과 같음)
    데이터를 저장하고 필요한 기능을 제공할 수 있다.

선언

struct Fruit {
	public string name;
    public float price;
    
    public void ShowInfo(){
    	Console.WriteLine("This is {0} and price is {1}", name, price);
    }
}

사용

Fruit orange;
orange.name = "Orange";
orange.price = 350f;

orange.ShowInfo();
profile
만성피로 개발자

0개의 댓글