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

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...

Related

if/else statements in for loop not working

I'm trying to make a program that asks for user input and the for loop should check if the input of both user id and pin matches any of the ten pre-made account's user id and pin, like an authorization system
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct account{
int uid;
int pin;
int user_bal;
};
int main()
{
int scan_uid, scan_pin;
int att = 3;
bool loop = true;
struct account user[10];
user[0].uid = 1234;
user[0].pin = 123456;
user[1].uid = 4181;
user[1].pin = 308592;
user[2].uid =1111;
user[2].pin =111111;
user[3].uid =2222;
user[3].pin =222222;
user[4].uid =4444;
user[4].pin =444444;
user[5].uid =5555;
user[5].pin =555555;
user[6].uid =6666;
user[6].pin =666666;
user[7].uid =7777;
user[7].pin =777777;
user[8].uid =8888;
user[8].pin =888888;
user[9].uid =9999;
user[9].pin =999999;
for (int i; i <= 9; i++){
user[i].user_bal = 1000;
}
do{
printf("\nEnter your user ID: ");
scanf("%d", &scan_uid);
printf("Enter your pin: ");
scanf("%d", &scan_pin);
printf("\n--------------------------------------------\n");
att--;
for (int i; i <= 9; ++i){
//printf("\n%d", i);
//printf("\n%d", user[i].uid);
//printf("\n%d", user[i].pin);
//printf("\n%d", scan_uid);
//printf("\n%d", scan_pin);
if (user[i].uid == scan_uid && user[i].pin == scan_pin){
loop = false;
}
else{
printf("\nThe username or password is incorrect!");
printf("\nYou have %d attempt(s) left.", att);
if (att > 0)
{
printf("\nPlease try again.\n");
}
else if (att == 0)
{
printf("\nUnauthorized Access.");
printf("\nReport for stolen credit card uploaded.");
}
}
}
}while (att > 0 || loop == false);
return 0;
}
I tried the relatively same code in python and it works perfectly there. I also checked if the "i" is correct and incremented and if it scanned the user input correctly. all ok. But i've hit a brick wall trying to solve why it just skips the 'if/else' and just scans input again.
I also tried an 'else if ' that does the opposite(!=) of the initial 'if' statement, with no luck.
Thanks.
Others have already pointed out that you need to initialize int i with int i = 0 in your for loop.
However, I would additionally like to point out several other mistakes here. First, your loop condition appears to be incorrect:
while (att > 0 || loop == false)
You want to continue the loop in the case where they haven't entered the correct value yet and where they still have more attempts left. However, as written, this will continue to loop even if the user enters the correct password. I think that this should actually be
while (att > 0 && loop == true)
Also, most languages don't require you to explicitly compare to true and false, so the following is stylistically better:
while (att > 0 && loop)
Also, as written, it prompts the user to try again; however, it doesn't prompt the user for input again after the first time, so it's impossible for the user to try again. You need to prompt the user for input again inside the loop if their input was incorrect.
A few issues ...
As Dan said, initialize i to 0. This will fix the segfault.
When you do loop = false; you need break; immediately afterwards.
And, your do/while condition is wrong. Change while (att > 0 || loop == false); into while ((att > 0) && loop);
The placement of the "incorrect passwords" related printf is incorrect. It should come after the for.
Otherwise, the same error message will be repeated 9 times for a single incorrect answer.
And, we want to exit the do/while loop [immediately after the for loop] if we see loop become false.
Here is the refactored code. It is annotated:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct account {
int uid;
int pin;
int user_bal;
};
int
main(void)
{
int scan_uid,
scan_pin;
int att = 3;
bool loop = true;
struct account user[10];
user[0].uid = 1234;
user[0].pin = 123456;
user[1].uid = 4181;
user[1].pin = 308592;
user[2].uid = 1111;
user[2].pin = 111111;
user[3].uid = 2222;
user[3].pin = 222222;
user[4].uid = 4444;
user[4].pin = 444444;
user[5].uid = 5555;
user[5].pin = 555555;
user[6].uid = 6666;
user[6].pin = 666666;
user[7].uid = 7777;
user[7].pin = 777777;
user[8].uid = 8888;
user[8].pin = 888888;
user[9].uid = 9999;
user[9].pin = 999999;
for (int i; i <= 9; i++) {
user[i].user_bal = 1000;
}
do {
printf("\nEnter your user ID: ");
scanf("%d", &scan_uid);
printf("Enter your pin: ");
scanf("%d", &scan_pin);
printf("\n--------------------------------------------\n");
att--;
// NOTE/BUG: i is uninitialized
#if 0
for (int i; i <= 9; ++i) {
#else
for (int i = 0; i <= 9; ++i) {
#endif
// printf("\n%d", i);
// printf("\n%d", user[i].uid);
// printf("\n%d", user[i].pin);
// printf("\n%d", scan_uid);
// printf("\n%d", scan_pin);
if (user[i].uid == scan_uid && user[i].pin == scan_pin) {
loop = false;
// NOTE/FIX: no need to continue loop if we get a match
#if 1
break;
#endif
}
}
#if 1
// stop if everything matched
if (! loop)
break;
#endif
printf("\nThe username or password is incorrect!");
printf("\nYou have %d attempt(s) left.", att);
if (att > 0) {
printf("\nPlease try again.\n");
}
else if (att == 0) {
printf("\nUnauthorized Access.");
printf("\nReport for stolen credit card uploaded.");
}
} while (att > 0);
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
First of all, you should initialize i to 0
To browse all array contents, you should increment i after the instruction NOT before (i++) instead of (++i)
Condition while loop is WRONG
Look at this version of your code, It works properly:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct account{
int uid;
int pin;
int user_bal;
};
int main()
{
int scan_uid, scan_pin;
int att = 3;
bool loop = true;
struct account user[10] = {0};
user[0].uid = 1234;
user[0].pin = 123456;
user[1].uid = 4181;
user[1].pin = 308592;
user[2].uid =1111;
user[2].pin =111111;
user[3].uid =2222;
user[3].pin =222222;
user[4].uid =4444;
user[4].pin =444444;
user[5].uid =5555;
user[5].pin =555555;
user[6].uid =6666;
user[6].pin =666666;
user[7].uid =7777;
user[7].pin =777777;
user[8].uid =8888;
user[8].pin =888888;
user[9].uid =9999;
user[9].pin =999999;
for (int i = 0; i <= 9; i++){
user[i].user_bal = 1000;
}
do{
printf("\n--------------------------------------------\n");
printf("\nEnter your user ID: ");
scanf("%d", &scan_uid);
printf("Enter your pin: ");
scanf("%d", &scan_pin);
printf("\n--------------------------------------------\n");
att--;
for (int i = 0; i <= 9; i++){
//printf("\n%d", i);
//printf("\n%d", user[i].uid);
//printf("\n%d", user[i].pin);
//printf("\n%d", scan_uid);
//printf("\n%d", scan_pin);
if (user[i].uid == scan_uid && user[i].pin == scan_pin)
{
loop = false;
break;
}
}
if (loop && att)
{
printf("\nThe username or password is incorrect!");
printf("\nYou have %d attempt(s) left.", att);
}
else if (! att && loop)
{
printf("\nUnauthorized Access.");
printf("\nReport for stolen credit card uploaded.\n");
}
else if (!loop)
{
printf("\nMatches !\n");
}
} while ((att > 0) && (loop == true));
return 0;
}

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;
}
}
}

