[C#] 조건문과 반복문, 배열과 컬렉션

Gee·2025년 1월 31일

강의 정리

목록 보기
4/10

조건문과 반복문1(2-1)

조건문의 종류

  • 조건문: 주어진 조건식의 결과에 따라 프로그램의 제어 흐름을 변경하는 제어문

if문

  • 조건식의 결과에 따라 실행 여부를 결정하는 조건문
  • else문
    • if문에서 조건식이 거짓일 경우 실행할 코드를 지정하는 조건문

else if문

  • if문의 조건식이 거짓일 때, 새로운 조건식을 사용해 실행 여부를 결정하는 조건문
  • else문은 생략이 가능
          int score = 100;
           string playerRank = "";

           if (score >= 90)
           {
               playerRank = "Diamond";
           }
           else
           {
               if (score >= 80)
               {
                   playerRank = "platinum";
               }
               else
               {
                   if (score >= 70)
                   {
                       playerRank = "Gold";
                   }
                   else
                   {
                       if (score >= 60)
                       {
                           playerRank = "Silver";
                       }
                       else
                       {
                           playerRank = "Bronze";
                       }
                   }
               }

           }

           Console.WriteLine("플레이어의 등급은 {0}입니다.", playerRank);
            int score = 100;
            string playerRank = "";

            if (score >= 90)
            {
                playerRank = "Diamond";
            }
            else if (score >= 80)
            {
                playerRank = "platinum";
            }
            else if (score >= 70)
            {
                playerRank = "Gold";
            }
            else if (score >= 60)
            {
                playerRank = "Silver";
            }
            else
            {
                playerRank = "Bronze";
            }

            Console.WriteLine("플레이어의 등급은 {0}입니다.", playerRank);
        }
  • 위 코드를 함축한 게 아래 코드

중첩 조건문

  • 하나의 조건문 안에 또 다른 조건문이 포함된 형태의 조건문
    int itemLevel = 3; // 아이템 레벨
    string itemType = "Weapon"; // 아이템 종류

    if (itemType == "Weapon")
    {
        if (itemLevel == 1)
        {
            // 레벨 1 무기 효과
            Console.WriteLine("공격력이 10 증가했습니다.");
        }
        else if (itemLevel == 2)
        {
            // 레벨 2 무기 효과
            Console.WriteLine("공격력이 20 증가했습니다.");
        }
        else
        {
            // 그 외 무기 레벨
            Console.WriteLine("잘못된 아이템 레벨입니다.");
        }
    }
    else if (itemType == "Armor")
    {
        if (itemLevel == 1)
        {
            // 레벨 1 방어구 효과
            Console.WriteLine("방어력이 10 증가했습니다.");
        }
        else if (itemLevel == 2)
        {
            // 레벨 2 방어구 효과
            Console.WriteLine("방어력이 20 증가했습니다.");
        }
        else
        {
            // 그 외 방어구 레벨
            Console.WriteLine("잘못된 아이템 레벨입니다.");
        }
    }
    else
    {
        // 그 외 아이템 종류
        Console.WriteLine("잘못된 아이템 종류입니다.");
    }
  • 관계 연산(AND, OR)으로 출력하면 문장이 너무 길어지기 때문에 중첩 조건문 사용

switch문

  • 변수나 식의 결과에 따라 다른 코드 블록을 실행하는 제어문
  • case문을 사용해 변수나 식의 결과에 따라 실행할 코드를 지정
        switch (job)
        {
            case "1":
                Console.WriteLine("전사를 선택하셨습니다.");
                break;
            case "2":
                Console.WriteLine("마법사를 선택하셨습니다.");
                break;
            case "3":
                Console.WriteLine("궁수를 선택하셨습니다.");
                break;
            default:       // 생략 가능
                Console.WriteLine("올바른 값을 입력해 주세요.");
                break;
        }

3항 연산자

  • if문의 간단한 형태로, 조건식의 결과에 따라 두 값을 선택하는 연산자
  • if else문을 함축적으로 사용한다고 생각하면 된다.
  • (조건식) ? 참일 경우 값: 거짓일 경우 값;
      int currentExp = 1200;
      int requiredExp = 2000;

      # 삼항 연산자
      string result = (currentExp >= requiredExp) ? "레벨업 가능" : "레벨업 불가능";
      Console.WriteLine(result);
		
        
      # if else 문
      if (currentExp >= requiredExp)
      {
          Console.WriteLine("레벨업 가능");
      }
      else
      {
          Console.WriteLine("레벨업 불가능");
      }

조건문과 반복문2(2-2)

조건문 심화

홀수와 짝수를 구분하는 프로그램

        // 1. 홀수와 짝수 구분하기
        Console.Write("번호를 입력하세요: ");
        int number = int.Parse(Console.ReadLine());

        if (number % 2 == 0)
        {
            Console.WriteLine("짝수입니다.");
        }
        else
        {
            Console.WriteLine("홀수입니다.");
        }
  • 홀짝을 구분하려면 나머지 연산을 활용하면 된다.
  • 2를 나누면 나머지는 무조건 0 혹은 1 이상이 나오기 때문

등급 출력

  • 0점부터 100점 사이의 점수를 받아와서 몇 등급인지를 출력해 보자.
        // 2. 등급 출력하기
        int playerScore = 100;
        string playerRank = "";

        switch(playerScore / 10)
        {
            case 10:
            case 9:
                playerRank = "Diamond";
                break;
            case 8:
                playerRank = "Platinum";
                break;
            case 7:
                playerRank = "Gold";
                break;
            case 6 :
                playerRank = "Silver";
                break;
            default:
                playerRank = "Bronze";
                break;
        }
        
        Console.WriteLine(playerRank);
  • 95에서 10을 나눠줘도 int기 때문에 9.5가 아니라 9가 됨. 결국 90~99 모두 10으로 나눴을 때 9가 된다는 점을 활용한 것
  • case 10은 랭크를 입력하지 않아도 case9에서 break를 타고 나가기 때문에 따로 적어주지 않아도 된다.

