클라이언트/ 서버/ 엔지니어 " 게임 개발자"를 향한 매일의 공부일지

반복문과 배열 그리고 예외 처리 25 - 연습문제 실습편 풀어보기 2 : 6~10번 문제 본문

프로그래밍 언어/자바

반복문과 배열 그리고 예외 처리 25 - 연습문제 실습편 풀어보기 2 : 6~10번 문제

huenuri 2024. 8. 15. 09:07

이제 연습문제 풀기 두번째 학습을 시작해본다. 오늘까지 16문제를 다 풀려고 했는데 과연 가능할지 의문이다. 언제나 내가 세운 학습목표보다 절반도 채우지 못하는 것 같다.

그래도 목표를 세우면 그에 맞게 노력을 하니 훨씬 더 좋다고 생각한다. 이제 공부를 시작해보자!


 

 

 

 

 

연습문제 실습편 풀어보기 2

 

문제 6번

배열과 반복문을 이용하여 프로그램을 작성해보자. 키보드에서 정수로 된 돈의 액수를 입력 받아 오만원 권, 만원 권, 천원 권 , 500원 , 100원, 50원, 10원 ,1원짜리 동전 몇 개로 변환되는지 출력하기

int [] unit = {50000, 10000, 1000, 500, 100, 50, 10, 1};	// 환산할 돈의 종류

 

 

 

여기까지밖에 짜지 못했다. 나머지는 자료를 통해 해결방법을 찾는 중이다. 이전에 똑같은 문제를 풀었었는데 2장에서는 조건문을 사용해서 돈을 일일이 몫과 나머지로 연산해서 담아주었다. 코드가 굉장히 길었던 기억이 난다. 하지만 반복문과 배열을 사용하면 이 식이 매우 간단해졌다.


 

 

 

 

사실 이전 코드에서 별로 고친 것은 없었다. 두 줄 정도를 추가했을 뿐이었다. 정말 못 풀었다고 생각했는데 그래도 여기까지 생각할 수 있다는 것으로 잘하고 있는 것이다. 배열을 사용하니 이렇게 간단해지다니 너무나도 놀라웠다.

프로그래밍은 하면 할수록 정말 재미있다.


 

 

 

 

문제 7번

정수 10개를 저장하는 배열을 만들고 1~10까지 범위의 정수를 랜덤하게 생성하여 배열에 저장하라. 그리고 배열에 든 숫자들과 평균 출력하기

 

 

 

어제 이 문제를 풀다가 너무 졸려서 하지 못하고 다음날 새벽 6시에 일어나서 공부를 시작해본다. 요즘은 6시에 일어나는 것도 쉽지 않다. 1시간 정도는 일정을 정리하고 7시에 새벽 공부를 시작했다.

여기서 좀 이해가 되지 않은 코드를 정리해볼 것이다. 지금까지는 Random으로 난수를 생성했으나 이번에 처음으로 Math.random 클래스를 사용했는데 이 둘의 차이가 무엇인지 궁금했다.


 

 

램덤 수를 생성할 때 Random과 Math.random()의 차이점

 

1. Math.random()을 사용한 방법

int rd = (int)(Math.random() * 10 + 1);

 

  • 설명:
    • Math.random() 메서드는 0.0 이상 1.0 미만의 난수를 생성한다.
    • (Math.random() * 10)을 통해 0.0부터 10.0 미만의 실수를 생성한 후, (int)를 사용하여 이 값을 정수로 변환한다.
    • + 1을 추가하여 1부터 10까지의 범위를 만듭니다.
  • 특징:
    • 단순성 : 코드가 간단하고 빠르게 사용할 수 있다다.
    • 정해진 범위 : 범위를 쉽게 조정할 수 있지만, 난수 생성에 대한 더 복잡한 요구 사항을 충족시키기에는 제한적일 수 있다.
    • 스레드 안전성 : Math.random()은 스레드 안전한 메서드이다.
    • 시드(seed) : 기본적으로 내부적으로 설정된 시드값을 사용하며, 시드를 사용자에게 노출하지 않는다.

 

2. Random 클래스를 사용한 방법

Random random = new Random(); 
int rd = random.nextInt(10) + 1;

 

  • 설명:
    • Random 클래스는 보다 고급의 난수 생성기를 제공한다.
    • random.nextInt(10)은 0부터 9까지의 난수를 생성하며, 여기에 + 1을 추가하여 1부터 10까지의 범위를 만듭니다.
    • Random 클래스는 난수 생성의 여러 메서드를 제공합니다 (nextInt(), nextDouble(), nextBoolean(), 등).
  • 특징:
    • 다양성 : Random 클래스는 다양한 데이터 타입의 난수를 생성하는 메서드를 제공한다.
    • 시드(seed) : Random 클래스는 사용자가 시드를 설정할 수 있도록 하여, 난수 생성이 더 제어 가능해진다. 같은 시드를 사용하면 항상 같은 난수 시퀀스를 생성한다.
    • 객체 지향 : Random 클래스는 객체로 생성되므로, 여러 인스턴스를 만들 수 있으며, 각각의 인스턴스는 독립된 난수 시퀀스를 가질 수 있다.
    • 스레드 안전성: Random 클래스는 기본적으로 스레드가 안전하지 않다. 다중 스레드 환경에서 Random 객체를 공유하면 문제가 발생할 수 있으므로, 필요시 ThreadLocalRandom을 사용하는 것이 좋다.

 

