Encountering an infinite loop depending on compiler and declarations - c

In this program there is a line where I create a variable called
"crazy_integer".
If I do not create this variable, MinGW creates an infinite loop!
I do not seem to have this problem with any other compiler.
Can anyone tell me what is going on here?
To recreate: Download the latest version of CodeBlocks with MingW, create
a new console project, and try running this program.
Then, try removing the line of code where I create "crazy_integer"
and run the program again. The result should be an infinite loop.
// In this program there is a line where I create a variable called
// "crazy_integer".
//
// If I do not create this variable, CodeBlocks creates an infinite loop!
// I do not seem to have this problem with any other compiler.
//
// Can anyone tell me what is going on here?
//
// To recreate: Download the latest version of CodeBlocks with MingW, create
// a new console project, and try running this program.
//
// Then, try removing the line of code where I create "crazy_integer"
// and run the program again. The result should be an infinite loop.
#include <stdio.h>
#include <string.h>
int find_winning_move(char *, char, int);
int display_board(char *);
int is_winning_position(char *, char);
void show_win_details(int, char);
int main(void) {
int retval = 0;
char raw_data[] = "X X XO ";
char player = 'X';
printf("We are examining this board: \n");
display_board(raw_data);
find_winning_move(raw_data, player, 1);
return 0;
}
int find_winning_move(char *raw_data, char player, int depth) {
char test_position[9];
int crazy_integer=0; // Adding this line will fix an infinite loop
int i, win_result;
for (i = 0; i < 9; i++) {
if (raw_data[i] == ' ') {
strcpy(test_position, raw_data);
test_position[i] = player;
win_result = is_winning_position(test_position, player);
printf("The result of playing %c at position %d is: %d \n",
player, i, win_result);
display_board(test_position);
}
}
return 0;
}
int display_board(char *raw_data) {
char display_model[] = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";
int i, j, k; k=0;
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
display_model[ (i * 10) + j ] = raw_data[k++];
}
}
printf("%s ", display_model);
}
int is_winning_position(char *raw_data, char player) {
int i;
// Test for horizontal win
for (i = 0; i <= 6; i+=3) {
if (raw_data[i] == player
&& raw_data[i+1] == player
&& raw_data[i+2] == player)
{
return 10 + i;
}
}
// Test for vertical win
for (i = 0; i <= 2; i++) {
if (raw_data[i] == player
&& raw_data[i+3] == player
&& raw_data[i+6] == player)
{
return 20 + i;
}
}
// Test for diagonal win
if (raw_data[4] == player) {
if (raw_data[0] == player && raw_data[8] == player) {
return 31;
}
if (raw_data[2] == player && raw_data[6] == player) {
return 32;
}
}
return 0;
}
void show_win_details(int win_value, char player) {
switch (win_value) {
// Horizontal
case 10 :
printf("Horizontal win on first row for Player: %c \n",
player);
break;
case 13 :
printf("Horizontal win on second row for Player: %c \n",
player);
break;
case 16 :
printf("Horizontal win on third row for Player: %c \n",
player);
break;
// Vertical
case 20 :
printf("Vertical win on first column for Player: %c \n",
player);
break;
case 21 :
printf("Vertical win on second column for Player: %c \n",
player);
break;
case 22 :
printf("Vertical win on third column for Player: %c \n",
player);
break;
// Diagonal
case 31 :
printf("Diagonal win upper left to lower right for Player: %c \n",
player);
break;
case 32 :
printf("Diagonal win lower left to upper right for Player: %c \n",
player);
break;
default: printf("Some error occurred. \n"); break;
}
}

Your variable declaration:
char test_position[9];
Is too short for the strcpy into it (strcpy(test_position, raw_data);). The source buffer raw_data is 9 characters plus the null terminator. So it results in a buffer overflow. Adding that integer variable probably provides extra space on the stack that "fixes" the stack overflow.

Related

I'm trying to make a program in C in which you can play hangman but as soon as it prints the option to guess the letter the program terminates