로그인 프로그램(AND)

  • 로그인 정보는 아이디와 비밀번호 모두 입력한 값과 똑같은지 검사해야 함
  • id는 똑같다. 그리고~ password도 똑같다. AND(&&)를 쓰자.
        // 3. 로그인 프로그램
        string id = "id";
        string password = "pw";
        
        Console.Write("아이디를 입력하세요: ");
        string inputId = Console.ReadLine();
        
        Console.Write("비밀번호를 입력하세요: ");
        string inputPassword = Console.ReadLine();

        if (id == inputId && password == inputPassword)
        {
            Console.WriteLine("로그인 성공!");
        }
        else
        {
            Console.WriteLine("로그인 실패...");
        }

알파벳 판별 프로그램(OR)

        // 4. 알파벳 판별 프로그램
        Console.Write("문자를 입력하세요: ");
        char input = Console.ReadLine()[0];
        
        // 소문자에 포함되면서 대문자에 포함되면
        if ( (input >= 'a' && input <= 'z') || (input >= 'A' && input <= 'Z') )
        {
            Console.WriteLine("알파벳입니다.");
        }
        else
        {
            Console.WriteLine("알파벳이 아닙니다.");
        }
  • ReadLine 문자열에서 제일 앞에 걸 가져오고 싶다면 괄호 끝에 대괄호를([0]) 붙인다. indexing. 0번째 거를 가져오라는 뜻
  • 그럼 input에서 입력한 문자열이 몇 개가 됐던 간에 맨 앞에 있는 한 글자만 가져오게 된다.
  • char도 정수형에 속함. 컴퓨터는 문자를 알 수 없기 때문에 문자표를 가지고 있고, 그 문자와 숫자를 대칭해서 사용하고 있음. 그래서 관계 연산자들이 정확하게 동작할 수 있다.
  • 소문자(a~z)에 포함된다. 혹은 대문자(A~Z)에 포함된다? =알파벳이다.

조건문과 반복문3(2-3)

반복문

  • 반복문: 일련의 명령문을 반복해서 실행하는 제어문

for문

  • 초기식, 조건식, 증감식을 사용해 반복문을 작성
    • 초기식: 반복문이 시작될 때 단 한 번 실행됨
    • 조건식: 반복문이 실행될 때마다 평가되며, 참(true)인 경우 반복문이 계속 실행됨
    • 증감식: 반복문이 실행될 때마다 실행되는 식
  for (초기식; 조건식; 증감식)
  {
      // 조건식이 참인 경우 실행되는 코드
  }
  • 몇부터(초기식), 몇까지(조건식), 얼마만큼씩(증감식)
        // for문 기초
        for (int i = 0; i < 10; i++) 
        {
            Console.WriteLine(i);
        }
  • int i = 0 // i는 0부터 시작해서
  • i < 10 // i가 10보다 작을 때까지(10이 될 때까지)
  • i++ // i는 1씩 증가한다.
  • 만약에 1부터 20 사이의 홀수만 출력하고 싶다. 근데 1씩 증가하면 한 다리씩 건너는 게 아니니까
        for (int i = 1; i < 21; i += 2) 
        {
            Console.WriteLine(i);
        }
  • i에다가 2를 더해서 넣겠다고 해주면 1, 3, 5... 이렇게 홀수만 출력된다.
  • 만약 이 반복문을 돌면서 이 i가 몇으로 끝났는지가 필요하다?
    근데 지금 이렇게 두면 int i는 for 문장의 것이라서, for 문장이 끝나면 그대로 ㅃ2해버린다.
    그래서 만약 이 int i를 이후에도 쓰고 싶다면
        int i = 0;
        for (i = 1; i < 21; i += 2) 
        {
            Console.WriteLine(i);
        }
  • 이렇게 int i를 바깥에다 선언해 주고 for 문장의 int를 빼면 된다.
  • 이러면 변수가 바깥에 선언되어 있기 때문에 바깥에서도 i를 쓸 수 있다.
  • 요약: for문 안에서 int i라고 선언한 경우엔 int i는 for 문장의 것. 근데 쓰려면 int i를 바깥으로 꺼내주면 ok

while문

  • 조건식이 참(true)인 동안 코드 블록을 반복적으로 실행
  while (조건식)
  {
      // 조건식이 참인 경우 실행되는 코드
  }
  • for문처럼 초기, 조건, 증감식이 아니고 조건식만 있다. 하지만! 둘이 같음. 그러나! 쓰는 역할은 조금 다르다.
  • for문은 명확한 회차, 명확한 데이터가 있을 때 확실히 쓰기 좋다.
  • while문은 조건식 밖에 없기 때문에 조건에 부합하는 반복을 돌릴 때 훨씬 쓰기 좋다.
  • for문: ~번 반복하기에 부합, while: ~인 동안 ~이 될 때 까지 반복하기에 부합
        // while문 기초
        int i = 0;
        while (i < 10)
        {
            Console.WriteLine(i);
            i++;
        }
  • int i = 0 // 초기, i < 10 // 조건, i++ // 증감
  • 결국 for문과 같다. 사용할 때 뭐가 조금 더 편하다 정도의 차이
  // while문 예시
  int count = 0;
  while (count < 10)
  {
      Console.WriteLine("적을 처치했습니다! 남은 적 수: " + (10 - count - 1));
      count++;
  }

  Console.WriteLine("축하합니다! 게임에서 승리하셨습니다!");

