Hi,

I am currently learning C#, but when I made a program that allows the user to guess a word (in Dutch that's called "Galgje") it repeats the while-statement twice, ignoring the scanf(). I searched with Google and found out that the program is too fast for the user input. I tried different functions for user input (gets() and getline()) with no luck.

Does anyone have a suggestion on how to fix this?

Thanks in advance,
~G

The code:

#include <stdio.h>

#define MAX_WORD_LENGTH 30

void prn_galg(int i) {
 switch (i) {
     case 0 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 1 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 2 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 3 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 4 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 5 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 6 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 7 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 8 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 9 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

     case 10 :
      printf("Amount of wrong letters: %d\n\n", i);
     break;

 }
}


main() {
 /* Declaring variables */
 char currentWord[] = {'.', '.', '.', '.', '.', '.', '\0'}; /* The dot word */
 char guessWord[] = {'m', 'o', 'n', 'k', 'e', 'y', '\0'}; /* The word that needs to be guessed */
 int errors = 0; /* Error amount, if its higher than 10 the loop stops */
 bool guessedLetter = false; /* Boolean used to check wether the player entered a correct letter */
 int i,n = 1;
 char c;
 char d;
 printf("Welcome to Galgje, want to try to guess the word?\nYou will loose if you have more than 10 errors.\n\nThis is the word you need to guess: %s\n\n", currentWord);
 while (currentWord != guessWord) {
 printf("===== GUESS %d =====\n\n%s", n, "Enter a letter:");
 scanf("%c", &c);
 for (i = 0; i < 6; i++) {
  if (guessWord[i] == c) {
   currentWord[i] = c;
   guessedLetter = true;
  }
 }
 if (guessedLetter == false) {
  errors++;
  printf("\nThat letter was incorrect.\n\n");
 } else {
 guessedLetter = false;
  printf("\nThat letter was correct.\n\n");
 }
 printf("%s%s\n\n", "The word including the letters you guessed: ", currentWord);
 prn_galg(errors);
 n++;
 }
}

lines 57 and 58: you do not have to initialize the arrays one letter at a time -- just do the entire string at one time

char currentWord[] = "......"; /* The dot word */
 char guessWord[] = "monkey"; /* The word that needs to be guessed */

