9강에서는 rand에 대해 알아보겠습니다. 원래는 switch와 게임 만들기까지 함께 다루려고했는데,
rand자체를 설명하는데도 꽤 많은 양이 나와서 switch와 게임 만들기는 10강으로 넘겼습니다.
🔶 rand()
프로그래밍에서 무작위 숫자가 필요할 땐 rand()라는 함수를 씁니다.
예를 들어 컴퓨터가 숫자 하나를 골라놓고 "내가 뭘 골랐는지 맞춰봐~" 하는 게임을 만들려면
그 숫자를 사람이 아니라 컴퓨터가 알아서 정하게 해야만 합니다.
이 때 그 역할을 해주는 게 rand()입니다.
먼저 아래의 코드를 입력해 봅시다.
int num = rand();
이는 num이라는 변수에 무작위 값을 매기는 코드입니다.
다만 이렇게만 띡 하고 끝내버리면 숫자가 너무 커지게 됩니다.
그래서 설정해야 할 숫자 범위만을 뽑아내기 위해 % 연산자를 써야합니다.
🔹 % 연산자
% 연산자는 rand() 가 만든 큰 숫자 중에서 내가 원하는 범위만큼을 잘라내는 도구 역할을 합니다.
그냥 rand()만 썼을 땐 숫자가 너무 크고 범위도 너무 넓기 때문에, 실제 내가 제어할 범위를 설정해 줘야합니다.
이 때 % 연산자를 써서 원하는 범위를 설정할 수 있습니다.
위의 코드에서 % 연산자를 넣고 그 뒤에 숫자를 적게되면 범위가 설정되죠
int num = rand() % 10; // 0~9 사이 숫자만 남김
코드를 이렇게 적었다면 딱 10개까지만 연산하게 됩니다.
C++은 1이 아닌 0부터 시작하기 때문에 10을 입력하면 1~10이 아닌 0~9가 됩니다.
만약 이걸 1~10으로 바꾸고 싶다면 10 뒤에 +1을 해주면 됩니다.
여러가지 예시를 표로 만들어서 더 잘 이해해봅시다.
코드 | 결과 범위 |
rand() % 2 | 0 또는 1 (두 가지 경우) |
rand() % 3 | 0, 1, 2 (세 가지 경우) |
rand() % 100 | 0 ~ 99 (100가지 경우) |
rand() % 100 + 1 | 1 ~ 100 (시작점 조정까지 포함) |
🔹 rand()는 랜덤이 아니다?
다시 rand()로 돌아와서 이어가겠습니다.
사실 rand()는 완전히 랜덤이 아닙니다.
그래서 막상 써보면 항상 비슷한 패턴으로 숫자를 만들어내죠.
for문을 이용한 코드를 통해 테스트를 해보겠습니다.
printf("난수 초기화 이전\n\n");
for (int i = 0; i < 10; i++)
{
printf("%d", rand() % 10);
}
- printf를 통해 가장 먼저 "난수 초기화 이전"을 표시해 줬습니다.
- 이후 for문을 이용해 i = 0이고 i < 10일 경우 i++을 해줬습니다.
- 그리고 rand()값을 % 10 줬으니, 0~9까지 총 10개의 난수가 출력될 겁니다.
자 이 코드를 적어놓고 한 번 출력해봅시다. 위처럼 숫자 10개가 랜덤하게 뜰 겁니다.
여기까지만 보면 "어? 랜덤으로 나오는거 같은데?"라고 생각할 수 있지만, 껐다가 한 번 더 실행을 해봅시다.
그럼 분명 실행했던 수와 완전히 똑같은 값이 다시 출력되는걸 알 수 있습니다.
몇 번을 다시해봐도 이 수는 항상 똑같이 나옵니다. 즉 '무작위(랜덤) 상태가 아니다'라는 거죠.
왜 그럴까요?
그 이유는 우리의 생각과는 다르게 컴퓨터는 스스로 무작위성을 만들 수 없기 때문입니다.
그래서 rand()는 정해진 알고리즘을 기반으로 "그럴듯한 숫자"를 만들어냅니다.
이걸 우리는 의사 난수(Pseudo-Random Number)라고 부르는데, 지금 굳이 이 용어까지 알 필요는 없습니다.
즉, 아무 설정 없이 rand()만 계속 쓰면 매번 실행할 때마다 비슷한 숫자들이 반복되게 됩니다.
그래서 우리는 다른 방법을 찾아야 합니다.
🔹 srand()와 time(NULL)
위의 문제점을 해결하기 위해 등장하는 것이 바로 srand()와 time(NULL)입니다.
srand()는 rand()의 시작점을 바꿔주는 함수입니다. 이걸 "랜덤 시드(seed)를 심는다"라고 표현합니다. (seed + random)
프로그래밍에서 ‘시드’란 랜덤 숫자를 만들어내는 출발점이 되는 숫자를 말합니다.
다만 이 srand()를 쓰려면 time(NULL)이라는 한가지 함수를 추가해줘야 합니다.
time(NULL)은 현재 시간을 초 단위로 반환하는 함수입니다.
즉 1초마다 값이 바뀌고, 그걸 시드로 주면, 실행할 때마다 완전히 다른 난수 패턴이 나오는 것이죠.
또한 이 time(NULL)을 쓰기 위해서는 #include <time.h>가 꼭 필요합니다.
이 라이브러리는 우리가 맨 위에 입력했던 #include <stdio.h> 밑에 붙여넣으면 됩니다.
혹시 저걸 붙였는데도 정상적으로 코드 실행이 안된다면 밑에 #include <stdlib.h>도 추가해주세요
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
🔹 #include <time.h>는 왜 필요한가
C 언어에는 기본적으로 시간과 관련된 기능이 없습니다.
그래서 time()이나 time_t, NULL, clock() 같은 시간 관련 기능을 쓰려면
시간 관련 라이브러리인 <time.h>를 포함해야 합니다.
만약 이를 안 넣고 time(NULL)을 쓸 시에는 컴파일 에러가 납니다.
그럼 이제 원리는 다 알았으니 srand()를 이용해 난수를 초기화시키는 코드를 만들어봅시다.
코드 작성은 위와 거의 동일하지만, 여기에 rand()에 srand(time(NULL))도 추가로 넣어줄 겁니다.
printf("난수 초기화 이후\n\n");
srand(time(NULL));
for (int i = 0; i < 10; i++)
{
printf("%d", rand() % 10);
}
자 최종적으로 코드가 이렇게 바꼈습니다. for문 위에 srand(time(NULL))을 넣어줬죠.
이제 실행을 해 보면 아까와는 다르게 매번 숫자가 바뀌는 것을 확인할 수 있습니다.
'C++ > 입문' 카테고리의 다른 글
[#10] switch문과 숫자 맞추기 게임 만들기 (4) | 2025.06.12 |
---|---|
[#8] break, continue, || 에 대해서 알아보자 (0) | 2025.06.11 |
[#7] 조건문(if, else if, else)으로 '숫자 맞추기 게임' 만들기 (2) | 2025.06.09 |
[#6] 반복문을 이용해서 피라미드 게임 만들기 (3) | 2025.06.02 |
[#5] 중첩(이중, 삼중) 반복문과 별 쌓기 (4) | 2025.05.30 |