for문 vs while문

  int sum = 0;

  for (int i = 1; i <= 5; i++)
  {
      sum += i;
  }

  Console.WriteLine("1부터 5까지의 합은 " + sum + "입니다.");
  int sum = 0;
  int i = 1;

  while (i <= 5)
  {
      sum += i;
      i++;
  }

  Console.WriteLine("1부터 5까지의 합은 " + sum + "입니다.");
  • for문은 반복 횟수를 직관적으로 알 수 있고, 반복 조건을 한눈에 확인할 수 있어 가독성이 좋다.
  • while문은 반복 조건에 따라 조건문의 실행 횟수가 유동적이며, 이에 따라 코드가 더 간결할 수 있다.
  • 어떤 반복문을 사용할지는 코드의 흐름에 따라, 상황에 맞게 선택하자.

do-while문

  • for과 while 모두 조건에 부합하지 않으면 반복문이 한 번도 돌지 않을 수 있다.
  • 그런데 만약 최소 한 번은 돌고 나서 조건을 검사해야 한다면? 그런 코드가 필요하다면? 그때 쓰는 게 do-while이다.
  do
  {
      // 조건식이 참인 경우 실행되는 코드
  }
  while (조건식);
  • do-while은 구조가 반대로 뒤집어져 있다.
  • 그래서 최초 한 번의 실행은 허용하고 나서 조건을 검사하겠다는 것.
int sum = 0;
int num;

do
{
    Console.Write("숫자를 입력하세요 (0 입력 시 종료): ");
    num = int.Parse(Console.ReadLine());
    sum += num;
} while (num != 0);

Console.WriteLine("합계: " + sum);
  • do를 먼저 넣었으니 이 중괄호는 최초 한 번은 무조건 실행됨
  • 숫자 값, int니까 정수 값을 하나 입력 받고 그걸 sum에 더하고 그게 0이 아니면 또 도는 식의 구조. 0이 입력되면 끝. 아니면 반복

foreach문

  • 배열이나 컬렉션에 대한 반복문을 작성할 때 사용
  foreach (자료형 변수 in 배열 또는 컬렉션)
  {
      // 배열 또는 컬렉션의 모든 요소에 대해 반복적으로 실행되는 코드
  }
  • foreach문은 몇 번 반복한다는 느낌보단 특정한 배열이나 컬렉션, 즉 자료의 뭉탱이를 기준으로 돌게 됨
  • 자료의 뭉탱이를 제공해 주면 거기서 하나씩 꺼내서 사용하는 것
  string[] inventory = { "검", "방패", "활", "화살", "물약" };

  foreach (string item in inventory)
  {
      Console.WriteLine(item);
  }
  • string의 배열 inventory. 배열은 데이터의 묶음
  • 이 inventory를 in에다가 제공하니, 처음 반복문을 돌 땐 검이 들어가서 돌고, 두 번째엔 방패가 들어가서 돌고, 세 번째엔 활이 들어가서 계속 돌게 됨
  • 누굴 기준으로 돌지? 데이터를 기준으로. 이게 foreach문의 규칙
  • 이후에 배열이나 컬렉션을 할 때 자주 등장함

중첩반복문

  • 반복문을 한번 더 돌리는 것

  • 이차원 반복문

  for (int i = 0; i < 5; i++)
  {
      for (int j = 0; j < 3; j++)
      {
          Console.WriteLine("i: {0}, j: {1}", i, j);
      }
  }
  • i가 5번 반복으로 돈다. 그런데 그 5번을 도는 와중에 j는 3번 돈다.
  • i가 0부터 4까지 도는 와중에 j는 0부터 2까지 도는 것
  • 그럼 3번씩 5번 도니까 총 15번의 반복을 돌게 된다.
        // 구구단 출력
        for (int i = 2; i <= 9; i++)
        {
            for (int j = 1; j <= 9; j++)
            {
                Console.WriteLine(i + " x " + j + " = " + (i * j));
            }
        }
  • 2단부터 9단을 도는 사이에 1부터 9를 매번 곱해주고 있다.
  • 실행해 보면 2단부터 9단까지의 구구단이 일렬로 출력됐다.
  • 이걸 가로로 나오게 하고 싶다면?
        for (int i = 2; i <= 9; i++)
        {
            for (int j = 1; j <= 9; j++)
            {
                Console.Write(i + " x " + j + " = " + (i * j) + "\t");
            }
            Console.WriteLine();
        }
  • WriteLine을 Write로 바꿔주고 \t를 추가, 맨 아래에 Console.WriteLine();을 추가해 주면 된다.
  • 그런데 이제 각 단을 하나의 세로 묶음으로 만들고 싶다면?
  • 지금까지는 2단, 3단 이렇게 순차적으로 갔다면 21, 31 이렇게 앞 숫자에 변화를 주면 될 것이다.
        for (int i = 1; i <= 9; i++)
        {
            for (int j = 2; j <= 9; j++)
            {
                Console.Write(j + " x " + i + " = " + (i * j) + "\t");
            }
            Console.WriteLine();
        }
  • 그래서 i의 값을 1로, j의 값을 2로 바꿔주고, Write의 i와 j의 위치를 바꿔주면 된다.
  • 실행해 보면 각 단이 일렬로 나눠졌다.
  • 간단히 값 몇 개만 바꿔도 시각적으로 보여지는 값들이 확 달라진다. 원하는 값들에서 규칙이 뭔지를 잘 분석해야 이처럼 코드를 쉽게 수정할 수 있다.

