Posted December 31, 2023 Hi all, I am VERY new to C and I am learning it by making a small program of Rock, paper, scissors. Now the way it works is that the user enters either Rock, paper or scissors and the program choose a random choice by crossing a random number. Here is my logic about the way I want to go about this: char RPS[2] = {"Rock", "Paper", "Scissors"}; //I need to give it a range of from [0, 2](inclusive) so that it can print the element out at whatever the random number is but I dont know how to do this //Also the way I made the list is wrong so I need some help there. If someone can explain me how to make a string in C I would appreciate it. Thanks in advance Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted December 31, 2023 C does not have a string data type, it only has char arrays. The array you've created has a size of two, so it can only contain two characters, not three strings. So for your use case you'd need an array of char arrays (char[][]). But since you only have three choices, it's likely easier to just pick a random number, then use a switch case to print the appropriate output. One way you can limit the range of a random number is by using a modulo division (which is not ideal, but it'll do): int r = rand() % 3; This generates a random number, then divides it by 3 and returns the remainder, which is a number between 0–2. Now just switch over the random number and print the appropriate word switch(r) { case 0: // print Rock break; case 1: // print Paper break; default: // print Scissors } Spoiler #include <time.h> #include <stdio.h> #include <stdlib.h> void main() { char values[3][8] = { "Rock", "Paper", "Scissors" }; srand(time(NULL)); int n = rand() % 3; printf("%d - %s\n", n, values[n]); } Remember to either quote or @mention others, so they are notified of your reply Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted December 31, 2023 Make sure to include stdlib.h for rand() to work. Microsoft owns my soul. Also, Dell is evil, but HP kinda nice. Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted December 31, 2023 Author Thanks for all the help but can you explain how to make a "string" in C and what srand is(I am really confused on what a seed is since other languages don't have such a concept)? Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted December 31, 2023 1 hour ago, goatedpenguin said: Thanks for all the help but can you explain how to make a "string" in C As I said above, C does not have a string data type. The only way to get a "string" in C is to use a char array. For example you could also create the array of "strings" in my example above like this: char rock[] = "Rock"; char paper[] = "Paper"; char scissors[] = "Scissors"; char *values[] = {rock, paper, scissors}; This creates three char arrays, containing "Rock", "Paper", "Scissors", then an array of char-pointers (with length 3), pointing to each of them. 1 hour ago, goatedpenguin said: I am really confused on what a seed is since other languages don't have such a concept Most languages have this concept, actually. Though more modern languages may choose to hide it from the developer (at least by default). For example in Java, if you do final var random = new Random(); it actually generates a new seed for this instance of Random internally. But you can explicitly specify a seed, if you want: final var random = new Random(0); Random numbers are generally only pseudo-random. They use an algorithm that produces a seemingly random sequence of numbers. When you start with the same seed, the sequence this algorithm produces is always the same. That's why you typically use something like the current date (in milliseconds) as a seed, to ensure the sequence is different from the last time. You should only seed the random number generator once (e.g. on app start) For example, if I do this in C, the sequence of random numbers returned by rand is always the same: srand(0); for(int n = 0; n < 100; n++) { int n = rand(); printf("%d,", n); } Run this code a few times, and you'll see that is returns the same 100 "random" numbers each time. Which would make for a rather boring game of rock, paper, scissors, since you can now predict what the program will choose. If you use "srand(time(NULL));" instead, the sequence is a different one each time. Remember to either quote or @mention others, so they are notified of your reply Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted December 31, 2023 Author Just now, Eigenvektor said: As I said above, C does not have a string data type. The only way to get a "string" in C is to use a char array. For example you could also create the array of "strings" in my example above like this: char rock[] = "Rock"; char paper[] = "Paper"; char scissors[] = "Scissors"; char *values[] = {rock, paper, scissors}; This creates three char arrays, containing "Rock", "Paper", "Scissors", then an array of char-pointers (with length 3), pointing to each of them. Most languages have this concept, actually. Though more modern languages may choose to hide it from the developer (at least by default). For example in Java, if you do final var random = new Random(); it actually generates a new seed for this instance of Random internally. But you can explicitly specify a seed, if you want: final var random = new Random(0); Random numbers are generally only pseudo-random. They use an algorithm that produces a seemingly random sequence of numbers. When you start with the same seed, the sequence this algorithm produces is always the same. That's why you typically use something like the current date (in milliseconds) as a seed, to ensure the sequence is different from the last time. You should only seed the random number generator once (e.g. on app start) For example, if I do this in C, the sequence of random numbers returned by rand is always the same: srand(0); for(int n = 0; n < 100; n++) { int n = rand(); printf("%d,", n); } Run this code a few times, and you'll see that is returns the same 100 "random" numbers each time. Which would make for a rather boring game of rock, paper, scissors, since you can now predict what the program will choose. If you use "srand(time(NULL));" instead, the sequence is a different one each time. Thanks for all the help I will share the code once I am done on this post so that yall can give me some suggestions for improving it. Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted December 31, 2023 4 hours ago, goatedpenguin said: Thanks for all the help but can you explain how to make a "string" in C and what srand is(I am really confused on what a seed is since other languages don't have such a concept)? Eigenvektor did a great job explaining how to use srand, but I can explain a bit more about strings in C. In C, a string is just an array of chars ending with a null byte. We can construct a string from scratch like this: #include <stdio.h> int main() { // Allocate space to hold the string char string[10]; // Place characters in the array string[0] = 'H'; string[1] = 'e'; string[2] = 'l'; string[3] = 'l'; string[4] = 'o'; // Don't forget the null byte string[5] = '\0'; // Print the string to the terminal puts(string); return 0; } This prints out Hello to the terminal. Note that even though our array has enough space to store 10 chars, only 5 get printed out. This is because functions operating on strings, like puts and strlen, stop when they encounter a null byte. That's the '\0' in the code above. If your string doesn't end with a null byte, then string functions can run further than they should and access invalid memory. That being said, you most likely won't work with strings in this way very often. It's more convenient to use string literals like what you did in your original post. All three of these are valid ways of storing a string using string literals: // String literals are automatically null-terminated char s1[6] = "Hello"; char s2[] = "Hello"; char* s3 = "Hello"; The difference between the first two methods and the third is that the third is read-only. This is because the first two strings are allocated on the stack while the third is allocated in a read-only section of the program. For example, we're able to modify the first two strings no problem: #include <stdio.h> int main() { // String literals are automatically null-terminated char s1[6] = "Hello"; char s2[] = "Hello"; char* s3 = "Hello"; // Modify the first two strings s1[1] = 'a'; s2[0] = 'Y'; // Print the strings to the terminal puts(s1); puts(s2); puts(s3); return 0; } But trying to modify the third string crashes the program with a segmentation fault, because we tried writing to read-only memory. #include <stdio.h> int main() { // String literals are automatically null-terminated char s1[6] = "Hello"; char s2[] = "Hello"; char* s3 = "Hello"; // Try to modify the third string s3[1] = 'a'; // Print the strings to the terminal puts(s1); puts(s2); puts(s3); return 0; } The advantage of using string literals is that you can let the compiler decide how to store the string, so you don't have to worry about the size of the array or forgetting the null terminator. Lastly, here's how I would write the code you initially posted: Spoiler #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { char* RPS[3] = {"Rock", "Paper", "Scissors"}; // Generate a random number between 0 and 2 (inclusive) srand(time(NULL)); int index = rand() % 3; printf("%s\n", RPS[index]); return 0; } Computer engineering grad student, cybersecurity researcher, and hobbyist embedded systems developer Daily Driver: CPU: Ryzen 7 4800H | GPU: RTX 2060 | RAM: 16GB DDR4 3200MHz C16 Gaming PC: CPU: Ryzen 5 5600X | GPU: EVGA RTX 2080Ti | RAM: 32GB DDR4 3200MHz C16 Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 1 Author Thank you so much for clearing all the misconceptions for now i am going to keep my code simple and not use pointers yet since i don’t have a good understanding of them. Again thanks everyone for the help i will make sure to give a update of my code in a lil bit. Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 2 Author So I have finished my program and it is a bit more nuanced but the while loop in my program is screwing it up and its not working. Code is below, suggestions to improve it will be great too thanks #include <stdio.h> #include <stdlib.h> #include <time.h> int main(){ //var init and set a random num srand(time(NULL)); int random = rand() % 3; char RPS[3][9] = {"Rock", "Paper", "Scissors"}; char Input_RPS[9] = {""}; char *computer_choice; computer_choice = RPS[random]; //logic while(1){ printf("Enter Rock, Paper or Scissors and see if you win! Enter q to quit the program. All lower caps! "); scanf("%s", Input_RPS); if(Input_RPS == "q"){ printf("Sorry to see you go"); break; } else if(computer_choice == Input_RPS){ printf("I choose the same one too its a draw! Gl to both of us next time ;) "); } else if(computer_choice == "Rock" && Input_RPS == "paper"){ printf("You won!"); } else if(computer_choice == "Paper" && Input_RPS == "Rock"){ printf("You lost!"); } else if(computer_choice == "Rock" && Input_RPS == "scissors"){ printf("You lost!"); } else if(computer_choice == "Scissors" && Input_RPS == "rock"){ printf("You won!"); } else if(computer_choice == "Paper" && Input_RPS == "scissors"){ printf("You won!"); } else if(computer_choice == "Scissors" && Input_RPS == "paper"){ printf("You lost!"); } } } Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 2 In C, you cannot use == to check for string equality. This is because the == operator checks if the strings' pointers are equal, rather than checking the characters they contain. To fix this, use the strcmp function. strcmp will return 0 if the two strings are equal. For example, this code: if(Input_RPS == "q"){ printf("Sorry to see you go"); break; } would be correctly written as: if(strcmp(Input_RPS, "q") == 0){ printf("Sorry to see you go"); break; } Computer engineering grad student, cybersecurity researcher, and hobbyist embedded systems developer Daily Driver: CPU: Ryzen 7 4800H | GPU: RTX 2060 | RAM: 16GB DDR4 3200MHz C16 Gaming PC: CPU: Ryzen 5 5600X | GPU: EVGA RTX 2080Ti | RAM: 32GB DDR4 3200MHz C16 Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 3 Author 8 hours ago, dcgreen2k said: In C, you cannot use == to check for string equality. This is because the == operator checks if the strings' pointers are equal, rather than checking the characters they contain. To fix this, use the strcmp function. strcmp will return 0 if the two strings are equal. For example, this code: if(Input_RPS == "q"){ printf("Sorry to see you go"); break; } would be correctly written as: if(strcmp(Input_RPS, "q") == 0){ printf("Sorry to see you go"); break; } I see thanks for the help, one questions though, if I #include many headers could this slow the performance of a program and what is the difference between including a header and importing a module(like python has modules but C has headers are they the same thing or do they differ a bit?) Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 3 1 hour ago, goatedpenguin said: I see thanks for the help, one questions though, if I #include many headers could this slow the performance of a program and what is the difference between including a header and importing a module(like python has modules but C has headers are they the same thing or do they differ a bit?) Including headers in C does not slow down the program. It can only slow down compilation, but this isn't something you should be worried about. Including a header and importing a module let you do similar things but are very different under the hood. In C and C++, including a header is very simple - the compiler copies and pastes the contents of the header file into your source code file where the #include statement is. Python's import statement is much more complex and I'm not that familiar with the specifics of it. However, imports are done at runtime since Python code isn't compiled in the same way C code is. In short: C's #include: May slow down compilation, no effect on runtime speed Python's import: May slow down runtime Neither of these are things you should worry about, though Computer engineering grad student, cybersecurity researcher, and hobbyist embedded systems developer Daily Driver: CPU: Ryzen 7 4800H | GPU: RTX 2060 | RAM: 16GB DDR4 3200MHz C16 Gaming PC: CPU: Ryzen 5 5600X | GPU: EVGA RTX 2080Ti | RAM: 32GB DDR4 3200MHz C16 Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 3 13 hours ago, dcgreen2k said: To fix this, use the strcmp function. strcmp will return 0 if the two strings are equal. I never really understood why stricmp was never implemented in the C standard (or at least not the ones I learned formally)...although I just import the Windows stuff so I get stricmp. Anyways @goatedpenguin, one thing to note as well strcmp doesn't handle lower case and upper case differences. So strcmp("rock", "Rock") will not be the same according to it. Just something to keep in mind when you are testing. To explain a bit why "cat" == variable_with_cat doesn't work though, you will need to think of C in terms of what it's comparing When you define something like char var[4] = "cat"; char var2[4] = "cat"; There is a place in memory which stores the value for cat for var and also another area where it stores var2...now in C, strings like that the variable just holds the memory address. So like var might = 0x00234; in memory, and var2 might = 0x00238; in memory. So when you compare var == var2, you actually are comparing 0x00234 == 0x00238. That is why comparing doesn't work. As a note, you have also capitalized Rock in one of the cases...which you told the user to write in lower case Okay, not for commenting about your code. It might be beneficial to convert what the user inputs into just a number...instead of all comparing the char*. const char* validOptions[] = {"rock", "paper", "scissors"}; //returns -1 if not a valid option or it will return the valid option # int userInputToCode(const char* input) { int i = 0; for(i = 0; i < 3; i++) { //Extra points if you replace 3 with the size of validOptions...but I didn't want to get too detailed if(stricmp(validOptions, input) == 0) return i; } return -1 } //Returns 0 if equal...but 1 if it isn't equal int stricmp(const char* lhs, const char* rhs) { while(lhs != 0 && rhs != 0) { if(tolower(lhs) != tolower(rhs)) //Compare case insenstive return 1; } return 0; } One of the reasons why I would do this though is so I could generalize it later on if I wanted other types of options without having to change it everywhere in the code. That's the thing, a bit of extra time early on can save you a ton of time refactoring later on. 3735928559 - Beware of the dead beef Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 3 One minor thing to point out: char Input_RPS[9] = {""}; scanf("%s", Input_RPS); This is technically a security vulnerability (possible buffer overflow). You're creating an array with a fixed size, then accept user input of arbitrary length. This means a user can enter as many characters as they want, exceeding the size of your buffer, potentially overflowing into other memory regions. Best case, nothing happens because the memory is unused. Worst case… who knows (i.e. undefined behavior). You can use "%8s" to limit the input size that is read to 8 characters: scanf("%8s", Input_RPS); Though, afaik, the recommended way of doing it is: fgets(Input_RPS, sizeof(Input_RPS), stdin); You can also simplify your logic by working with numbers, rather than char arrays, internally. Meaning convert user input into a number ("rock" -> 0, "paper" -> 1, "scissors" -> 2), then compare these directly to the chosen random number. Spoiler #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> int sanitize(char* user_input) { // Ignore anything but first character, since it is distinct enough if (user_input[0] == 'r' || user_input[0] == 'R') { return 0; } else if (user_input[0] == 'p' || user_input[0] == 'P') { return 1; } else if (user_input[0] == 's' || user_input[0] == 'S') { return 2; } else if (user_input[0] == 'q' || user_input[0] == 'Q') { return -1; } return -2; } void evaluate(int user_choice, int game_choice, int *user_score, int *game_score) { if (user_choice == game_choice) { printf("Draw\n"); } else if ((user_choice + 1) % 3 == game_choice) { printf("You lose!\n"); ++(*game_score); } else { printf("You win!\n"); ++(*user_score); } } int main(){ srand(time(NULL)); char RPS[3][9] = { "Rock", "Paper", "Scissors" }; char user_input[9] = {}; int game_score = 0; int user_score = 0; printf("Enter '[r]ock', '[p]aper' or '[s]cissors' and see if you win!\n"); printf("Enter 'q' to quit\n"); //logic while(1){ printf("\nPlease enter [r],[p],[s],[q]: "); fgets(user_input, sizeof(user_input), stdin); int user_choice = sanitize(user_input); if(user_choice == -1){ printf("Sorry to see you go\n"); exit(0); } else if (user_choice < 0) { continue; } int game_choice = rand() % 3; printf("Your choice: %s\n", RPS[user_choice]); printf("Mine : %s\n", RPS[game_choice]); evaluate(user_choice, game_choice, &user_score, &game_score); printf("\nYour score is %d wins, %d losses\n", user_score, game_score); } } Remember to either quote or @mention others, so they are notified of your reply Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 3 7 hours ago, Eigenvektor said: Though, afaik, the recommended way of doing it is: True, should also be checking for null pointer after the read as well if(fgets(user_input, sizeof(user_input), stdin) == NULL) { //code because the user put in a blank input continue; } 3735928559 - Beware of the dead beef Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Posted January 6 Author Hi all sorry for not replying for a long time after digesting all the info I managed to finish my program and just wanted to say thanks I will be soon making a new post for my other project. Link to comment Share on other sites More sharing options... Link to post Share on other sites More sharing options...
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now