C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
91: Generating Random Numbers with rand and srand
Alright, let's try to build something simple: a digital six-sided die for a tabletop game. It sounds trivial, but C handles "randomness" in a way that often trips people up the first time they touch it. I'll walk you through how I usually figure this out when I've forgotten the specifics.
The "Wait, Why Is This the Same?" Moment
First instinct? Just call rand(). I'll throw together a quick loop to simulate rolling a die five times and see what we get.
#include <stdio.h>
#include <stdlib.h>
int main() {
for(int i = 0; i < 5; i++) {
printf("%d ", rand());
}
return 0;
}
I run this, and I get: 41 18467 6334 26500 789. Okay, looks random enough. But here's the weird part—I run the program again, and I get 41 18467 6334 26500 789 again. And again. Every single time.
This is because rand() isn't actually random; it's a pseudo-random number generator. It uses a mathematical formula to produce a sequence of numbers. That formula starts with a "seed" value. If the seed is always the same (which it is by default), the sequence will be identical every time you launch the app. That's great for debugging a bug in a specific sequence, but terrible for a game.
Planting a Seed
To fix this, I need to change the seed. C gives us srand() (short for seed-rand) for this. I'll try giving it a hardcoded number just to see if it changes the output.
srand(123); // Planting a seed of 123
for(int i = 0; i < 5; i++) {
printf("%d ", rand());
}
Now I get a different sequence than before, but if I run the program again, I still get that same new sequence. Using a hardcoded number just swaps one predictable sequence for another. To make it feel truly random to the user, I need a seed that changes every time the program starts. The easiest way? The current system time.
I'll pull in <time.h> and use time(NULL), which returns the number of seconds since the Epoch. Since that number is always increasing, the seed will be different every time you hit "Run".
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL)); // Seed based on current time
for(int i = 0; i < 5; i++) {
printf("%d ", rand());
}
return 0;
}
Now, every time I run it, I get a totally different set of numbers. We've solved the predictability problem.
Squeezing the Range
The problem now is that rand() returns massive integers—anywhere from 0 up to RAND_MAX (which is at least 32,767). I can't use a number like 26,500 for a six-sided die. I need a way to "clamp" this value.
I'll use the modulo operator %. If I take rand() % 6, the remainder will always be between 0 and 5. But a die is 1 to 6, not 0 to 5. A simple + 1 shift fixes that.
int roll = (rand() % 6) + 1;
I'll put it all together now. I'll wrap the roll in a function to keep the main clean. One quick tip: notice I only call srand() once at the very start of the program. A common mistake is putting srand() inside a loop. If you do that, and the loop runs fast enough, time(NULL) will return the same second for every iteration, and you'll end up with the same "random" number repeated five times. Always seed once, then harvest as many numbers as you need.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int roll_die() {
return (rand() % 6) + 1;
}
int main() {
srand(time(NULL));
printf("Rolling the dice...\n");
for(int i = 0; i < 3; i++) {
printf("Roll %d: %d\n", i + 1, roll_die());
}
return 0;
}
📋 Practical Task
Build a Critical Hit Simulator
Write a program that simulates a combat encounter in a game. The program should perform the following:
- Seed the random number generator using the current time.
- Generate a random number between 1 and 100 to represent an "attack roll".
- If the roll is 95 or higher, print "CRITICAL HIT!" and a bonus damage value (a random number between 20 and 50).
- If the roll is between 1 and 94, print "Normal Hit" and a standard damage value (a random number between 5 and 19).
Make sure your damage ranges are calculated correctly using the (rand() % range) + offset logic we discussed.
There are no comments for now.