Break & Continue

  • Break는 반복문을 중지시키는 역할
  • Continue는 현재 반복을 중지하고 다음 반복을 진행하는 역할
        // break와 continue 기초
        for (int i = 1; i <= 10; i++)
        {
            Console.WriteLine(i);
        }
  • 이 코드에서 3의 배수는 그냥 넘어갔으면 좋겠다.
  • 만약 i가 3의 배수라면 넘어가라고 해주자.
        for (int i = 1; i <= 10; i++)
        {
            if (i % 3 == 0)
            {
                continue;
            }
            
            Console.WriteLine(i);
        }
  • continue 라인에 포인트를 두고 실행해 보니 1, 2까지는 출력이 됐고 멈춰있다.
  • F10을 눌러보면 이후 i++ 증감식으로 이동했다. 이렇게 동작하는 게 continue
  • break도 써보자. 만약 i가 7이 되면 끝내게 하자.
        for (int i = 1; i <= 10; i++)
        {
            if (i % 3 == 0)
            {
                continue;
            }
            
            Console.WriteLine(i);

            if (i == 7)
            {
                break;
            }
        }
  • break에 포인트를 찍고 실행해 보니 7에서 멈춰있다. F10을 누르면 반복문이 끝나서 밑으로 빠져나왔다.
  • 즉 continue는 이번 회차만 건너간 뒤 증감식으로 가 버리고, break는 이 반복문을 그냥 떠나버린다.
        // break와 continue 예제
        int sum = 0;

        while (true)        // 무한루프
        {
            Console.Write("숫자를 입력하세요: ");
            int input = int.Parse(Console.ReadLine());

        }

        Console.WriteLine("합계: " + sum);
  • 예제. 코드가 크게 다르지 않지만 while이 나왔다.
  • 원래는 괄호 안에 조건이 들어가는데 여기엔 true가 들어있다.
  • 이러면 무한루프에 빠지게 됨.. 어떻게 돼도 참밖에 안나오니까
  • 그래서 while문에 언젠가는 break문이 나오겠다고 생각하면 된다.
  • 또 while문만 무한루프를 돌릴 수 있는 게 아니라 for문도 가능함. for문은 원래 안에 있는 애들을 다 생략할 수 있음
  • for(;;) 이렇게 세미콜론 두 개만 넣어주면 무한루프 됨
  • 이어서 코드를 보자. 숫자를 입력받으려 ReadLine했고, int한테 Parse를 요청해서 정수 값으로 반환했다.
  • 그다음 입력받은 숫자가 0이면 프로그램을 종료 시키고 싶다.
        int sum = 0;

        while (true)        // 무한 루프, for(;;)
        {
            Console.Write("숫자를 입력하세요: ");
            int input = int.Parse(Console.ReadLine());

            if (input == 0)
            {
                Console.WriteLine("프로그램 종료");
                break;
            }
        }

        Console.WriteLine("합계: " + sum);
  • 첫 번째로 input이 0일 때 반복문을 종료하는 break를 적어줬다.
        int sum = 0;

        while (true)        // 무한 루프, for(;;)
        {
            Console.Write("숫자를 입력하세요: ");
            int input = int.Parse(Console.ReadLine());

            if (input == 0)
            {
                Console.WriteLine("프로그램 종료");
                break;
            }

            if (input < 0)
            {
                Console.WriteLine("음수는 무시");
                continue;
            }
        }

        Console.WriteLine("합계: " + sum);
  • 두 번째로 입력받은 숫자가 0보다 작으면 무시한다는 continue를 적어줬다.
  • 그럼 양수는?
        int sum = 0;

        while (true)        // 무한 루프, for(;;)
        {
            Console.Write("숫자를 입력하세요: ");
            int input = int.Parse(Console.ReadLine());

            if (input == 0)
            {
                Console.WriteLine("프로그램 종료");
                break;
            }

            if (input < 0)
            {
                Console.WriteLine("음수는 무시");
                continue;
            }
            
            sum += input;
            Console.WriteLine(sum);
        }

        Console.WriteLine("합계: " + sum);
  • 양수일 때는 sum에다가 입력 받은 숫자를 더한다고 적어줬다.
  • 이러면 숫자를 무한히 입력 받으면서 0이 입력되면 프로그램 종료, 음수면 무시, 그 외 양수값이 들어오면 모두 다 더하는 프로그램을 짠 것

조건문과 반복문4(2-4)

반복문 심화 실습

가위 바위 보 로직 만들기

        // 1. 가위 바위 보
        string[] choice = { "가위", "바위", "보" };
  • string으로 가위 바위 보의 배열을 적어줬다.
  • 배열은 같은 자료형의 값을 여러 개 모아둔 것
        string[] choice = { "가위", "바위", "보" };
        string playerCoice = "";
        string computerCoice = choice[new Random().Next(0, 3)];
  • choice에서는 0번, 1번, 2번 등을 고를 수 있는데 그럼 랜덤이 아니게 돼서 new Random().Next(0, 3)를 추가
  • 이렇게 만들면 0부터 2까지만 랜덤으로 나오게 된다.
        string[] choice = { "가위", "바위", "보" };
        string playerCoice = "";
        string computerCoice = choice[new Random().Next(0, 3)];

        while (playerCoice != computerCoice)
        {
            Console.Write("가위, 바위, 보 중 하나를 선택하세요: ");
            playerCoice = Console.ReadLine();
        }
  • 그 다음은 while. 'playerCoice와 computerCoice가 다르면'을 적어준다.
  • 랜덤으로 뽑았으니 컴퓨터는 현재 가위, 바위, 보 중에 하나일 거고 플레이어는 아직 빈 문자열이라 Write에서 선택하라고 말해준다. ReadLine도 추가
        string[] choice = { "가위", "바위", "보" };
        string playerCoice = "";
        string computerCoice = choice[new Random().Next(0, 3)];

        while (playerCoice != computerCoice)
        {
            Console.Write("가위, 바위, 보 중 하나를 선택하세요: ");
            playerCoice = Console.ReadLine();

            if (playerCoice == computerCoice)
            {
                Console.WriteLine("비겼습니다.");
            }
            else if
            {
                
            }
        }
  • 그리고 if를 통해 playerCoice와 computerCoice가 같은지 물어봤다. 같으면 비겼다는 문구 출력
  • 이 프로그램을 비겼을 때만 종료할 수 있게 만들자.
        while (playerCoice != computerCoice)
        {
            Console.Write("가위, 바위, 보 중 하나를 선택하세요: ");
            playerCoice = Console.ReadLine();

            if (playerCoice == computerCoice)
            {
                Console.WriteLine("비겼습니다.");
            }
            else if (
                (playerCoice == "가위" && computerCoice == "보") ||
                (playerCoice == "바위" && computerCoice == "가위") ||
                (playerCoice == "보" && computerCoice == "바위")
                    )
            {
                Console.WriteLine("플레이어 승리!");
            }
            else
            {
                Console.WriteLine("컴퓨터 승리!");
            }
        }
  • 이어서 else if를 작성. 플레이어가 이기는 조건을 세 개 작성했다.
  • else는 비기거나 지는 게 아닌 경우니 컴퓨터 승리 문구 작성
  • 실행해 보면 비겼을 경우에만 프로그램이 종료되는 걸 볼 수 있다.