Why I get very huge output in printf on C language?

This is my code, I want to calculate distance between robot and monster, but the output "horizontal and vertikal" is false
#include <stdio.h>
void findPos(char *dir, int a, int b)
{
int up = 0, down = 0;
int left = 0, right = 0;
int i,x,y;
for (i = 0; dir[i] != '\0' ; i++) {
//Counts each direction
if (dir[i] == 'U' || dir[i] == 'u')
up++;
else if (dir[i] == 'D' || dir[i] == 'd')
down++;
else if (dir[i] == 'L' || dir[i] == 'l')
left++;
else if (dir[i] == 'R' || dir[i] == 'r')
right++;
//In case of illegal character in the string
else
{
printf("Position Unable to Find, Enter Correct Direction.");
break;
}
}
//Final position of robot
x = right - left;
y = up - down;
printf("Final Position of the Robot: (");
printf("%d", x);
printf(",%d", y);
print(")");
printf("\nposition between robot and monster");
printf("\nhorizontal: %d", a-x);
printf("\nvertikal: %d", b-y);
}
int main()
{
char *dir;
int a,b,t;
/* Intializes random number generator */
srand((unsigned) time(&t));
/* Print 2 random numbers from 0 to 100 */
a = rand() % 100;
b = rand() % 100;
printf("\nCoordinate of monster: ");
printf("(%d,", a);
printf("%d)", b);
//Input the direction string
printf("\nEnter the Direction String: ");
scanf("%s", &dir);
//Function call to calculate position
findPos(&dir, a,b);
return 0;
}
and this is the output
Coordinate of monster: (5,47)
Enter the Direction String: UURRRRRLLL
Final Position of the Robot: (2,2)
position between robot and monster
horizontal: 19530
vertikal: 1280463440
it seems your program is exhibiting undefined behavior, you are actually lucky its not crashing, dir is never allocated . you might want to calloc it before using , also remove the & in scanf, infact move to fgets unless inclined to use scanf
printf("\nEnter the Direction String: ");
scanf("%s", dir);

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;
}

