0
#define _CRT_SECURE_NO_WARNINGS     
#include <stdio.h>                  
#include <ctype.h>                  
#define MAXGUESSES 5


void Instructions();


int PlayGuess(char solution);


char  GetLetter();


int CompareLetters(char guess, char solution);




int main()
{
    int i = 0;
    int numgames = 0;
    char solution;
    char guess;
    int compareletter(char guess, char solution);
    FILE *inp;
    inp = fopen("letterList.txt", "r");
    fscanf(inp, "%c", &solution);
    Instructions();
    //get number of games the user wants to play
    printf("Please enter the number of games you want to play\n");
    scanf("%d", &numgames);
    for (i = 1; i <= numgames; i++)
        //print current game (value of i)
    {
            //get letter to guess from file
            fscanf(inp, "%c", &solution);
            PlayGuess(solution);
            printf("\nThe letter is %c\n", solution);
    }


    fclose(inp);

}
void Instructions()
{
    printf("Welcome to Letter Guess\n");
    printf("To begin you will enter the number of games you want to 
play(1 – 4 games)\n");
    printf("You have 5 chances to guess each letter\n");
    printf("Let's begin\n");

}

int PlayGuess(char solution) //player defined guesses.
{
    int numGuesses = 0;
    int winOrLose = 0;
    while (numGuesses < MAXGUESSES)
    {
            GetLetter();

            numGuesses = numGuesses + 1;
            if (numGuesses>MAXGUESSES)
            {
                    printf("You have run out of guesses\n");
            }
    }


    return 0;
}


//get the guess from the user (call GetLetter function)
//call compareLetters function

char GetLetter()
{
    char guess = 0;
    char solution;
    printf("Enter a guess:", guess);
    scanf(" %c", &guess);
    CompareLetters(guess, solution);
    return guess;
}


//compare the guess and the solution
//return a 1 if they are the same
// message based on before or after alphabetically
//return a 0 if the guess and answer are not the same

int CompareLetters(char guess, char solution)
{
    if (guess == solution) //if answer is correct
    {   printf("Thats it!\n");
    return 1;
    }
    else
        if (guess<solution)
        {
                printf("The letter you are trying to guess comes after %c\n", guess);
                printf("\nTry again\n");
                GetLetter();

                return 0;
        }
        else
            if (guess>solution)
            { printf("The letter you are trying to guess comes before %c", guess);
    printf("\nTry again\n");
    GetLetter();
    return 0;
            }
}

Sorry if the code is a bit messy.

Problem #1: The variable "solution" is uninitialized but i do not know how to fix it. I have this problem a lot, if possible i could use an explanation.

Problem #2: When i launch the program and enter the amount of games I want to play it ignores it and gives me endless guesses, the program never stops.

Thanks.

  • 1
    What is the value of `char solution;` in your call to `int compareletter(char guess, char solution);`? (2) How are you handling `'\n'` left in `stdin` by `scanf("%d", &numgames);` before your call to `fscanf(inp, "%c", &solution);`? – David C. Rankin Oct 11 '17 at 03:25
  • i dont think char solution has a value in int compareletter(char guess, char solution) – Jared Majuk Oct 11 '17 at 03:29
  • Correct, that will invoke *Undefined Behavior*. The bigger question is why are you duplicating `int compareletter(char guess, char solution);` in `main()` before your `for` loop? Also **make sure**, you are passing the `/Wall` or `/W3` option to `cl.exe` (VS) to enable compiler warnings. The compiler will point out the lines containing problem areas. – David C. Rankin Oct 11 '17 at 03:30
  • You are not passing „solution“ to GetLetter – neuhaus Oct 11 '17 at 03:31
  • should int compareletter(char guess, char solution); in main() go after the for loop? – Jared Majuk Oct 11 '17 at 03:37
  • @DavidC.Rankin That's not a function call, it's a declaration. Do you see the data type, `int`, in front of it? Declaration. The arguments are also declarations, not expressions. – Tom Karzes Oct 11 '17 at 04:51
  • Jared, the uninitialized variable warning is coming from `GetLetter`. You declare `solution`, then pass it to `CompareLetters` without ever assigning a value to it. – Tom Karzes Oct 11 '17 at 04:53
  • @TomKarzes see second comment *"The bigger question is why are you duplicating int compareletter(char guess, char solution); in main() before your for loop?*" – David C. Rankin Oct 11 '17 at 04:54
  • @DavidC.Rankin It's declaring a lowercase version of the function which doesn't exist, so it serves no purpose. But the uninitialized variable error is coming from `GetLetter`, not `main`. – Tom Karzes Oct 11 '17 at 04:57
  • Well slap my old eyes, you are correct. It's superfluous, but you are indeed correct. Thanks. – David C. Rankin Oct 11 '17 at 04:59

3 Answers3

1
  1. Just put char solution = '\0';. It's enough to get rid of warning.
  2. Try printing the value of numgames you've just read in scanf() function. It seems you're getting some invalid value for some reason...

Upd: I see your problem: you're calling GetLetter() from PlayGuess(); and you're calling CompareLetters() from GetLetter(); and then you call GetLetter() from CompareLetters() so you create endless recursion. Remove calls GetLetter() from CompareLetters().

Jurlie
  • 1,014
  • 10
  • 27
0

You have to initialize guess and solution to something before you use them in a function.

And what does this line

int compareletter(char guess, char solution);

indicate, there is no function with same name nor it is a call to any function.

In case for dummy initialization you can use

solution = '\0';
Jasmeet
  • 1,315
  • 11
  • 23
  • the int compareletter(char guess, char solution); is suppose to let the user know if the guess comes alphabetically before or after the answer – Jared Majuk Oct 11 '17 at 03:43
  • I suppose that is done by CompareLetters() not compareletter(), or do you have a different function compareletter() defined. – Jasmeet Oct 11 '17 at 03:58
  • Also you are not passing your 'solution' variable to GetLetter(). It is being locally declared i.e it is a complete different variable. – Jasmeet Oct 11 '17 at 04:04
  • how do i make it not a completely different variable? Also after fixing the CompareLetters(), nothing changed. – Jared Majuk Oct 11 '17 at 04:05
  • Change the GetLetter defintion to char GetLetter(char solution) and remove local declaration for solution in GetLetter(). Now pass your solution variable when calling GetLetter, i.e Getletter(solution). – Jasmeet Oct 11 '17 at 04:29
0

Continuing from my comments, the key takeaways from your code are (1) you cannot learn C by guessing at syntax, compiling, over and over again, (2) validate ALL input to your program by checking the return of all input functions and validating the value you receive, (3) enable compiler warnings and then read, understand and correct each warning before attempting to compile again, and (4) do not accept code until it compiles cleanly, without warning.

Since your code includes #define _CRT_SECURE_NO_WARNINGS, it is apparent you are on windows using cl.exe (either from cmd.exe or from VS-Code). For learning basic programming, close VS-Code, open the Command Line provided by your VS (or SDK) install, and don't worry about using the IDE again, until you have mastered compiling from the command line and understand your compiler options. See cl.exe C/C++ Compiler Options, or type cl /? at the command prompt.

From the command line, your basic compile string should be similar to:

cl.exe /nologo /W3 /Ox /Tc mysource.c

(/W3 enable most warnings, /Ox enable all optimizations)

I find it helpful to not clutter my c-source directory with .obj and .exe files so I create two additional directories /obj and /bin for the object and executable files. You then use the /Fo and /Fe options to tell the compiler to put the object files and exe files in the proper directories, e.g.

cl /nologo /W3 /Ox /Foobj/mysource /Febin/mysource /Tc mysource.c

That will put mysource.obj in the obj directory and mysource.exe in the bin directory.

You must have the logic for your code clear in your head before you sit behind the keyboard and start pecking away. (See: (1) above). The easiest way to keep it straight by drawing a simple logic diagram for your code and identify what values you will handle in main() and then what will be handled in each function(). You don't need anything fancy, an 8.5x11 sheet of paper and pencil will do. After you have a clear road map for what each part of your code will do, then sit down and start pecking away.

Putting that logic to test, you can rework your code so it makes a lot more sense than it currently does, e.g.

#define _CRT_SECURE_NO_WARNINGS     
#include <stdio.h>                  
#include <ctype.h>                  

#define MAXGUESSES 5

void Instructions();
int PlayGuess (char solution);
char  GetLetter();
int CompareLetters (char guess, char solution);

int main (void)
{
    int i = 0,
        numgames = 0;
    char solution;
    FILE *inp = fopen ("letterList.txt", "r");

    if (inp == NULL) {
        fprintf (stderr, "error: file open failed 'letterList.txt'.\n");
        return 1;
    }

    Instructions(); /* give instructions */

    /* get number of games the user wants to play */
    printf("Please enter the number of games you want to play: ");
    if (scanf ("%d", &numgames) != 1) {
        fprintf (stderr, "error: invalid input - numgames.\n");
        return 1;
    }
    putchar ('\n');

    for (i = 0; i < numgames; i++)
    {
        /* get letter to guess from file */
        if (fscanf (inp, " %c", &solution) == EOF || solution < ' ' 
                    || '~' < solution) {
            fprintf (stderr, "error: invalid character - solution.\n");
            return 1;
        }
        printf (" ==>  Game  %d  <==\n\n", i + 1);
        PlayGuess (solution);
        printf("The letter was '%c'!\n\n", solution);
    }
    fclose (inp);

    return 0;       /* main() is type int and returns a value */
}

void Instructions()
{
    printf ("Welcome to Letter Guess\n"
            "To begin you will enter the number of games you want "
            "to play (1 – 4 games)\n"
            "You have 5 chances to guess each letter\n"
            "Let's begin\n\n");
}

int PlayGuess (char solution)
{
    int numGuesses = 0;
    char guess;

    while (numGuesses < MAXGUESSES)
    {
        guess = GetLetter();
        if (CompareLetters (guess, solution))
            return 1;
        numGuesses = numGuesses + 1;
    }
    printf ("You have run out of guesses\n");

    return 0;
}


/* get a letter and validate it is good */
char GetLetter()
{
    char guess = 0, 
        tmp;

    printf ("Enter a guess: ");

    if (scanf (" %c", &tmp) != EOF && ' ' <= tmp && tmp <= '~')
        guess = tmp;

    return guess;
}


/* compare the guess and the solution
 * return a 1 if they are the same
 * message based on before or after alphabetically
 * return a 0 if the guess and answer are not the same
 */
int CompareLetters(char guess, char solution)
{
    if (guess == solution)      /* answer is correct */
    {   
        printf ("Thats it!\n\n");
        return 1;
    }

    if (guess < solution)
        printf ("The letter you are trying to guess comes after '%c'\n", 
                guess);
    else 
        printf ("The letter you are trying to guess comes before '%c'\n", 
                guess);

    printf ("Try again\n\n");

    return 0;
}

Example Compile String for cl.exe (VS)

>cl /nologo /W3 /Ox /Foobj/guessletter /Febin/guessletter /Tc guessletter.c

Example Use/Output

> bin\guessletter.exe
Welcome to Letter Guess
To begin you will enter the number of games you want to play (1 – 4 games)
You have 5 chances to guess each letter
Let's begin

Please enter the number of games you want to play: 2

==>  Game  1  <==

Enter a guess: k
The letter you are trying to guess comes before 'k'
Try again

Enter a guess: c
The letter you are trying to guess comes after 'c'
Try again

Enter a guess: d
Thats it!

The letter was 'd'!

==>  Game  2  <==

Enter a guess: e
The letter you are trying to guess comes after 'e'
Try again

Enter a guess: g
The letter you are trying to guess comes before 'g'
Try again

Enter a guess: f
Thats it!

The letter was 'f'!

Look things over and think about how to approach programming in C. It is an exact language. It is up to you to account for all characters in all input buffers as well as your memory use. If you don't know what parameters a library function takes, or what type and value it will return, or how to use it, look it up. The man pages are available at, e.g. msdn fscanf, fwscanf or scanf(3): input format conversion)

Let me know if you have further questions.


Accepting Input In Any Case, Converting to Lowercase

To accept input in any case and convert the value to lowercase so that guess is always lowercase in your code, you need to change only one-line:

/* get a letter and validate it is good
 * (convert letter to lowercase)
 */
char GetLetter()
{
    char guess = 0, 
        tmp;

    printf ("Enter a guess: ");

    if (scanf (" %c", &tmp) != EOF && ' ' <= tmp && tmp <= '~')
        guess = tolower (tmp);

    return guess;
}

note: For ASCII characters, the 6th-bit is the 'case bit', if it is 1, the character is lowercase, 0 uppercase. tolower can simply be written as:

unsigned c_tolower (unsigned c)
{
    if ('A' <= c && c <= 'Z')
        c ^= (1 << 5);

    return c;
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • You were a great help and I appreciate all the advice. – Jared Majuk Oct 11 '17 at 14:32
  • But I have one more question, how do I make it so the guess I enter (uppercase or lowercase) doesn't matter. For example let's the say the answer is "B" but i put "b", how do I make it so the program will accept both? – Jared Majuk Oct 11 '17 at 14:34
  • Also do you have any recommendations on a youtube channel or book to look at that can assist me in learning C? – Jared Majuk Oct 11 '17 at 14:46
  • `guess = tolower(tmp);` will accept any case input but make all guesses lowercase. See [The Definitive C Book Guide and List](https://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list). Learning C is a journey, not a race, take the time and enjoy learning the details, slow and steady wins the race. – David C. Rankin Oct 11 '17 at 20:32
  • I always used /W4 for warnings, didn't know about /W3 – RollRoll Oct 11 '17 at 20:55
  • I always try and use `/Wall`, but that can be a little excessive for just getting started (unless you are handy with `/wdXXXX` (where `XXXX` is the warning code you wish to independently disable) - to get rid of the non-C related warnings the MS compiler loves to issue). – David C. Rankin Oct 11 '17 at 20:58