숫자 맞추기 로직 만들기

        // 2, 숫자 맞추기
        int targetNumber = new Random().Next(1, 101);
        int guess = 0;
        int count = 0;
        Console.WriteLine("1부터 100 사이의 숫자를 맞춰보세요.");

        while (guess != targetNumber)
        {
            
        }
  • 1부터 100까지 랜덤한 숫자가 나오는 코드와 초깃값, 안내 문구 작성
  • 컴퓨터가 생각한 targetNumber가 내가 생각한 숫자보다 클 때는 조금 더 크다고 알려주고, 작을 땐 작다고 알려주고, 맞췄을 땐 축하합니다를 출력해주면 되겠다. 이렇게 총 세 가지의 경우가 나옴
  • 그러면서 내가 숫자를 입력한 횟수(count)를 하나씩 증가시킴
        int targetNumber = new Random().Next(1, 101);
        int guess = 0;
        int count = 0;
        
        Console.WriteLine("1부터 100 사이의 숫자를 맞춰보세요.");
        
        while (guess != targetNumber)
        {
            Console.Write("추측한 숫자를 입력하세요. ");
            guess = int.Parse(Console.ReadLine());
            count++;
  • guess를 Console.ReadLine으로 받아 오는데 그냥 ReadLind은 string 값이다. 하지만 우리가 쓰고자 하는 guess는 정수값. 정수한테 변환을 요청해야 함
  • 그래서 int.Parse()를 추가해 준다. 그럼 입력받은 문자를 숫자로 변환해서 guess에 저장하게 된다.
  • 그리고 입력한 횟수에 따라 카운트를 하나씩 증가시켜 주자.
        int targetNumber = new Random().Next(1, 101);
        int guess = 0;
        int count = 0;
        
        Console.WriteLine("1부터 100 사이의 숫자를 맞춰보세요.");
        
        while (guess != targetNumber)
        {
            Console.Write("추측한 숫자를 입력하세요. ");
            guess = int.Parse(Console.ReadLine());
            count++;

            if (guess < targetNumber)
            {
                Console.WriteLine("좀 더 큰 숫자를 입력하세요.");
            }
            else if (guess > targetNumber)
            {
                Console.WriteLine("좀 더 작은 숫자를 입력하세요.");
            }
            else
            {
                Console.WriteLine("축하합니다! 숫자를 맞추셨습니다.");
                Console.WriteLine("시도한 횟수 : " + count);
            }
  • 아래에는 guess가 클 때, 작을 때, 같을 때의 조건문을 입력해준다.
  • 실행해 보면 숫자를 맞출 때까지 계속해서 반복문이 실행되는 걸 볼 수 있다.

배열과 컬렉션(2-5)

  • 배열과 컬렉션의 선언, 초기화 방법을 이해하고 활용해 보자.
  • 다양한 자료형의 배열과 컬렉션을 사용해 프로그램을 작성해 보자.

배열

  • 동일한 자료형의 값들이 연속적으로 저장되는 자료구조
  • 학생 100명이 있을 때, 한 명 한 명을 변수로 저장하면 관리가 안 되기 때문에 '학생들'이라는 한 배열을 만드는 것

1차원 배열

  • 동일한 데이터 유형을 가지는 데이터 요소들을 한 번에 모아서 다룰 수 있는 구조
  • 인덱스를 사용해 요소에 접근 가능
  • 선언된 크기만큼의 공간을 메모리에 할당받음
  // 배열 선언
  데이터_유형[] 배열_이름;

  // 배열 초기화
  배열_이름 = new 데이터_유형[크기];

  // 배열을 한 줄로 선언 및 초기화
  데이터_유형[] 배열_이름 = new 데이터_유형[크기];

  // 배열 요소에 접근
  배열_이름[인덱스] =;= 배열_이름[인덱스];
  int[] array1 = new int[5];       // 크기가 5인 int형 배열 선언
  string[] array2 = new string[3]; // 크기가 3인 string형 배열 선언
  int num = 0;

  // 배열 초기화
  array1[0] = 1;
  array1[1] = 2;
  array1[2] = 3;
  array1[3] = 4;
  array1[4] = 5;

  num = array1[0];	// 사용 시 이렇게 적어주면 0번째에 있는 값이 반환됨
  // 예제
  int[] itemPrices = { 100, 200, 300, 400, 500 };
  int totalPrice = 0;

  for (int i = 0; i < itemPrices.Length; i++)
  {
      totalPrice += itemPrices[i];
  }

  Console.WriteLine("총 아이템 가격: " + totalPrice + " gold");
  • itemPrices라는 배열을 하나 만들었다. 이번에는 new로 생성한 게 아니라 배열을 만들자마자 5개의 데이터를 채워 넣었다. 위에서 new int[5]로 만든 것처럼 똑같이 5개가 생성 된 것.
  • 하지만 이번에는 초기화도 진행해 데이터까지 들어감
  • 그런 다음 totalPrice를 0으로 지정해 줬고, 다음엔 똑같이 반복문이 나온다.
  • 이전 예제에서 자주 쓰던 i < 10의 10 대신 itemPrices.Length가 들어가 있다.
  • 이어지는 데이터들, 자료 구조들의 개수는 보통 Length라고 표현함
  • Length는 즉 이 배열의 길이. 5개니까 5라는 값이 나오고, 해당 반복문은 0부터 4까지 5번 반복된다는 뜻이 된다.
  • 그래서 i에는 0부터 4까지 들어가니까 itemPrices의 0번 ~ 4번째까지의 데이터(100 ~ 500 값)를 totalPrice에다 더해준다. 즉 totalPrice에서 총합을 구한다는 것. 그다음 총합에 대한 출력을 진행

게임 캐릭터의 능력치 배열 만들기

        // 플레이어의 공격력, 방어력, 체력, 스피드를 저장할 배열
        int[] playerStats = new int[4]; 

        // 능력치를 랜덤으로 생성하여 배열에 저장
        Random rand = new Random();
        for (int i = 0; i < playerStats.Length; i++)
        {
            playerStats[i] = rand.Next(1, 11);
        }

        // 능력치 출력
        Console.WriteLine("플레이어의 공격력: "  + playerStats[0]);
        Console.WriteLine("플레이어의 방어력: "  + playerStats[1]);
        Console.WriteLine("플레이어의 체력: "    + playerStats[2]);
        Console.WriteLine("플레이어의 스피드: "  + playerStats[3]);
  • int 배열 4개짜리를 만들어서 4개에 각각 원하는 값들을 집어넣고, 랜덤으로 1부터 10사이의 정수값들을 배치시킴. 그다음 0번째, 1번째 이렇게 각각의 값들에 의미를 부여해서 사용하게 되는 것
  • 여기에도 playerStats.Length에 Length라는 값이 있다. 그러니 이 배열의 길이를 구할 수 있겠다.

학생들의 성적 평균 구하기

  • 학생들의 5명의 점수를 가져와서 총합을 구하고, 그 총합에 대한 평균을 구해보자.
        // 학생들의 성적 평균 구하기
        int[] scores = new int[5];

        for (int i = 0; i < scores.Length; i++)
        {
            Console.Write("학생 " + (i + 1) + "의 성적을 입력하세요: ");
            scores[i] = int.Parse(Console.ReadLine());
        }
        
        int sum = 0;

        for (int i = 0; i < scores.Length; i++)
        {
            sum += scores[i];
        }
        
        double average = sum / scores.Length;
        Console.WriteLine("성적 평균은 " + average + "입니다.");
  • 이렇게 작성해주고 아무렇게나 점수를 입력해 실행해 보면 평균의 결과가 정수값이 나온다. 계산이 뭔가 잘못됐다.
  • sum의 자료형은 int. scores.Length의 자료형도 개수니까 int.
    int / int 니까 정수밖에 안 나오는 것
  • double average가 있지만 계산 공식 자체에서 이미 정수로 진행하기 때문에 그냥 int값이 double로 바뀐 상태로 들어가게 됨
  • 그래서 이런 계산을 하기 전에 필수적으로 sum과 Length 둘 중 하나는 다른 형태로 만들어 줘야 함
        int[] scores = new int[5];

        for (int i = 0; i < scores.Length; i++)
        {
            Console.Write("학생 " + (i + 1) + "의 성적을 입력하세요: ");
            scores[i] = int.Parse(Console.ReadLine());
        }
        
        int sum = 0;

        for (int i = 0; i < scores.Length; i++)
        {
            sum += scores[i];
        }
        
        double average = (double)sum / scores.Length;
        Console.WriteLine("성적 평균은 " + average + "입니다.");
  • 그래서 sum을 double로 만들어 줬다.
  • 이렇게 해야 실제로 결과가 double 형태로 나오고 그 결과에 double 형태가 average에 들어가게 되는 것
  • 이런식으로 연산식을 할 땐 둘 중 하나는 꼭 double 혹은 float이라는 실수형으로 만들어 줘야 결과도 실수형으로 나올 수 있다.

배열을 활용한 숫자 맞추기 게임

		// 배열을 활용한 숫자 맞추기 게임
        Random random = new Random();  // 랜덤 객체 생성
        int[] numbers = new int[3];  // 3개의 숫자를 저장할 배열

        // 3개의 랜덤 숫자 생성하여 배열에 저장
        for (int i = 0; i < numbers.Length; i++)
        {
            numbers[i] = random.Next(1, 10);
        }

        int attempt = 0;  // 시도 횟수 초기화
        while (true)
        {
            Console.Write("3개의 숫자를 입력하세요 (1~9): ");
            int[] guesses = new int[3];  // 사용자가 입력한 숫자를 저장할 배열

    
        }
  • random이 하나 만들어져 있다. 이전에는 new Random().Next()로 바로 사용했는데 이번엔 랜덤을 하나 미리 받아놓고 계속 사용하려고 만든 것
  • 그런 다음 numbers라고 하는 3개짜리 int 배열을 만들어 줬고, 3개의 랜덤 숫자를 생성해 배열에 저장시켰다. (numbers.Length만큼 반복되니까)
		Random random = new Random();  // 랜덤 객체 생성
        int[] numbers = new int[3];  // 3개의 숫자를 저장할 배열

        // 3개의 랜덤 숫자 생성하여 배열에 저장
        for (int i = 0; i < numbers.Length; i++)
        {
            numbers[i] = random.Next(1, 10);
        }

        int attempt = 0;  // 시도 횟수 초기화
        while (true)
        {
            Console.Write("3개의 숫자를 입력하세요 (1~9): ");
            int[] guesses = new int[3];  // 사용자가 입력한 숫자를 저장할 배열

            for (int i = 0; i < numbers.Length; i++)
            {
                guesses[i] = int.Parse(Console.ReadLine());
            }
        }
  • 3번의 입력을 받기 위해 아래에 for문을 작성했다.
  • 그리고 나와 쟤의 세 개의 배열을 비교해 보려면 내 1번 카드를 쟤 카드 세 장과 비교하고, 내 2번 카드를 쟤 카드 세 장과 비교하고 이렇게 반복하면 될 것이다. 이러면 구구단을 출력했을 때와 같은 이차원 반복이 나오게 된다.
  • 이차원 반복을 돌려보자.
            for (int i = 0; i < numbers.Length; i++)
            {
                guesses[i] = int.Parse(Console.ReadLine());
            }

            int correct = 0;

            for (int i = 0; i < numbers.Length; i++)
            {
                for (int j = 0; j < guesses.Length; j++)
                {
                    
                }
            }
  • 아래에다 이렇게 작성해주면 numbers의 0, 1, 2(Length)를 반복하는 와중에 guesses의 개수만큼 0부터 2까지 반복을 돌게 되겠다.
  • 이때 비교를 해주자.
			int correct = 0;

            for (int i = 0; i < numbers.Length; i++)
            {
                for (int j = 0; j < guesses.Length; j++)
                {
                    if (numbers[i] == guesses[j])
                    {
                        correct++;
                        break;
                    }
                }
            }
  • numbers의 i번째와 guesses의 j번째가 둘이 같다면 correct를 하나 증가시킨다. 같으니까 더 이상 다음 비교를 할 필요가 없으니 break로 나가게 해준다. 이 break는 자기를 감싸는 하나의 반복문 밖에 못 나감.
    그럼 다음 반복이 시작되면서 또다시 검사 진행
  • 그런데 이렇게 동작했을 때 3개 * 3개를 검사했는데 3개가 correct가 나온다면?
            int correct = 0;

            for (int i = 0; i < numbers.Length; i++)
            {
                for (int j = 0; j < guesses.Length; j++)
                {
                    if (numbers[i] == guesses[j])
                    {
                        correct++;
                        break;
                    }
                }
            }
            
            attempt++;
            Console.WriteLine("시도 #" + attempt + " : " + correct + "개의 숫자를 맞추셨습니다.");
        }
  • 시도 횟수를 더해주고 몇 개를 맞췄는지도 알려주면 되겠다.
            attempt++;
            Console.WriteLine("시도 #" + attempt + " : " + correct + "개의 숫자를 맞추셨습니다.");

            if (correct == 3)
            {
                Console.WriteLine("축하합니다! 모든 숫자를 맞추셨습니다.");
                break;
            }
  • 그다음 모든 숫자가 다 맞은 경우 축하 메세지를 출력해 주고 break 해준다.
  • 이 break는 얘를 감싸고 있던 while문을 감싸는 break
  • 실행해 보면 숫자 맞추기 게임이 잘 진행된다.

다차원 배열

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

  // 다차원 배열 초기화
  array3[0, 0] = 1;
  array3[0, 1] = 2;
  array3[0, 2] = 3;
  array3[1, 0] = 4;
  array3[1, 1] = 5;
  array3[1, 2] = 6;

  // 선언과 함께 초기화
  int[,] array2D = new int[3, 4] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
  • new int[2, 3] = 3개짜리 배열을 2개 붙여놨다는 뜻
  • int[,]와 new int[2, 3] 처럼 일반 일차원 배열과는 다르게 쉼표를 넣어줌
  • '// 다차원 배열 초기화'처럼 접근할 때도 숫자값을 두 개 넣음. 앞이 행, 뒤가 열이라고 보면 된다.
  • 선언과 함께 초기화하는 방법도 있는데, 중괄호를 이용해서 바로 초기화 진행이 가능하다.
  // 3차원 배열의 선언과 초기화
  int[,,] array3D = new int[2, 3, 4] 
  {
      { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } },
      { { 13, 14, 15, 16 }, { 17, 18, 19, 20 }, { 21, 22, 23, 24 } }
  };
  • 3차원 배열은 4개짜리가 3갠데 2층인 구조라고 볼 수 있다.

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

  • 다차원 배열을 활용하면 복잡한 데이터 구조를 효율적으로 관리할 수 있다.
  • 2차원 배열은 행과 열로 이루어진 데이터 구조를 다루기에 적합하다.
  • 3차원 배열은 면, 행, 열로 이루어진 데이터 구조를 다루기에 적합하다.
  int[,] map = new int[5, 5];
  for (int i = 0; i < 5; i++)
  {
      for (int j = 0; j < 5; j++)
      {
          map[i, j] = i + j;
      }
  }

  for (int i = 0; i < 5; i++)
  {
      for (int j = 0; j < 5; j++)
      {
          Console.Write(map[i, j] + " ");
      }
      Console.WriteLine();
  }
  • 2차원은 map같은 걸 만들 때 많이 씀. 이것도 5, 5 map 배열
  • i < 5, j < 5로 해서 반복문을 5번씩 돌고 있다.
  • 채워 넣어진 값들을 아래 반복문에서 줄 별로 출력하고 있는 것