The program isn't printing after giving me the first chance to guess.
#include <stdio.h>
#include <string.h>
int main() {
char menu;
int c = 0, flag = 0, life = 8;
printf("\nWelcome to Hangman!!!");
printf("\nThis is a game of hangman.");
printf("Player 1 enters a random word and the other has to guess it.");
printf("You get 8 lives in total i.e. you can have a maximum of 8 wrong guesses.");
printf("\n");
printf("Press n for new game\n");
printf("Press q to quit\n");
printf("\n");
scanf("%c", &menu);
int i = 0, j = 0;
char w[20], ch;
if (menu == 'q') {
printf("Exiting...");
printf("Thanks for playing");
}
else if (menu == 'n') {
printf("Player 1 enters a word\n");
scanf("%s", w);
int len = strlen(w);
for (int i = 0; i < len; i++) {
toupper(w[i]);
}
printf("\e[1;1H\e[2J");
char arr[len - 1];
for (int i = 0; i < len - 1; i++) {
arr[i] = '_';
printf("%c", arr[i]);
}
printf("\n");
while (life != 0) {
for (int i = 0; i < len - 1; i++) {
if (arr[i] == '_') {
flag = 1;
break;
}
else {
flag = 0;
}
}
if (flag == 0) {
printf("You Won!!\n");
printf("You Guessed The Word: %s", w);
break;
}
else {
char ans;
printf("Enter a letter between A-Z");
scanf("%c", ans);
toupper(ans);
for (int j = 0; j < len; j++) {
if (ans == w[j]) {
arr[j] = ans;
c++;
}
}
if (c == 0) {
life--;
}
c = 0;
for (int j = 0; j < len; j++) {
printf("%c", arr[j]);
}
printf("\n Lives Remaining= %d \n", life);
}
}
if (life == 0) {
printf("\n You Lost!!! \n");
printf("The Word Was: %s", w);
}
}
else {
printf("Invalid Character");
}
}
Output:
Welcome to Hangman!!!
This is a game of hangman.Player 1 enters a random word and the other has to >guess it.You get 8 lives in total i.e. you can have a maximum of 8 wrong >guesses.
Press n for new game
Press q to quit
n
Player 1 enters a word
Hello
Enter a letter between A-Z
PS C:\Users\arora\Desktop\Programs\C>
There are quite a few problems with your program. Here are the major ones:
You want to use use space prefix in the format string for scanf(" %c", ...) to ensure previous newlines are ignored.
scanf("%c", ans); should be &ans. It causes scanf() to fail rendering the remain of the program non-interactive. Without input from the user the core game logic doesn't work.
Here are some of the other issues:
#include <ctype.h>.
(not fixed) Consider changing the menu logic so 'q' quits, and any other letter starts a game.
Game prompt contains long lines that are hard to read for the player(s).
You use a printf() per line which makes it hard to read. Use a single call and multi-line strings as input.
Try to branch your code less by making use of early return. It makes it easier to read.
Check the return value of scanf(). If it fails then whatever variable it read doesn't have a well defined value.
Ensure that scanf() read no more than 19 bytes into a 20 byte array w. It takes a little macro magic to generate the 19 so I didn't make this change but it's a good idea to #define constants for magic values like the 20.
arr is not \0 terminated (len-1). Most c programmers expect a string so it's not worth the confusion to save 1 byte.
Use a function or macro for the ANSI escape to clear the screen.
Eliminate unused variables i, j.
Reduce scope of variables (declare variables close to where you use them).
The calculation of the flag variable is cumbersome.
(not fixed) The prompt "Enter a letter between A-Z" is somewhat ambiguous. Suggest "... between A and Z".
It's generally a good idea to leave user input as you read. If you care about the repeated toupper() you can create a copy of the user input with letters in upper case, and create another variable to hold the upper case version of the player's guess. This avoid you saying things like you entered the word "BOB" when the actual input was "bob".
You attempt to use toupper() to convert each letter to upper case but don't assign the result to anything so it does not do anything constructive.
Consider some functions to document what each your code does. I added some comments for now.
(mostly not fixed) Consider using better variable names (c, w, arr, flag).
(not fixed) Should you reject a word with your magic '_' value? In general should you validate that the word is reasonable (a-z, len > 0, len < 20)?
(not fixed) Consider, in arr, just storing if a letter was correctly guess (boolean). When evaluating the state show the letter from w if it is already guessed otherwise the _.
(not fixed) If you guess a correct letter again, it's considered a good guess. Should it?
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define clear() printf("\e[1;1H\e[2J")
int main() {
printf(
"Welcome to Hangman!!!\n"
"\n"
"This is a game of hangman.\n"
"Player 1 enters a random word and the other has to guess it.\n"
"You get 8 lives in total i.e. you can have a maximum of 8 wrong guesses.\n"
"\n"
"Press n for new game\n"
"Press q to quit\n"
);
char menu;
if(scanf(" %c",&menu) != 1) {
printf("scanf failed\n");
return 1;
}
switch(menu) {
case 'q':
printf(
"Exiting..."
"Thanks for playing\n"
);
return 0;
case 'n':
break;
default:
printf("Invalid Character");
return 1;
}
printf("Player 1 enters a word\n");
char w[20];
if(scanf("%19s", w) != 1) {
printf("scanf failed\n");
return 1;
}
clear();
char arr[20];
int len=strlen(w);
for(int i=0;i<len;i++) {
arr[i]='_';
}
arr[len] = '\0';
int life=8;
for(;;) {
printf("%d Lives Remaining\n", life);
// read a guess from player
for(int i = 0; i < len; i++) {
printf("%c", arr[i]);
}
printf(" Enter a letter between A-Z ");
char guess;
if(scanf(" %c", &guess) != 1) {
printf("scanf failed\n");
return 1;
}
// determine if any of the letters are in the secret word
int c = 0;
for(int i=0; i<len; i++) {
if(toupper(guess) == toupper(w[i])) {
arr[i]=guess;
c = 1;
}
}
if(c==0) {
life--;
}
// game over?
int flag = 0;
for(int i = 0; i<len; i++) {
if(arr[i]=='_') {
flag=1;
break;
}
}
if(flag==0) {
printf("You Won!!\n");
printf("You Guessed The Word: %s\n",w);
break;
}
if(life==0) {
printf("\n You Lost!!!\n");
printf("The Word Was: %s\n", w);
break;
}
}
}

Issue with Mastermind Game in C language