Why is this simple C tic-tac-toe program "forgetting" the value at position [0][0] in an array, but works fine for everything else?

The format for inserting a move is xYZ, where x is either 'o' or 'x', Y is the line number and Z is the column number.
If you try to play x11 and then o11, for example, it will correctly point out that it's an invalid play since (1,1) is already occupied. It works for every position BUT (0,0), where for some reason it lets you keep playing the same move over and over.
I also know that it draws the board properly after your move, so if you play o00 it will show a O at (0,0), but then it will forget that position come next turn.
Example: http://image.prntscr.com/image/e002bb6db5da4c7b823bf9bcac7af5eb.png
Code:
#include <stdio.h>
int main()
{
int board[3][3] = { 0 };
int i, j, linha, coluna, valido, run = 1;
char comando[3], jogador, ultimo_jogador;
while (run) {
//recebe o comando para executar esse turno
valido = 0;
do {
printf("Digite a jogada: ");
scanf(" %3[^\n]", comando);
jogador = comando[0];
linha = comando[1] - 48;
coluna = comando[2] - 48;
if ((jogador == 'x' || jogador == 'o') && jogador != ultimo_jogador && board[linha][coluna] == 0) {
if (jogador == 'x')
board[linha][coluna] = 1;
else if (jogador == 'o')
board[linha][coluna] = 2;
ultimo_jogador = jogador;
valido = 1;
}
else {
printf("Comando inválido\n");
}
} while (!valido);
//desenha o tabuleiro do jogo
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
if (i == 0 && j == 0)
printf("Value at 0,0: %d\n", board[i][j]);
if (board[i][j] == 0) {
printf("_|");
}
else if (board[i][j] == 1) {
printf("X|");
}
else if (board[i][j] == 2) {
printf("O|");
}
}
printf("\n");
}
}
return 0;
}
You just had a visit of undefined behaviour AKA UB.
I finally found an explanation:
You define comando with a size of 3, but when scanning the string, you're entering 3 chars but you miss the space for the string termination.
In our tests, the value overwrites some local variable like i or j, which is not noticeable since they're initialized afterwards and each time, but your compiler seem to locate the board memory just after the comando buffer (the compiler can do whatever it pleases with local variable addresses)
The result is that you're overwriting the first cell each time you input your value.
Solution: do this:
char comando[4];

Resources