2차원 배열을 사용하여 게임 맵을 구현

        // 2차원 배열을 사용하여 게임 맵을 구현
        int[,] map = new int[5, 5]
        {
            { 1, 1, 1, 1, 1 },
            { 1, 0, 0, 0, 1 },
            { 1, 0, 1, 0, 1 },
            { 1, 0, 0, 0, 1 },
            { 1, 1, 1, 1, 1 },
        };

        for (int i = 0; i < 5; i++)
        {
            for (int j = 0; j < 5; j++)
            {
                if (map[i, j] == 1)
                {
                    Console.Write("■ ");
                }
                else
                {
                    Console.Write("□ ");
                }
            } 
            Console.WriteLine();
        }   
  • 이렇게 입력해주고 실행해보면 1이라고 입력한 데는 까만 상자가, 0이라고 입력한 데는 빈 상자가 출력돼 있다.
  • 실제로도 이런 식으로 map을 많이 만든다고 함

컬렉션

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

List

  • List는 가변적인 크기를 갖는 배열
  • List를 생성할 때는 List에 담을 자료형을 지정
  List<int> numbers = new List<int>(); // 빈 리스트 생성
  numbers.Add(1); // 리스트에 데이터 추가
  numbers.Add(2);
  numbers.Add(3);
  numbers.Remove(2); // 리스트에서 데이터 삭제

  foreach(int number in numbers) // 리스트 데이터 출력
  {
      Console.WriteLine(number);
  }
  • list (2)를 지워주고 foreach를 사용한다는 건 이 List에 들어있는 걸 i에 하나씩 꺼내오겠다는 뜻
  • 실행해 보면 2는 삭제됐기에 1과 3밖에 출력되지 않는다.
  • 이거랑 같은 방식의 코드를 for문으로 한번 구현해 보자.
        List<int> list = new List<int>();
        list.Add(1);
        list.Add(2);
        list.Add(3);
        
        list.Remove(2);

        for (int i = 0; i < list.Count; i++)
        {
            Console.WriteLine(list[i]);
        }
  • for문의 다른 점은 list.count라고 쓰고, Console에도 i에 대괄호를 사용해 0번째, 1번째 등의 인덱싱이 가능하다.