결론

  • 간단한 난수 생성: 빠르고 간단한 난수 생성이 필요한 경우 Math.random()을 사용한다.
  • 다양한 요구사항: 특정 시드를 설정하거나, 다양한 유형의 난수를 생성하는 등 더 복잡한 요구가 있을 경우 Random 클래스를 사용한다.

 

 

 

 

 

문제 8번

정수를 몇 개 저장할지 키보드로부터 개수를 입력받아(100보다 작은 개수) 정수 배열을 생성하고, 이곳에 1~100까지 범위의 정수를 랜덤으로 삽입하라. 배열에는 같은 수가 없도록 하고 배열을 출력하기

 

혼자서 풀어보기

 

빨간줄도 표시되고 문제를 잘못 푼 게 많아서 찾아보면서 다시 풀어보았다.


 

 

 

 

다시 풀어보기

 

 

이렇게 코드가 길다. 100이 넘어가는 상황도 조건으로 만들어주었고 중복 체크도 했다. 근데 100이 넘어갈 때 왜 return을 사용하는지 이해가 되지 않아서 관련 내용을 찾아보았다. 정수가 10개 단위로 잘 출력이 되고 있다. 그리고 중복되는 수도 없다.


 

 

 

1. return에 경고 표시가 되는 이유

return; 문장 옆에 아무것도 없는 경우, 이는 메서드의 실행을 중지하고 호출자에게 제어를 반환하는 역할을 한다. 이 문장은 주로 void 타입의 메서드에서 사용되며, 메서드를 즉시 종료하고 싶을 때 사용된다.

노란줄이 표시되는 것은 "dead code" 경고일 가능성이 크다. 즉, 이후의 코드가 실행되지 않기 때문에 코드의 의미가 없어졌다는 경고이다. return;을 사용하면 그 뒤에 있는 코드가 실행되지 않으므로, 만약 return; 이후에 코드가 작성되어 있다면 해당 코드가 쓸모없다는 경고를 나타난다.

 

노란줄을 없애는 방법

  1. return 이후의 코드를 제거:
    • 만약 return; 이후에 불필요한 코드가 존재한다면, 해당 코드를 제거해야 한다. 예를 들어, return; 뒤에 코드가 있으면 이 코드가 실행되지 않기 때문에 경고가 나타날 수 있다.
     
    위 코드에서 return; 뒤의 코드가 실행되지 않을 것이라는 경고가 뜨는 상황이다. 이 경우에는 return; 뒤의 코드를 삭제하거나, return;을 제거할 수 있다.

 

  2. return 문 사용 위치를 조정:

  • return; 문이 필요한 위치에 사용되었는지 확인한다. 예를 들어, 조건문 내에서 메서드를 종료하는 것이 필요하지 않다면 return; 문을 제거할 수 있다

 3. return과 값을 반환하는 경우:

  • 만약 메서드가 void가 아닌 다른 반환 타입을 가지며 값을 반환해야 한다면, return 뒤에 반환할 값을 지정해야 한다.
if (count > 100) { System.out.println("100 이하의 값을 입력하세요."); return; }

 

요약

  • 의도한 동작을 유지하려면 return;을 그대로 두는 것이 중요하다. 특히 메서드의 특정 조건에서 실행을 멈추고 싶을 때 유용하다.
  • return;을 제거하면 메서드가 계속 실행되므로, 이후 코드가 실행되어도 문제가 없는지 확인해야 한다. 그렇지 않으면 코드가 의도와 다르게 동작할 수 있으며, 이로 인해 오류나 예기치 않은 결과가 발생할 수 있다.

 

 

 

 

return은 그냥 두기로 했다. return을 없앴더니 계속해서 다음 수를 입력하는 공간이 나타나며 다음 코드로 넘어가지 않았다. return은 여기서 종료하는 기능이 있는 것이다. 여기서는 0으로 값을 맞출 일이 없기에 그 뒤에 아무것도 표시할 필요가 없다. 한 문제를 푸는데 정말 많은 시간이 걸린다.

관련된 이론 학습도 병행하기 때문이다. 그래도 난 천천히 공부해보기로 했다. 뭔가를 빨리 배우는 것보다 훨씬 더 깊은 학습이 되는 걸 느끼고 있다.


 

 

 

2. j값의 의미