I've been trying for a while to make this work but I'm still stuck with some issue...I would love some help.
The thing is the code works almost the way I want, the only issue I have is when the program is telling you how many colours you guessed right, if the first colour matches it works good but if the others positions are right the program give a wrong answer (or at least not what I would like).
I'm just starting to code I know my code is really far from being perfect.
Here is my code :
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#define SIZE_STRING 4
#define SIZE_STRING_BIG 15
void randomSeed(){
srand( (unsigned)time( NULL ) );
}
int randomM(int nMin, int nMax){
return nMin + rand()%(nMax-nMin+1);
}
int main(){
randomSeed();
char szUser[SIZE_STRING_BIG];
char szP[6]={'Y','B','W','P','R','G'}, szComputer[SIZE_STRING_BIG] = {szP[randomM(0,5)], szP[randomM(0,5)], szP[randomM(0,5)], szP[randomM(0,5)], '\0'};
int counter=0;
int colour=0;
int position=0;
printf("\n\n MASTERMIND ");
printf("\n\n We'll play with this colours:");
printf("\n\n Y - Yellow B - Blue W - White");
printf("\n P - Purple R - Red G - Green");
printf("\n\n You have 8 changes to get t right. \n");
printf(" Machine choose %s", szComputer); // this line just to check everything works allright
do{
counter++;
position=0;
colour=0;
printf("\n ===================================================\n");
printf("\n Chance %d", counter);
printf("\n\n Please add your 4 colours ");
printf("\n (Please write the four capital letters without space) ");
scanf("%s",szUser);
if(strlen(szUser) != SIZE_STRING)
{
printf("\n\n Sorry you choose a wrong option.");
counter--;
} else {
if(strcmp(szUser,szComputer))
{
printf("\n Wrong choice. Try again...");
if (szUser[0] == szComputer[0])
{
position++;
}
if (szUser[1] == szComputer[1])
{
position++;
}
if (szUser[2] == szComputer[2])
{
position++;
}
if (szUser[3] == szComputer[3])
{
position++;
}
printf("\n\n You have %d in the right position", position);
if ( szUser[0] == szComputer[0] || szUser[0] == szComputer[1] || szUser[0] == szComputer[2] || szUser[0] == szComputer[3] )
{
colour++;
}
if ( szUser[1] == szComputer[1] || szUser[1] == szComputer[2] || szUser[1] == szComputer[3] )
{
colour++;
}
if ( szUser[2] == szComputer[2] || szUser[2] == szComputer[3] )
{
colour++;
}
if ( szUser[3] == szComputer[3] )
{
colour++;
}
printf("\n You have %d colours right\n", colour);
}
}
}while(strcmp(szUser,szComputer) && counter <=7);
if (strcmp(szUser,szComputer))
{
printf("\n\n Sorry, you run out of chances...");
}
if(!strcmp(szUser,szComputer))
printf("\n\n Right choice !\n");
return 0;
}
I suggest using another array to keep track of which of the computer's pegs you've already seen for the current turn of the game:
char seen[SIZE_STRING];
For each turn, reset the "seen" flags and the count of correct colour and position pegs, and the count of correct colour and wrong position pegs:
memset(seen, 0, sizeof(seen));
position = 0;
colour = 0;
Then count user pegs with the correct colour and position, marking them as seen:
for (int i = 0; i < SIZE_STRING; i++)
{
if (szUser[i] == szComputer[i])
{
seen[i] = 1;
position++;
}
}
Then count user pegs with the same colour as computer pegs that haven't been seen yet, marking the matching computer pegs as seen. These user pegs will all be at the wrong position because pegs of the correct colour at the correct position have already been accounted for above:
EDIT 1: My original version of the inner loop could count a user peg more than once if several computer pegs had the same colour as the user peg. I have added a break; statement to the inner loop to fix this so that each user peg can match at most one computer peg.
EDIT 2: The outer loop also needs to skip over any user pegs that matched in the position matching loop to avoid counting them twice.
for (int u = 0; u < SIZE_STRING; u++)
{
// Bug fix (EDIT 2). Skip user pegs already accounted for by position matching loop ...
if (szUser[u] == szComputer[u])
{
// Already accounted for this user peg.
continue;
}
for (int c = 0; c < SIZE_STRING; c++)
{
if (!seen[c] && szUser[u] == szComputer[c])
{
colour++;
seen[c] = 1;
// Bug fix (EDIT 1) due to comment by #Rup ...
break; // Skip to next user peg.
}
}
}
I've been trying with the code you posted but still doesnt work 100% properly. The code works allright almost all cases but still some cases get it wrong. I'm having trouble with the white pegs, im still having some extra white pegs in one case, for example if the code to guess is RYPG and i introduce RRRR it answer back 1 red flag and 1 white flag when it should say just 1 red flag. and if the code is RYPG and i introduce RRPP it answer back 2 red flags and 2 white flags when it should be just 2 red flags. Here is my code:
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#define SIZE_STRING 4
#define SIZE_STRING_LONG 15
void randomSeed(){
srand( (unsigned)time( NULL ) );
}
int randomM(int nMin, int nMax){
return nMin + rand()%(nMax-nMin+1);
}
int main(){
randomSeed();
char szUser[SIZE_STRING_LONG];
char szP[6]={'Y','B','W','P','R','G'}, szComputer[SIZE_STRING_LONG] = {szP[randomM(0,5)], szP[randomM(0,5)], szP[randomM(0,5)], szP[randomM(0,5)], '\0'};
int counter=0;
int colour=0;
int position=0;
char alreadyChecked[SIZE_STRING];
printf("\n\n MASTERMIND ");
printf("\n\n We'll play with this colours:");
printf("\n\n Y - Yellow B - Blue W - White");
printf("\n P - Purple R - Red G - Green");
printf("\n\n You have 8 changes to get t right. \n");
printf("\n\n White flags indicate right colour in right position");
printf("\n\n Red flags indicate right colour in wrong position");
printf("\n\n Computer choses %s", szComputer); //check if the program works allright
do{
counter++;
position=0;
colour=0;
memset(alreadyChecked, 0, sizeof(alreadyChecked));
printf("\n ===================================================\n");
printf("\n Chance %d", counter);
printf("\n\n Please enter your 4 colours choice");
printf("\n (Please write capital letters without space ");
scanf("%s",szUser);
if(strlen(szUser) != SIZE_STRING)
{
printf("\n\n Sorry you choose a wrong option.");
counter--;
} else {
if(strcmp(szUser,szComputer))
{
printf("\n Wrong choice. Try again...");
for (int u = 0; u < SIZE_STRING; u++)
{
if (szUser[u] == szComputer[u])
{
position++;
}
}
if (position > 0 && position < 2)
{
printf("\n\n You have %d red flag", position);
}
if (position > 1 )
{
printf("\n\n You have %d red flags", position);
}
for (int u = 0; u < SIZE_STRING; u++)
{
if (szUser[u] == szComputer[u])
{
continue;
}
for (int c = 0; c < SIZE_STRING; c++)
{
if (!alreadyChecked[c] && szUser[u] == szComputer[c])
{
colour++;
alreadyChecked[c] = 1;
break;
}
}
}
if (colour > 0 && colour < 2)
{
printf("\n\n You have %d white flag", colour);
}
if (colour > 1 )
{
printf("\n\n You have %d white flags", colour);
}
if (colour == 0 && position == 0)
{
printf("\n\n 0 white flags and 0 red flags");
}
}
}
}while(strcmp(szUser,szComputer) && counter <=7);
if (strcmp(szUser,szComputer))
{
printf("\n\n Sorry, you run out of chances...");
}
if(!strcmp(szUser,szComputer))
printf("\n\n Right combination !\n");
return 0;
}

