0

I apologize if the title is misleading in anyway, because I don't know where or how to start on this one.

Recently I wrote a math game that makes random numbers and turns them into equations. But all the program can do Is take in numbers, if I wanted to allow commands like say show-stats to show your stats. I have to write the command and then a number after for the command to get recognized like so

show-stats 0
score is 1

show-stats
0             //number is required for some reason
score is 1

This is a minimal example I wrote

#include <stdio.h>
#include <string.h>

int main() {
 int bar;
 char foo[]="";
 int score = 1;
    
 scanf("%s%i",foo,&bar);
 if(strcmp(foo,"show-stats"))
 {
  printf("Score is %i",score);
 }
 
 if(bar == 2)
 {
  score = bar*2;
  printf("Doubled Points.\n");
 }
}

Here is the actual code, In case you need. Also, I'd like advisors on the actual code, like if its spaghetti or if something is performance consuming, or just what I can improve on in general if its not too much trouble. thanks in advance and I'm open to suggestions.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define VER 10
#define DIV "-----"

int main()
{
 system("clear");
 
 unsigned int x,y;                                                                                                                                                                   //equation numbers
 int ans,sum;                                                                                                                                                                        //user answer
 unsigned int max = 10;                                                                                                                                                              //max possible number that can be made, cannot go under 10.
 int score;                                                                                                                                                                          //what do you think?
 char operation;
 int correctAnswers = 0,wrongAnswers = 0;

 printf("Math game\nVersion %i.\n",VER);
 for (; ;)
 {
   //phase 1; make numbers.
   srand(time(NULL));
   x = rand() % max;
   y = rand() % max;
   //phase 2; make operation type.
   operation = rand() % 2;
   switch (operation)
   {
    case 0:operation = '+';sum = x + y;break;
    case 1:operation = '-';sum = x - y;break;
   }
   //phase 3; write question to console and get user answer
   printf("What is %i %c %i? ",x,operation,y);                                                                                                                                       //get input
   scanf("%i",&ans);
   //phase 4; determine right answer
   if (ans == sum)
   {
    score++;
    correctAnswers++;
    max++;
    printf("Your correct! +1!\n");
    printf("%sStats%s\nScore:%i\nMax possible number:%i\nCorrect Answers:%i\nWrong Answers:%i\n%s%s%s\n",DIV,DIV,score,max,correctAnswers,wrongAnswers,DIV,DIV,DIV);                   //print stats when user wins,is a seperate call for readability. same thing on line 53 but for loss
   }
   
   else
   {
    score--;
    wrongAnswers++;
    if(max>10){max--;};                                                                                                                                                              //assures max doesn't go under 10
    printf("Wrong! -1\n");
    printf("%sStats%s\nThe correct answer was %i\nMax possible number : %i\nScore : %i\nCorrect Answers : %i\nWrong Answers : %i\n%s%s%s\n",DIV,DIV,sum,max,score,correctAnswers,wrongAnswers,DIV,DIV,DIV);
   }
 }
}
cs07
  • 15
  • 4
  • 2
    First thing, *never* use `scanf()` to read user input without checking the return value. The general recommendation is to use `fgets()` to read a complete line of input and then do the parsing with the much richer (and less error-prone) arsenal of e.g. `strtol()`. – DevSolar Sep 01 '21 at 14:32
  • 4
    `char foo[]="";` How many characters do you think, this array can hold when you read the string with `scanf`? Hint: It cannot! – Gerhardh Sep 01 '21 at 14:33
  • oh really? thanks, but what do you mean by return values? – cs07 Sep 01 '21 at 14:33
  • @Gerhardh wait really? let me check it out real quick. Thanks! – cs07 Sep 01 '21 at 14:34
  • 3
    @cs07 have you learnt what exactly functions are, and what function return values are? – mediocrevegetable1 Sep 01 '21 at 14:34
  • @mediocrevegetable1 oh those, I thought he meant something else. yeah I know what he means now thanks – cs07 Sep 01 '21 at 14:35
  • @DevSolar so I use fgets to read the entire thing and then parse it `strtol()`, sounds easy enough. – cs07 Sep 01 '21 at 14:37
  • 1
    How is your minimal example related to your actual code? You don't read any string in the second snippet. – Gerhardh Sep 01 '21 at 14:37
  • @Gerhardh I know, I took that part out because it just bugged the entire thing, but when you do scan it and read it with strcmp like in the minimal example, same thing happens – cs07 Sep 01 '21 at 14:39
  • Please don't post code that does something completely different. How would it be useful if it doesn't even contain the functionality you are struggling with? Do you have the same undefined behaviour due to corrupting memory in the real code? – Gerhardh Sep 01 '21 at 14:40
  • yeah, thats why I posted it, In hindsight I should've wrote why i removed it from the second snippet – cs07 Sep 01 '21 at 14:42
  • [What can I use for input conversion instead of scanf?](https://stackoverflow.com/questions/58403537) – Steve Summit Sep 01 '21 at 14:45
  • 2
    Good idea to read the manual page for scanf – Ed Heal Sep 01 '21 at 14:49
  • Yeah I am right now – cs07 Sep 01 '21 at 14:51
  • regarding: `char foo[]="";` this only allocates a single byte. So this: `scanf("%s%i",foo,&bar);` will overflow the `foo` buffer, resulting in undefined behavior. Suggest: `char foo[ 1024 ]="";` and `scanf("%1023s%i",foo,&bar);` – user3629249 Sep 02 '21 at 16:59
  • the second code fails to inform the user of what `0` and `1` (the operation) means – user3629249 Sep 02 '21 at 17:07

1 Answers1

1

Thanks to DevSolar, I know how to do this. Using fgets() and strtol() you can collect the entire string, and parse it into the command and the number, I read up on strtol here https://www.tutorialspoint.com/c_standard_library/c_function_strtol.htm

edit:

char str[30] = ""; //the string the user types
   fgets(str,30,stdin);
   char *ptr; //the part of the string turned into words
   long ret; //the part of the string turned into numbers

   ret = strtol(str, &ptr, 10); //parameter 1;source string that is parsed;//parameter 2; string part of source.//parameter 3; base
   printf("The number(unsigned long integer) is %ld\n", ret);
   printf("String part is |%s|", ptr);
cs07
  • 15
  • 4
  • 1
    Please note that also for `fgets` you need a buffer that is actually large enough to hold some input. Your buffer from question cannot hold any input at all. It can only hold the terminating 0 byte. – Gerhardh Sep 01 '21 at 15:01
  • The link you posted about the function `strtol` omits many important details about the function's behavior. For example, it does not specify how to check for a conversion error or a range error. I recommend that you use [this link from cppreference.com](https://en.cppreference.com/w/c/string/byte/strtol) instead. – Andreas Wenzel Sep 01 '21 at 16:54
  • @AndreasWenzel yeah, that's why i took so long to make an edit, because It didn't describe anything well, so I just tinkered in gdb online until i knew what they did, ill give this a read though – cs07 Sep 01 '21 at 16:57
  • There are still two paths on which your code can fail: 1) The `fgets()` could fail, returning `NULL`. 2) The input could start with something else than a number (returning `0` and setting `ptr = str`). 3) The input could be a number of too big a magnitude to fit into `ret` (returning `LONG_MAX` / `LONG_MIN` and setting `errno = ERANGE`). I understand that checking for these might seem overkill for some piece of experimental code, but getting into the habit of checking for any possible errors is important. – DevSolar Sep 01 '21 at 20:19
  • I took a nap after so sorry for responding 4 HOURS late, but anyways I didn't know that fgets could fail, though I did know the input could start with something else in which case I just took the lazy route and wrote "if you want to use a command and answer a question, put the command before the answer" – cs07 Sep 02 '21 at 00:45
  • regarding: `ret = strtol(str, &ptr, 10);` It seems your expecting some text before the number, but `strtol()` will not skip over text when looking for a number – user3629249 Sep 02 '21 at 17:13
  • oh ok. will note. – cs07 Sep 02 '21 at 21:50