Dictionary

  • 딕셔너리(Dictionary)는 키와 값으로 구성된 데이터를 저장
  • 딕셔너리는 중복된 키를 가질 수 없으며, 키와 값의 쌍을 이루어 데이터를 저장
  using System.Collections.Generic;

  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);
  }
  • Dictionary는 key값과 value 값을 매칭시켜 놓음
  • Alice는 100, Bob은 80, Charlie는 90 이렇게
  • 그런데 여기서 Remove Bob을 했기 때문에 Bob-80이 사라지고 Alice랑 Charlie만 남은 것
  • 여기도 마찬가지로 foreach로 반복을 돌리는데 KeyValuePair로 돌리고 있다. 왜냐면 key값과 value값을 정해줘야 하기 때문에.
  • 그래서 Console.WriteLine에서 key와 value를 따로따로 출력하고 있다.

Stack

  • Stack은 후입선출(LIFO) 구조를 가진 자료구조
  • 바구니 모양을 생각하면 쉽다. 먼저 들어온 것부터 차곡차곡 쌓이니까 제일 마지막에 들어온 것이 먼저 나가야 함
  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 (마지막에 추가된 요소)
  • 비유하면 아래 -> 위 순서로 1 -> 2 -> 3 이렇게 쌓여 있는 상태
  • Pop을 진행했을 땐 제일 위에 있는 3이 나오게 된다.