Add value of playing cards - with pointers and structures

I'm going through some c programming questions and I'm currently stuck on a pointer related question
Q: Write a function that takes the values of a two-card blackjack HAND as input, and returns the point total of the hand. The value
of the cards '2' through '9' is equal to their face value, the cards 'T', 'K', 'Q', 'J' are worth 10 points and the ace ('A') is worth 11 points
unless it comes with another ace, then that second ace is worth 1 point. The program should be able to catch incorrect input.
Examples:
Enter cards: A Q
The score is 21
Enter cards: A A
The score is 12
I've tackled this question before, but this time I'd have to use pointers which I'm still fairly new towards. Getting card values and calculating cards must be done in one function. Here's what i have so far:
#include <stdio.h>
#define HAND 2
struct player_hand
{
char card1;
char card2;
};
void getHandValue(struct player_hand * hnd_ptr, char size, char size2)
{
int first_card;
int second_card;
//get cards from user
scanf("%c %c",&hnd_ptr->card1, &hnd_ptr->card2);
printf("Enter Cards: %c %c", &hnd_ptr->card1, &hnd_ptr->card2);
//check value of first card in hand
if(hnd_ptr->card1<='9' && hnd_ptr->card1>='2')
{
first_card=(int)hnd_ptr->card1 -48;
}
//check for special cards: king, queen, jack, ten
else if(hnd_ptr->card1=='T'||hnd_ptr->card1=='K'||hnd_ptr->card1=='Q'||hnd_ptr->card1=='J')
{
first_card=10;
}
//if first card is Ace
else if(hnd_ptr->card1=='A')
{
first_card=11;
}
else
{
//card not valid
printf("Not a valid card: %c",hnd_ptr->card1);
return;
}
//check value of 2nd card
if(hnd_ptr->card2<='9' && hnd_ptr->card2>='2')
{
second_card=(int)hnd_ptr->card2 -48;
}
//if 2nd card is a special kind
else if(hnd_ptr->card2=='T'||hnd_ptr->card2=='K'||hnd_ptr->card2=='Q'||hnd_ptr->card2=='J')
{
second_card=10;
}
//if 2nd card is Ace
else if(hnd_ptr->card2=='A')
{
if(hnd_ptr->card1=='A')
second_card=1;
else
second_card=11;
}
else
{
//if 2nd card not valid
printf("Not a valid card: %c",hnd_ptr->card2);
return;
}
add cards
printf("\nThe total card value is: %d",first_card+second_card);
}
//call function, test if works
//calling it wrong?
int main(void)
{
struct player_hand hnd [HAND] = { {'A', 'A'}};
getHandValue (hnd, HAND);
return;
}
You have a few bugs.
Incorrect call in main.
The function doesn't need size arguments and if it did they should be int.
Bad return from main.
In the function, the printf is wrong.
Things are much more complicated than they need to be because the struct uses two scalars instead of an array.
I've created two versions of your program. One with bugs annotated. And another that cleans things up.
Here's the annotated version:
#include <stdio.h>
#define HAND 2
struct player_hand {
char card1;
char card2;
};
// NOTE/BUG: use 'int' for size and size2
void
getHandValue(struct player_hand *hnd_ptr, char size, char size2)
{
int first_card;
int second_card;
// get cards from user
scanf("%c %c", &hnd_ptr->card1, &hnd_ptr->card2);
// NOTE/BUG: this would print the _address_ of the values vs. the values
printf("Enter Cards: %c %c", &hnd_ptr->card1, &hnd_ptr->card2);
// NOTE/BUG [sort of]: the code below is cut-n-paste replication because you
// have separate card1 and card2 in the struct -- this "cries out" for an
// array and a loop. Consider the general case where you have 5 cards in the
// hand (e.g. five card charlie). The code would be easier even with an array
// of only two
// check value of first card in hand
if (hnd_ptr->card1 <= '9' && hnd_ptr->card1 >= '2') {
first_card = (int) hnd_ptr->card1 - 48;
}
// check for special cards: king, queen, jack, ten
else if (hnd_ptr->card1 == 'T' || hnd_ptr->card1 == 'K' || hnd_ptr->card1 == 'Q' || hnd_ptr->card1 == 'J') {
first_card = 10;
}
// if first card is Ace
else if (hnd_ptr->card1 == 'A') {
first_card = 11;
}
else {
// card not valid
printf("Not a valid card: %c", hnd_ptr->card1);
return;
}
// check value of 2nd card
if (hnd_ptr->card2 <= '9' && hnd_ptr->card2 >= '2') {
second_card = (int) hnd_ptr->card2 - 48;
}
// if 2nd card is a special kind
else if (hnd_ptr->card2 == 'T' || hnd_ptr->card2 == 'K' || hnd_ptr->card2 == 'Q' || hnd_ptr->card2 == 'J') {
second_card = 10;
}
// if 2nd card is Ace
else if (hnd_ptr->card2 == 'A') {
if (hnd_ptr->card1 == 'A')
second_card = 1;
else
second_card = 11;
}
else {
// if 2nd card not valid
printf("Not a valid card: %c", hnd_ptr->card2);
return;
}
printf("\nThe total card value is: %d", first_card + second_card);
}
//call function, test if works
//calling it wrong?
int
main(void)
{
// NOTE: based on usage, this is only an array because you're not using &hnd
// below
struct player_hand hnd[HAND] = {
{'A', 'A'}
};
// NOTE/BUG: too few arguments to function, but why pass count at all?
getHandValue(hnd, HAND);
// NOTE/BUG: need to return value (e.g. return 0)
return;
}
Here's the cleaned up version:
#include <stdio.h>
#define CARDS_PER_HAND 2
struct player_hand {
char card[CARDS_PER_HAND];
};
void
getHandValue(struct player_hand *hnd_ptr)
{
int idx;
int card;
int sum;
int count[CARDS_PER_HAND];
// get cards from user
printf("Enter Cards:");
fflush(stdout);
for (idx = 0; idx < CARDS_PER_HAND; ++idx)
scanf(" %c", &hnd_ptr->card[idx]);
// print cards
printf("Cards entered:");
for (idx = 0; idx < CARDS_PER_HAND; ++idx)
printf(" %c", hnd_ptr->card[idx]);
printf("\n");
for (idx = 0; idx < CARDS_PER_HAND; ++idx) {
card = hnd_ptr->card[idx];
// simple cards
if (card <= '9' && card >= '2') {
count[idx] = (card - '2') + 2;
continue;
}
switch (card) {
case 'A':
count[idx] = 11;
if ((idx == 1) && (count[0] == 11))
count[idx] = 1;
break;
case 'T':
case 'K':
case 'Q':
case 'J':
count[idx] = 10;
break;
default:
printf("Not a valid card: %c", card);
return;
break;
}
}
sum = 0;
for (idx = 0; idx < CARDS_PER_HAND; ++idx)
sum += count[idx];
printf("The total card value is: %d\n", sum);
}
int
main(void)
{
struct player_hand hnd;
getHandValue(&hnd);
return 0;
}
If, in addition to the other answers, your intent was to pass a 2-hand array, you would need to handle both hands within a loop in your scoring function. For example:
#include <stdio.h>
#define HAND 2
struct player_hand
{
char card1;
char card2;
};
void getHandValue (struct player_hand *hnd_ptr, int size)
{
int first_card;
int second_card;
/* get cards from user */
for (int i = 0; i < size; i++) {
printf ("\nenter cards for hand %d (card1 card2): ", i);
/* you must handle the '\n' that remains after last char */
if (scanf ("%c %c%*c", &hnd_ptr[i].card1, &hnd_ptr[i].card2) != 2) {
fprintf (stderr, "error: invalid entry.\n");
return;
}
printf ("you entered: %c %c\n", hnd_ptr[i].card1, hnd_ptr[i].card2);
}
for (int i = 0; i < size; i++)
{
/* check value of first card in hand */
if(hnd_ptr[i].card1 <= '9' && hnd_ptr[i].card1 >= '2')
{
first_card = (int)hnd_ptr[i].card1 - '0';
}
/* check for special cards: king, queen, jack, ten */
else if (hnd_ptr[i].card1 == 'T' || hnd_ptr[i].card1 == 'K' ||
hnd_ptr[i].card1 == 'Q' || hnd_ptr[i].card1 == 'J')
{
first_card = 10;
}
/* if first card is Ace */
else if (hnd_ptr[i].card1 == 'A')
{
first_card = 11;
}
else
{
/* card not valid */
printf("Not a valid card: %c",hnd_ptr[i].card1);
return;
}
/* check value of 2nd card */
if(hnd_ptr[i].card2 <= '9' && hnd_ptr[i].card2 >= '2')
{
second_card=(int)hnd_ptr[i].card2 - '0';
}
/* if 2nd card is a special kind */
else if (hnd_ptr[i].card2 == 'T' || hnd_ptr[i].card2 == 'K' ||
hnd_ptr[i].card2 == 'Q' || hnd_ptr[i].card2 == 'J')
{
second_card = 10;
}
/* if 2nd card is Ace */
else if (hnd_ptr[i].card2 == 'A')
{
if (hnd_ptr[i].card1 == 'A')
second_card = 1;
else
second_card = 11;
}
else
{
/* if 2nd card not valid */
printf ("Not a valid card: %c", hnd_ptr[i].card2);
return;
}
/* add cards */
printf ("\nThe total cards value (hand %d) is: %d\n",
i, first_card + second_card);
}
}
int main(void)
{
struct player_hand hnd[HAND] = { {'A', 'A'}, {'A', 'A'} };
getHandValue (hnd, HAND);
return 0;
}
Example Use/Output
$ ./bin/cards
enter cards for hand 0 (card1 card2): A A
you entered: A A
enter cards for hand 1 (card1 card2): 8 K
you entered: 8 K
The total cards value (hand 0) is: 12
The total cards value (hand 1) is: 18
If your intent was not to pass an array of struct, then obviously looping would not be necessary. Note: two loops were used. The first to get the cards for both hands, the second to compute the scores for both. (you could do it with one, but it looked as if you intended to have all cards entered before scoring) Look things over and let me know if you have further questions.
You're not passing the address of hnd to the function getHandValue(). To do this you have to pass the address using the & operator getHandValue(&hnd).
You're also not initializing struct player_hand hnd correctly. There's one set of {} too many.
Here's an edited version of your main() code that works, just some minor edits to how your pointer is set up.
// main
int main(void)
{
// minor edits to fix the code here
struct player_hand hnd = {'A', 'A'};
struct player_hand *hndPtr = &hnd;
getHandValue (hndPtr);
return 0;
}