line 65: >> while (currentWord != guessWord) {
You can not compare two strings using the != or == operators. You have to call the function strcmp(), like this: while( strcmp(currentWord, guessWord) != 0){ strcmp() returns 0 when the two strings are identical (including letter case).

Edited 6 Years Ago by Ancient Dragon: n/a

Thanks for the help, i added them into my code and that part is now working fine.

Although it wasen't the solution to the while() problem. It turns out when the user entered for example an "a" and pressed enter, there were 2 characters: a and \n, so the while was executed twice. I corrected it by adding an if ( c != '\n' ) {} right after the scanf(). I hope other people will read this when they are having trouble with while(). The full code will be posted as soon as all problems are solved.

There is one last issue: retrieving words from a text file and then select the one with a random number. The following code is what I have so far, but when i execute it, a popup comes saying an error occured in the process (it does go through the compiler).

// This part works fine, and returns a number from 0-2
char randomNumber() {
srand(time(NULL));
int g = (rand() % 2);
return g;
}

// This part is the error-cause
char getWord(int wordN) {
  FILE *file;
  char c[50001];
  int r;
  // Opening the words file
  file = fopen("words.txt", "r");

  // Checking wether it is possible to open the file
  if(file==NULL) {
   printf("Error: can't open file.\n");
  } else {
    r = fread(c, 1, 50000, file);
   c[r] = '\0';
   pch = strtok (c," ,.-");
  return pch[wordN];
  }
  fclose(file);
}

Also, this is the part in main() in which I call the functions:

int wordNumber = randomNumber(); // Which word shall be used?
 char guessWord[] = getWord(wordNumber);

words.txt

dude|monkey|guy

Does anyone have a suggestion on how to fix this?

~G

Edited 6 Years Ago by Graphix: Perfectionist ;)

Well, I tried different things the past 2 hours, and at the end got it to work, but I still am not able to retrieve the word. I can open the file, read it, separate it, but I am not able to put the values in an array and then return the one with the random number identifier.

Please note the comments in the code, they explain the erros caused:

char randomNumber() {
srand(time(NULL));
int g = (rand() % 9);
return g;
}

char getWord(int wordN) {
  char c[50000];  /* declare a char array */
  int n;
  FILE *file;  /* declare a FILE pointer  */

  /* Opening words file */

  printf("Opening words.txt ....\n");
  file = fopen("words.txt", "r");
  printf("File opened successfully.\n");

  /* Incase the file can tbe openend */
  if(file==NULL) {
    printf("Error: can't open file.\n");
    return 1;
  }  else {

    /* Reading the contents of the file */

    n = fread(c, 1, 50000, file);
    c[n] = '\0';

    /* Separating the contents, divided by | */

    char arofstr[200];
    char *token = strtok(c, "|");
    int f = 0, j;
    while(token != NULL)
    {
      printf("[%s]\n", token); // This prints out [dude][monkey][guy]
      /* This is the problem of it: I cant use arofstr[f] = token
      If i used *token, it only returns the first letter (the pointer)
      */
      arofstr[f] = *token;
      token = strtok(NULL, "|");
      f++;
    }
    printf(arofstr);
    /* Closing the file */
    printf("Closing file...\n");
    fclose(file);
    printf("File closed succesfully.\n\n");
    /* This also returns an error, due to the fact that it isn't the same data type
    I think. Again, I searched with Google but had no succes. */
    return arofstr[wordN];
  }

}

main() {
 /* Declaring variables */
 /* Random deciding which word is chosen to be guessed:
 guessWord is the word that needs to be guessed
 currentWord is the word that is filled with dots */
 int wordNumber = randomNumber(); // Which word shall be used?
 randomNumber();
 /* Here an error is caused: intializer fails to determine size of guessWord.
 What am I doing wrong? */
 char guessWord[] = getWord(wordNumber);
 /* Calculate the length of the guessWord */
 int wordlength = sizeof(guessWord) - 1;
 char currentWord[wordlength];
 int t;
 for (t = 0; t < wordlength; t++) {
  currentWord[t] =  '.';
 }

/*
Here is the rest of main() it isn't interesting as it isn't causing an error...
...code....
...code....
For if you would like to try the code out yourself, I add the following code:
*/
}

Do you have a suggestion?

~G

Edited 6 Years Ago by Graphix: n/a

line 7: >> char getWord(int wordN) {

All getWord() will return is a single character. What you want it to return is an entire string, so declare it like this: char* getWord(int wordN){ I think you want arofstr to be an array of 200 strings. Then declare it like this: char* arofstr[200] = {0}; That is an array of 200 pointers, and each pointer is initialized to NULL.

line 40: you will have to copy the entire string to the pointer -- the = symbol will not do that.

arofstr[f] = malloc(strlen(token)+1); // allocate memory for the string
strcpy(arofstr[f],token);

line 51: You need to free() all the strings except the one that you want to return.

int i;
// free all the memory allocated for the strings
// It is ok to pass a NULL pointer to free(), so you
// don't have to test for that.
for(i  = 0; i < 200; i++)
{
    if( i != wordN)
         free(arofstr[i]);
}
// now you can return the string
return arofstr[wordN];

line 57: its int main(). Most modern compilers will complain if you declare it anything else.

line 65: >> char guessWord[] = getWord(wordNumber);
You have to use a pointer here: char* guessWord = getWord(wordNumber); or you could copy it

char guessWord[255];
char* ptr = getWord(wordNumber);
strcpy(guessWord,ptr);
// now free up the memory returned by that function\
// to avoid memory leak.
free(ptr);

line 67: >> int wordlength = sizeof(guessWord) - 1;
Can't use sizeof() here because it will return the wrong thing. Call strlen() instead.

line 68: >>char currentWord[wordlength];
Current c standards don't allow you do do that. You will have to call malloc() to allocate the memory char* currentWord = malloc( wordLength ); >>Here is the rest of main() it isn't interesting as it isn't causing an error...
From all the errors I found above, my guess is that you are wrong about that.

Edited 6 Years Ago by Ancient Dragon: n/a

Due to the fact it about a half day before you replied, i checked the code again and again (I guess this is called "learning" :)) and found the faults before your post. Anyway, the code is now working perfect, but if you have still have comments(s) on how the code below should be improved, please post them :).

Also, when I went your approach, it resulted an error:

invalid conversion from *void to *char

at the following part:

arofstr[f] = malloc(strlen(token)+1); // allocate memory for the string
strcpy(arofstr[f],token);

so I didn't add that part into the code.

Also the following code resulted in a windows error (it got through compiler, but resulted in an error when executed):

int i;
// free all the memory allocated for the strings
// It is ok to pass a NULL pointer to free(), so you
// don't have to test for that.
for(i  = 0; i < 200; i++)
{
    if( i != wordN)
         free(arofstr[i]);
}
// now you can return the string
return arofstr[wordN];

The full encoding that works:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ctype.h>
#include <conio.h>
#include <time.h>
#include <string.h>

void prn_galg(int i) {
 switch (i) {
     case 0 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("\n");
      printf("\n");
      printf("\n");
      printf("\n");
      printf("\n");
      printf("\n");
      printf("____________\n\n");
     break;

     case 1 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 2 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 3 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 4 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    O \n");
      printf("  |\n");
      printf("  |\n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 5 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    O \n");
      printf("  |    |\n");
      printf("  |    |\n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 6 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    O \n");
      printf("  |   \\|\n");
      printf("  |    | \n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 7 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    O \n");
      printf("  |   \\|/\n");
      printf("  |    | \n");
      printf("  |\n");
      printf("__|_________\n\n");
     break;

     case 8 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    O \n");
      printf("  |   \\|/\n");
      printf("  |    | \n");
      printf("  |   /\n");
      printf("__|_________\n\n");
     break;

     case 9 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    O \n");
      printf("  |   \\|/\n");
      printf("  |    | \n");
      printf("  |   / \\\n");
      printf("__|_________\n\n");
     break;

     case 10 :
      printf("Amount of wrong letters: %d\n\n", i);
      printf("  _______\n");
      printf("  |/   | \n");
      printf("  |    X \n");
      printf("  |   \\|/\n");
      printf("  |    | \n");
      printf("  |   / \\\n");
      printf("__|_________\n\n");
     break;

 }
}

char randomNumber() {
srand(time(NULL));
int g = (rand() % 101);
return g;
}

const char *getWord(int wordN) {
  char c[50000];  /* declare a char array */
  int n;
  FILE *file;  /* declare a FILE pointer  */

  /* Opening words file */

  file = fopen("words.txt", "r");

  /* Incase the file can tbe openend */
  if(file==NULL) {
    printf("Error: can't open file.\n");
    return "error";
  }  else {

    /* Reading the contents of the file */

    n = fread(c, 1, 50000, file);
    c[n] = '\0';

    /* Separating the contents, divided by | */

    char *token = strtok(c, "|");
    char *words[200] = {0};
    int f = 0;
    while(token != NULL)
    {
      /* printf("[%s]\n", token); */
      /* Here the error is caused */
      words[f] = token;
      token = strtok(NULL, "|");
      f++;
    }
    /* Closing the file */

    fclose(file);

    /* Returning string */
    return words[wordN];
  }

}

int main(void) {
char udi[5] = "EMP";
while ((strcmp(udi, "END") != 0) && ((strcmp(udi, "AGAIN") == 0) || (strcmp(udi, "EMP") == 0))) {
 strcpy(udi, "EMP");
 /* Declaring variables */
 /* Random deciding which word is chosen to be guessed:
 guessWord is the word that needs to be guessed
 currentWord is the word that is filled with dots */

 /* Retrieving the wordNumber */

 int wordNumber = randomNumber(); // Which word shall be used?

 /* Retrieving the word that matches with the wordNumber */
 /* Check which number was chosen: printf("%d", wordNumber); */

 const char *tempWord = getWord(wordNumber);

 /* Declaring the guessWord with the length of dkljafoue */

 char guessWord[strlen(tempWord)];

 /* Copying the string of dkljafoue into guessWord */

 strcpy(guessWord, tempWord);

 /* Calculate the length of the guessWord */

 int wordlength = strlen(guessWord);

 /* Creating the dotword (name: currentWord) */

 char currentWord[wordlength - 1];
 int t, k;
 for (t = 0; t <= wordlength; t++) {
  if (t == wordlength) {
      currentWord[t] = '\0';
  } else {
  currentWord[t] =  '.';
  }
 }
 /* Currentword check: printf("Currentword: \"%s\"", currentWord); */
 int errors = 0; /* Error amount, if its higher than 10 the loop stops */
 bool guessedLetter = false; /* Boolean used to check wether the player entered a correct letter */
 int i,n = 1;
 char c;
 char d;
 printf("Welcome to the game Hangman, want to try to guess the word?\nYou will loose if you have 10 errors.\n\nThis is the word you need to guess: %s\n\n", currentWord);
 printf("===== ATTEMPT %d =====\n\n%s", n, "Enter a letter:");
 while( (strcmp(currentWord, guessWord) != 0) && (errors < 10) ){
 scanf("%c", &c); /* Retrieving the user entry */
 c = tolower(c);
 if (c != '\n') {
 if (isalpha(c)) { /* Making sure that the letter is alphanumeric */
 for (i = 0; i < wordlength; i++) {
  if (guessWord[i] == c) {
   currentWord[i] = c;
   guessedLetter = true;
  }
 }
 if (guessedLetter == false) {
  errors++;
  printf("\nThat letter was incorrect.\n\n");
 } else {
 guessedLetter = false;
  printf("\nThat letter was correct.\n\n");
 }
 printf("%s%s\n\n", "The word including the letters you guessed: ", currentWord);
 prn_galg(errors);
 n++;
 if ( (strcmp(currentWord, guessWord) != 0) && (errors < 10) ) {
 printf("===== ATTEMPT %d =====\n\n%s", n, "Enter a letter:");
 }
 } else {

  printf("Only alphanumeric symbols are allowed (a-z, A-Z), try again:\n");
 }
 }
 }
 /* Showing the results, wether the player won or not  */
 printf("===== RESULTS =====\n\n- MESSAGE -\n\n");
 if (errors < 10) {
  if (strcmp(currentWord, guessWord) == 0) {
      printf("Congratulations you have guessed the right word!\n\n");
  } else {
      printf("You have guessed the wrong word, better luck next time!\n\n");
  }
 } else {
     printf("You have guessed the wrong word, better luck next time!\n\n");
 }
 printf("- STATISTICS -\n\nErrors: %d\nThe word that needed to be guessed: %s\nThe word you guessed: %s\n", errors, guessWord, currentWord);
 printf("\nPlease enter the letters END in caps to end the game or enter AGAIN to restart:\n");
 while ((strcmp(udi, "END") != 0) && (strcmp(udi, "AGAIN") != 0)) {
  if (strcmp(udi, "EMP") != 0) {
      printf("\n\nIt is not allowed to enter anything else than AGAIN or END, try again:\n");
  }
  scanf("%s", udi);
 }
 printf("\n\n---------------------------------------------------\n\n");
}
exit(0);
}

~G

>>invalid conversion from *void to *char
You must be compiling that program as c++, not C (filename has extension *.cpp, not *.c). C does not require typecast, c++ does. Rename your program to have *.c extension and you will not get that error.

>>so I didn't add that part into the code.
Big big mistake. So instead of correcting your program you decided to just leaved the bugs in.

line 157: That return will cause program crash because it is returning a pointer into array c, which will get destroyed as soon as that function returns. You need to allocate new memory and return a pointer to it.

char* p = malloc( strlen(token)+1);
strcpy(p, token);
return p;

-The program's extension has been from day 1 .c The filename is hangman.c . But perhaps it is my opensource editor/compiler Code::Blocks that only compiles to c++, I don't know.

-Although you now say I didn't correct bugs, I first adjusted your corrections in the program, then I removed the ones that resulted in an error.

The bugs I fixed:

~ char getWord(int wordN) { into char* getWord(int wordN){
~ char *words[200] into char* words200] = {0};
~ main() into int main(void)
~ char guessWord[] = getWord(wordNumber); into various lines

The rest returned error with the invalid conversion from *void to *char

-157 I don't understand what you mean, I allocated the memory of c at line 142 (c[50000]), and I don't quite understand why I should declare another pointer and then return that at line 157?

~G

Edited 6 Years Ago by Graphix: n/a

I created a new C console project with Code::Blocks and it did not produce a warning or error on malloc(), just as I had suspected. Then I created a new C++ console project, changed the file extension to *.c and Code::Blocks produced an error like you said. Apparently the compiler doesn't know that *.c is a C source file, not c++. So you obviously created the wrong kind of console project.

nt main()
{
    char *ptr = malloc(25); // no warnings or errors here
    strcpy(ptr, "Hello World");
    printf("%s\n", ptr);
    free(ptr);
    return 0;
}

>>157 I don't understand what you mean, I allocated the memory of c at line 142

No you didn't. line 142 declared a character array ON THE STACK and such arrays can not be used in the return statement. Even if you allocate new memory for c using malloc you still can not return a pointer to somewhere in the middle of that array because the original pointer will be lost and result in a memory leak. The only way to successfully return a character array is the way I mentioned. Well, there is another way but it is a little more complicated -- pass the pointer by reference to that function

const char *getWord(int wordN, char** retvalue) {
...
...
  if( retvalue != NULL)
  {
      // deallocate the pointer if necessary
      free(*retvalue);
     *retvalue = malloc( ... );
     return *retvalue;
  }
}

int main()
{
    char *ptr = NULL;
    
    char* word = getWord(wordN, &ptr) ;
    free(ptr);
    // do not attempt to free word because word has the same address as ptr.
};

Edited 6 Years Ago by Ancient Dragon: n/a

Ok, I created a new project -> Console application -> C ->variousprojects.cbp -> GNU GCC Compiler -> Debug & Release ->finish.

Then I created a new file:

New -> file... -> c/c++ source -> C -> hangman.c -> finish

The *void *char errors are now fixed, but now it returns errors regarding the boolean guessedLetter. Did I declare it wrong, not according to the C standard?

The errors:

'bool' undeclared
syntax error before "guessedLetter"
guessedLetter undeclared
true undeclared
false undeclared

~G

Never mind, I searched a bit and found out that C doesn't have a boolean, I changed guessLetter into a int, at which 0 represents false and 1 represents true.

The program is now working correctly, thank you very much for you help!

~G

This question has already been answered. Start a new discussion instead.