Queue

  • 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 (가장 먼저 추가된 요소)
  • 여기서는 Enqueue와 Dequeue정도로 사용함
  • 이외에도 다양한 기능이 있는데 이후에 자세히 알아보자.

HashSet

  • HashSet은 중복되지 않은 요소들로 이루어진 집합
  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);
  }
  • List와 거의 유사하게 생겼지만 중복되지 않은 요소들이 있다는 점이 다름

배열과 리스트

  • 배열과 리스트의 차이를 알고 적절히 사용하자.
  • 리스트는 동적으로 크기를 조정할 수 있어 배열과는 다르게 유연한 데이터 구조를 구현할 수 있다.
  • 하지만 리스트를 무분별하게 사용하는 것은 좋지 않은 습관.
  1. 메모리 사용량 증가
    • 리스트는 동적으로 크기를 조정할 수 있어 배열보다 많은 메모리를 사용한다. 따라서 많은 데이터를 다루는 경우 리스트를 무분별하게 사용하면 메모리 사용량이 급격히 증가해 성능 저하를 유발할 수 있다.
  1. 데이터 접근 시간 증가
    • 리스트는 연결 리스트(linked list)로 구현되기 때문에, 인덱스를 이용한 데이터 접근이 배열보다 느리다. 리스트에서 특정 인덱스의 데이터를 찾기 위해서는 연결된 노드를 모두 순회해야 하기 때문. 이러한 이유로 리스트를 무분별하게 사용하면 데이터 접근 시간이 증가해 성능이 저하될 수 있다.
  2. 코드 복잡도 증가
    • 리스트는 동적으로 크기를 조정할 수 있기 때문에 데이터 추가, 삭제 등의 작업이 배열보다 간편하다. 하지만 이러한 유연성은 코드 복잡도를 증가시킬 수 있다. 리스트를 사용할 때는 데이터 추가, 삭제 등의 작업을 적절히 처리하는 코드를 작성해야 하므로, 코드의 가독성과 유지보수성이 저하될 수 있다.
  • 따라서 리스트를 무분별하게 사용하는 것은 좋지 않은 습관.
    데이터 구조를 선택할 때는, 데이터의 크기와 사용 목적을 고려해서 배열과 리스트 중 적절한 것을 선택해야 한다.
profile
...

0개의 댓글