Program written in C, loops indefinately or crashes after a while

this is both my first time asking a question and also one of my first times writting such a big programm. As you might guess im new at programming.
Alright the source code:
#include <stdio.h>
typedef struct{
int **a;
int size;
}_board;
typedef _board* board;
typedef struct{
int row,col;
}position;
int main () {
int i, j, turn=1, victory = 0, num=0;
_board b;
char P1symbol, P2symbol, mark, boardarray[b.size][b.size];
position p;
printf("WELCOME TO THE GAME OF TIC TAC TOE!\n");
do {
printf("\nwill player one, use X or O as his symbols? select by pressing x or o\n");
scanf(" %c", &P1symbol);
if (P1symbol == 'x' || P1symbol == 'o') {
num = 1;
}
} while ( num == 0);
if (P1symbol == 'x') {
P2symbol = "o";
}
else {
P2symbol = "x";
}
do {
printf("\n now choose the size of the game board, type a numeral and press enter");
scanf("%d", &b.size);
}while (b.size <= 0);
for (i=0; i=b.size; i++){
for (j=0; j=b.size; j++){
boardarray[i][j] = "-";
}
}
do {
do {
boardsketch(boardarray, b.size);
if (turn%2 == 1) {
printf("player 1, please choose a box to input you mark on");
mark = P1symbol;
}else{
printf("player 2, please choose a box to input you mark on");
mark = P2symbol;
}
printf("type the coordinates i,j, which correspond to the row and collumn number");
printf("make sure the numbers are valid, not taken, and between 0 and %d", b.size);
scanf("%d %d", &p.row, &p.col);
}while (p.row > b.size && p.row < 0 && p.col > b.size && p.col <0 && boardarray[p.row][p.row] != "-");
turn++;
boardarray[p.row][p.col] = mark;
} while (wincheck(boardarray, p.row, p.col, b.size) != 1);
return 0;
}
int wincheck(int row, int col, int size, char boardarray[size][size])
{
if (boardarray[row][col] = boardarray[row -1][col -1] = boardarray[row +1][col +1]) {
return 1;
}
if (boardarray[row][col] = boardarray[row -1][col] = boardarray[row +1][col]) {
return 1;
}
if (boardarray[row][col] = boardarray[row][col -1] = boardarray[row][col +1]){
return 1;
}
if (boardarray[row][col] = boardarray[row -1][col +1] = boardarray[row +1][col -1]){
return 1;
}
}
void boardsketch(int size, char boardarray[size][size]) {
int i, j;
for (i=0; i=size; i++) {
for (j=0; j=size; j++) {
if (boardarray[i][j] == '-') {
printf("| ");
} else {
printf("%c |", &boardarray[i][j]);
}
}
}
}
Now the program's purpose is to simulate a game of tic tac toe (with the addition of the user, deciding the size of the game board). My problem is that, altough compilation IS achieved the program does 2 wierd behaviors when reaching a specific line, that line being:
do {
printf("\n now choose the size of the game board, type a numeral and press enter");
scanf("%d", &b.size);
}while (b.size <= 0);
If i input a value that doesnt obey to b.size <= 0, the printf above, repeats indefinately, if i DO put a correct value, the programm doesnt resume. What am i doing wrong? again im new at programming sooooo... go easy on me :D
There are compiler errors in your code. I don't know how you got it to compile and build it the first place.
Compiler errors:
You have:
P2symbol = "o";
Type of "o" is char const*. The type of P2symbol is char. What you need is
P2symbol = `o`;
Few lines after that, you have:
P2symbol = "x";
That needs to be changed to:
P2symbol = `x`;
Few lines after that, you have:
boardarray[i][j] = "-";
It suffers from the same compiler error. You need to change it to:
boardarray[i][j] = `-`;
Your declaration and definition of boardsketch does not match with the way you are calling it. Your call is:
boardsketch(boardarray, b.size);
You have defined it as:
void boardsketch(int size, char boardarray[size][size]) {
....
}
You need to change either the call or the function definition so that they match. Also, you should declare the function before it is used. Add
void boardsketch(int size, char boardarray[size][size]);
before the start of main.
The definition and call of wincheck suffers from the same error. It also should have a declaration before it's usage.
A few lines after that call to boardarray, you have the line:
}while (p.row > b.size && p.row < 0 && p.col > b.size && p.col <0 && boardarray[p.row][p.row] != "-");
The last part of that statement suffers from the char and char const* mismatch. You need to change it to:
}while (p.row > b.size && p.row < 0 && p.col > b.size && p.col <0 && boardarray[p.row][p.row] != '-');
Run Time Errors:
You have:
_board b;
char P1symbol, P2symbol, mark, boardarray[b.size][b.size];
The problem with that is b.size is not initialized. It could be anything. Using it to declare broadarray is problem. Imagine the chaos that will ensue if the b.size were to be initialized to a negative number. For sane and predictable behavior, you should initialize b properly before using its data.
A few lines below, you are asking for size to be input by the user.
do {
printf("\n now choose the size of the game board, type a numeral and press enter");
scanf("%d", &b.size);
}while (b.size <= 0);
There is a logic error here. You are asking for the size of the board after you have already created boardarray. What you could do is gather the initial input and use them to call another function where the core of the game play happens.
/* Function that contains the core part of playing the game */
void playgame(char P1symbol, char P2symbol, int size)
{
int i, j, turn=1, victory = 0;
char mark, boardarray[size][size];
position p;
for (i=0; i=size; i++){
for (j=0; j=size; j++){
boardarray[i][j] = '-';
}
}
do {
do {
boardsketch(size, boardarray);
if (turn%2 == 1) {
printf("player 1, please choose a box to input you mark on");
mark = P1symbol;
}else{
printf("player 2, please choose a box to input you mark on");
mark = P2symbol;
}
printf("type the coordinates i,j, which correspond to the row and collumn number");
printf("make sure the numbers are valid, not taken, and between 0 and %d", size);
scanf("%d %d", &p.row, &p.col);
}while (p.row > size && p.row < 0 && p.col > size && p.col <0 && boardarray[p.row][p.row] != '-');
turn++;
boardarray[p.row][p.col] = mark;
} while (wincheck(p.row, p.col, size, boardarray) != 1);
}
Now, main can be simplified to:
int main () {
char P1symbol;
char P2symbol;
int size;
int num = 0;
printf("WELCOME TO THE GAME OF TIC TAC TOE!\n");
do {
printf("\nwill player one, use X or O as his symbols? select by pressing x or o\n");
scanf(" %c", &P1symbol);
if (P1symbol == 'x' || P1symbol == 'o') {
num = 1;
}
} while ( num == 0);
if (P1symbol == 'x') {
P2symbol = 'o';
}
else {
P2symbol = 'x';
}
do {
printf("\n now choose the size of the game board, type a numeral and press enter");
scanf("%d", &size);
}while (size <= 0);
playgame(P1symbol, P2symbol, size);
return 0;
}
Ah, the problem is your for loop after the do while. You are assigning your counters instead of evaluating the limits. Asigning them will result to true every time. Try this instead:
for (i=0; i<b.size; i++){
for (j=0; j<b.size; j++){
boardarray[i][j] = "-";
}
}
Also, do not create an array with undefine value b.size...