for (int j = 0; j < i; j++) {
    if (arr[j] == randomNum) {
        isDuplicate = true;
        break;
    }
}

 

이 코드가 좀 이해가 되지 않았다. j < i가 무슨 말인지..

 

코드 설명

  1. for (int j = 0; j < i; j++):
    • 이 for 루프는 현재까지 배열에 저장된 모든 값을 순회한다.
    • j는 0부터 i-1까지 증가하며, 배열 arr의 앞쪽에 있는 요소들을 하나씩 검사합니다.
    • i는 현재 배열에 숫자가 몇 개 저장되어 있는지를 나타내며, 새로 생성된 랜덤 숫자가 배열의 몇 번째 인덱스에 저장될지를 의미한다.
    • 따라서 j < i로 루프를 돌리면, 배열의 0번 인덱스부터 현재 i번째 인덱스 직전까지의 모든 값을 검사하게 된다.
  2. if (arr[j] == randomNum):
    • 배열 arr의 j번째 인덱스에 저장된 값이 새로 생성된 randomNum과 같은지를 확인한다.
    • 즉, arr[j]에 이미 randomNum이 저장되어 있는지 확인하는 과정이다.
  3. isDuplicate = true;:
    • 만약 arr[j]와 randomNum이 같다면, 이미 배열에 같은 숫자가 있다는 의미이다.
    • 이 경우 isDuplicate를 true로 설정하여 중복이 있음을 표시한다.
  4. break;:
    • 중복이 발견되면 더 이상 반복문을 실행할 필요가 없으므로, break;를 사용해 for 루프를 즉시 종료한다.
    • 이렇게 하면 중복이 발견되면 불필요한 추가 검사를 하지 않으므로, 효율성을 높일 수 있다.

 

왜 j를 사용하는지

  • 배열의 모든 기존 값을 확인하기 위해: j는 배열의 앞부분, 즉 이미 저장된 값들을 순차적으로 접근하기 위해 사용된다. j는 0부터 시작해서 i-1까지의 모든 인덱스를 가리키며, 이 범위 내에서 중복되는 값이 있는지를 검사한다.
  • 이전 값들만 검사하기 위해: 현재 새로 생성된 randomNum은 아직 배열에 저장되지 않았기 때문에, 검사할 필요가 없다. 따라서 j를 0부터 i-1까지로 설정하여 이미 배열에 저장된 값들만 확인한다.

 

이제 모든 내용들을 확실히 이해했다. 드디어 다음 문제로 넘어갈 수 있을 것 같다.


 

 

 

 

문제 9번

4 x 4의 2차원 배열을 만들고 이곳에 1에서 10까지 범위의 정수를 랜덤하게 생성하여 정수 16개를 배열에 저장하라. 그리고 2차원 배열을 화면에 출력하라.

 

 

혼자서는 여기까지밖에 풀지 못했다. 난수가 생성되지 않아 1만 출력이 되었고 다시 하려니 수를 담을 수 없다는 오류 표시가 떴다.


 

 

 

 

다시 풀어보기

 

이 문제는 앞의 문제처럼 4칸씩 나눌 필요가 없다. 왜냐하면 처음부터 4개씩 나누어져 있는 2차원 배열이기 때문이다. 알고 나면 풀 수 있지만 알기 전까지는 정말 어려웠다. 특히 난수 함수를 사용하는 부분이 어려웠다.

그리고 처음에는 탭 키를 잘못 써서 /t가 계속 출력이 되었다. 반대로 써야 한다는 것에 주의해야 할 것이다.


 

 

 

 

 

 

문제 10번

4 x 4의 2차원 배열을 만들고 이곳에 1에서 10까지 범위의 정수를 랜덤하게 생성하여 임의의 위치에 삽입하라. 동일한 정수가 있어도 상관없다. 나머지 6개의 숫자는 모두 0이며 만들어진 2차원 배열을 화면에 출력하기

 

 

이 문제는 거의 혼자서 풀었다. 개수가 10개가 넘어가면 나머지를 0으로 채운다는 조건만 생성하면 된다. 앞의 문제와 많이 유사하다.


 

 

 

 

학습을 마치고

이렇게 4문제를 푸는데(어제 1개) 무려 2시간이나 걸렸다. 그래도 많은 것들을 배우는 시간이 되었다. 처음에는 배열을 생성하는 것도 난수를 만드는 것도 몰랐으나 이제는 많이 익숙해져서 혼자서도 어느 정도 만들 수 있게 된 것이다.

11번부터는 많이 어렵고 복잡한 문제들이 나와있지만 이 문제도 모두 풀고 내 것으로 만들어볼 것이다.

 

그리고 이전에 학습에서 그러했듯이 이 문제도 다시 풀어보며 복습을 할 것이다. 그때가 되면 지금보다 훨씬 더 많은 것을 깨달을테니 기대해봐야지~