My comparison of two strings for a hangman game doesn't work properly

I've been working on a hangman game for a class course and I'm almost done. However, I've stumbled upon a problem that I can't seem to fix.
First, the computer choose a random word from a text file, takes the lenght of that word and with that length creates a masked copy of the original word. Then the game start. The player types in letters and if the word is completed before he/she fails six times, he wins. Otherwise, he/she loose. I think the problem with my code is when I create my mask of the word chosen by the computer, but I'm not sure.
If I run the program it looks something like this:
Chosen word: strand (first control of word chosen by computer)
Chosen word: strand (second control to see if the same word is copied from the function to the string in the main)
Chosen word: monster (this is printed by the free() function. for some reason it's one word higher)
Chosen word: strand (third control is done before the lenght of the word is copied, in order to see if it's the right word being copied, which it is)
Wordlenght: 6 (control to see if the lenght matches the word, which it does)
Mask: _ _ _ _ _ _ N (ignore the spaces between the underscores, they are only there to make it easier to see. this is where i think the problem is, because of the extra character added in the end, the "N" in this case. the number of underscores match the number of letters which is good)
Mask: _ _ _ _ _ _ N (printed by the second free() function)
Then the actual game starts. Everything else works fine (if the player aborts or looses and if the player wants or doesn't want to play again). I checked if the actual strcmp() in the int resultat (char* word, char* mask, int count) function worked, and it did. So the fault has be with the strings being compared. I think it's when I get the lenght of the chosen word with strlen(). When I get the length, I subtract with one because otherwise I would get a lenght which is too long(for example, paper would give a lenght of 6, but when I subtract with one I get 5).
If someone could help me or maybe give me some hints I would be very grateful!
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<time.h>
#define MAX_WORD_LEN 20
char* datorns_val();
int ordlengd(char* word);
char* datorns_val_mask(char* word, int len);
int spel(char* word, char* mask, int len, int count, int result);
int resultat (char* word, char* mask, int count);
char get_user_choice();
void hangman(int count, int result);
const int MAX_GUESS = 6;
const char ABORT_CH = '0';
const int LOOSE = 0;
const int WIN = 1;
const int ABORTED = 2;
/************************************************************
*
* MAIN
*
*
************************************************************/
int main ()
{
char word[MAX_WORD_LEN];
char mask[MAX_WORD_LEN];
int ch;
int len;
int result;
int count;
/* -------------------- Programstart -----------------*/
srand(time(NULL));
while (true)
{
result = 5;
count = 0;
strcpy(word,datorns_val());
printf("Valt ord 2: %s", word);
free(datorns_val());
len = ordlengd(word);
strcpy(mask,datorns_val_mask(word,len));
printf("\nMask 2: %s <-----", mask);
free(datorns_val_mask(word,len));
printf( "\nV\x84lkommen till HANGMAN 2014!\n");
printf( "Du har %d gissningar p\x86 dig (avbryt med 0)\n", MAX_GUESS );
printf( "Datorn har nu valt ett ord p\x86 %d bokst\x84ver\n", len );
/* GAME MAIN LOOP */
while (count < 6)
{
count=spel(word,mask,len,count,result);
result=resultat(word,mask,count);
hangman(count,result);
}
/* END MAIN GAME LOOP */
if( result == WIN )
{
printf("\nGrattis du vann!\n");
}
else if( result == LOOSE )
{
printf("\nTyv\x84rr du f\x94rlorade! Ordet var: %s\n", word);
}
else
{
printf("Avbrutet\n");
}
printf("Vill du spela igen? (j/n)");
ch = get_user_choice();
if (ch == 'n' || ch == 'N')
{
break;
}
}
}
/***********************************************************
*
* --------- Funktionsdefinitioner ----------------
*
***********************************************************/
char get_user_choice()
{
char tkn;
scanf(" %c", &tkn);
return tkn;
}
char* datorns_val()
{
char ordlista[20];
char* valt_ord = malloc(20);
int random;
int raknare = 0;
random = rand()%4+1;
FILE *ptr_file;
ptr_file =fopen("hangman.dat","r");
if (!ptr_file)
{
printf("Filen kunde inte öppnas!");
}
while (fgets(ordlista,20, ptr_file)!= NULL)
{
if (raknare == random)
{
strcpy(valt_ord, ordlista);
break;
}
raknare=raknare+1;
}
printf("Valt ord 1: %s",valt_ord);
fclose(ptr_file);
return valt_ord;
}
int ordlengd(char* word)
{
printf("Valt ord 3: %s", word);
int ordlengd;
ordlengd=strlen(word)-1;
printf("Ordlengd 1: %i", ordlengd);
return ordlengd;
}
char* datorns_val_mask(char* word, int len)
{
int j;
char* gissning = malloc(20);
for (j=0; j<len; j++)
{
gissning[j]='_';
}
printf("\nMask 1: %s <----", gissning);
return gissning;
}
int spel(char* word, char* mask, int len, int count, int result)
{
int j;
char bokstav;
int ratt = 0;
printf("\nSkriv en bokstav: ");
scanf(" %c", &bokstav);
for(j=0; j<len; j++)
{
if(bokstav==word[j])
{
mask[j]=bokstav;
ratt = 1;
}
else if(bokstav=='0')
{
count = 7;
return count;
}
}
if (ratt == 0)
{
printf("\nBokstaven finns inte i ordet!\n");
count=count+1;
}
printf("Antal fel: %i\n\n", count);
ratt = 0;
for (j=0; j<len; j++)
{
printf("%c", mask[j]);
printf(" ");
}
return count;
}
void hangman(int count, int result)
{
const char* str[20];
int j;
str[0]="\n_______ \n";
str[1]=" | \n";
str[2]=" O \n";
str[3]="//|\\\\\n";
str[4]=" | \n";
str[5]="// \\\\\n";
if(result != ABORTED)
{
for (j=0; j<count; j++)
{
printf("%s", str[j]);
}
}
}
int resultat (char* word, char* mask, int count)
{
char* a = "Hej";
char* b = "Hej";
if (count == 6)
{
return LOOSE;
}
else if (count < 6 && strcmp(mask,word) == 0)
{
return WIN;
}
else if (count == 7)
{
return ABORTED;
}
}
There are some things around the code:
1) The first free() call in pointless:
free(datorns_val());
This reserves memory for a string and deletes it without making any use of it. So get rid of it.
2) Using fgets() to read strings from a file stores also the '\n' character at the end of the line into your string, so you must get rid of it. As a hint, I have used this sentence:
while(fscanf(ptr_file,"%s", ordlista) >0)
that does not store '\n' characters.
3) In ordlengd(char* word) function, you had problem with an extra character (the above mentioned '\n') so the length is the same as the one returned by strlen(), not the
strlen(word) - 1
you had written.
4) You have think about another condition to end the while loop of the main function. I would suggest to add
else return 5;
at the end of resultat() function and the check this value en the while loop of the main function
while (count < 6 && result == 5)
Hope it helps

Resources