Segmentation Fault in Craps program

T

tigrfire

I've been working on a program to try and play a game of Craps, based
on a version I found elsewhere - I didn't code the original, but I
added a few things such as a balance and wager system. I'm having
trouble doing it all without using global variables though, so I have
another post in this group about local variable usage and how to pass
it, but just when I thought I'd got it, my program has a segmentation
fault. I'm not exactly sure what a seg fault is, but I didn't get any
warnings about it when I compiled. I'm posting my program here to see
if anyone can tell me what I'm doing wrong. I'm almost positive it has
something to do with the way I pass variables between multiple
functions, most likely, between playGame() and getYesOrNo().

#include <stdio.h>
#include <stdlib.h>
#include <time.h> /* contains prototype for function time */

/* enumeration constants represent game status */
enum Status { CONTINUE, WON, LOST };

int rollDice( void ); /* function prototype */
int getWager(); /* getWager function prototype */
int playGame(); /* playGame function prototype */
void getYesOrNo(); /* getYesOrNo function prototype */

int main()
{
playGame();
return 0;
}


/* PRE: none
POST: returns to the caller one of the enumatered constants WON or
LOST */

int playGame ()
{
int sum; /* sum of rolled dice */
int myPoint; /* point earned */
int balance; /* user's current balance */
int theWager;

theWager = getWager();

balance = 1000;

printf("Balance = $%d.00\n",balance);

getWager();

enum Status gameStatus; /* can contain CONTINUE, WON, or LOST */

/* randomize random number generator using current time */
srand( time( NULL ) );

sum = rollDice(); /* first roll of the dice */

/* determine game status based on sum of dice */
switch( sum ) {

/* win on first roll */
case 7:
case 11:
gameStatus = WON;
break;

/* lose on first roll */
case 2:
case 3:
case 12:
gameStatus = LOST;
break;

/* remember point */
default:
gameStatus = CONTINUE;
myPoint = sum;
printf( "Point is %d\n", myPoint );
break; /* optional */
} /* end switch */

/* while game not complete */
while ( gameStatus == CONTINUE ) {
sum = rollDice(); /* roll dice again */

/* determine game status */
if ( sum == myPoint ) { /* win by making point */
gameStatus = WON; /* game over, player won */
} /* end if */
else {

if ( sum == 7 ) { /* lose by rolling 7 */
gameStatus = LOST; /* game over, player lost */
} /* end if */

} /* end else */

} /* end while */

/* display won or lost message */
if ( gameStatus == WON ) { /* did player win? */
printf( "Player wins\n" );
} /* end if */
else { /* player lost */
printf( "Player loses\n" );
} /* end else */

if (balance > 0)
{
getYesOrNo();
}
else
{
printf("Your final balance is $%d.00", balance);
}
return balance;
}


/* roll dice, calculate sum and display results */
int rollDice( void )
{
int die1; /* first die */
int die2; /* second die */
int workSum; /* sum of dice */

die1 = 1 + ( rand() % 6 ); /* pick random die1 value */
die2 = 1 + ( rand() % 6 ); /* pick random die2 value */
workSum = die1 + die2; /* sum die1 and die2 */

/* display results of this roll */
printf( "Player rolled %d + %d = %d\n", die1, die2, workSum );

return workSum; /* return sum of dice */

} /* end function rollRice */


/* PRE: player inputs a dollar amount to wager on next game
POST: function checks wager, if wager is invalid, prompt user to
enter new wager. when valid
wager is entered, returns to the calling function */


int getWager()
{
int wager;
int theBalance;

theBalance = playGame();

printf("Enter wager: ");
scanf("%d", &wager);

while (wager > theBalance || wager <= 0)
{
printf("Your wager must not exceed your current balance.\n");
printf("Enter a new wager: ");
scanf("%d", &wager);
}
return wager;
}


/* PRE: checks whether or not the last game was WON or LOST
POST: either adds or subtracts the wager from the player's current
balance */
/*
void adjustBalance()
{
if (gameStatus = WON)
{
balance = balance + wager;
}
else
{
balance = balance - wager;
}
}
*/

/* PRE: asks if the user desires to play another game of craps
POST: function checks the response to make sure it is either 'y' or
'n'.
the function will repeatedly ask until one of these conditions is
satisfied
and upon a valid answer, return to the calling function */

void getYesOrNo()
{
printf("Do you want to play another game? (y or n): ");

char ch;
int theBalance;

theBalance = playGame();

ch = getchar();
while (getchar() != '\n');

if (ch == 'y')
{
playGame();
}
else if
(ch == 'n')
{
printf("Your final balance is $%d.00", theBalance);
}
else
{
printf("You must answer y or n.\n\n");
getYesOrNo();
}
}

Note: I know the program's not perfect yet, it doesn't run correctly
and has a lot of things that still need fixing, so if you point them
out, I'm probably aware of them, just don't know how to fix them yet.
 
O

Old Wolf

tigrfire said:
my program has a segmentation fault. I'm not exactly sure what
a seg fault is, but I didn't get any warnings about it when I
compiled. I'm posting my program here to see if anyone can tell
me what I'm doing wrong.

int playGame ()
{
int sum; /* sum of rolled dice */
int myPoint; /* point earned */
int balance; /* user's current balance */
int theWager;

theWager = getWager(); [snip]
}


int getWager()
{
int wager;
int theBalance;

theBalance = playGame();
[snip]

The first thing playGame() does is to call getWager().
And the first thing getWager() does is to call playGame().

See the problem?
 
T

tigrfire

That's what I figured the problem was, but that just leads me to
another problem: How do I get my other functions to see each other's
local variables without resorting to the method I already have. If I
modify the way it is, how can I accomplish that, I'm just a little lost.
 
M

Mike Wahler

tigrfire said:
That's what I figured the problem was, but that just leads me to
another problem: How do I get my other functions to see each other's
local variables

You don't (that is, you shouldn't). That's what 'local' means.

You can inform other functions of their values by passing their
values as arguments to those other functions.

(You *can* give other functions direct access to them
by passing their addresses as arguments, but whether or not
this is a good idea depends upon the purpose of those other
functions. In your example, there's no reason to).
without resorting to the method I already have. If I
modify the way it is, how can I accomplish that, I'm just a little lost.

I think you still haven't figured out exactly what it is you
want to do. Try expressing it in terms of the problem you
want to solve rather than with what code you *think* *might*b
be necessary. I too often see novices end up making a program
much more complex than necessary.

-Mike
 
T

tigrfire

I'll give it a try Mike, let me set it all up then.

I have my current program, as is, listed above, which I want to perform
as follows:
1. Outputs player's current balance
2. Prompts user for a wager which must be greater than 0 and less than
the player's current balance.
3. If this input is invalid, prompts the user for another input using a
different prompt statement.
4. After input is validated, a craps game is played using random number
generators.
5. Another function performs the addition or subtraction, dependant on
the gameStatus being WON or LOST.
6. After each game, the player is prompted whether he would like to
play another game, assuming balance > 0.

My current problems:
1. I can output the current player's balance, but I don't know if it
will still work if the balance itself changes.
2. Since I'm using only local variables, I'm kind of stumped out how to
have multiple functions play around with the same variable. I think I
finally have a clear example of this for demonstration:

int getWager()
{
int wager;
int balance; /* user's current balance */

balance = 1000;

printf("Balance = $%d.00\n",balance);

printf("Enter wager: ");
scanf("%d", &wager);

while (wager > balance || wager <= 0)
{
printf("Your wager must not exceed your current balance.\n");
printf("Enter a new wager: ");
scanf("%d", &wager);
}
return wager;
}


void adjustBalance()
{

if (gameStatus = WON)
{
balance = balance + wager;
}
else
{
balance = balance - wager;
}
}

As you can see, both functions need to interpret the same balance and
wager values, but I can't do it with a global variable so I need a way
to pass both the balance and wager from getWager() to adjustBalance().
This is the krux of my problems in this program actually, so I'll just
leave it there for now. gameStatus is based out of my original program
posted earlier, which the function adjustBalance() also needs to be
able to understand.
 
M

Mike Wahler

tigrfire said:
I'll give it a try Mike, let me set it all up then.

I have my current program, as is, listed above, which I want to perform
as follows:
1. Outputs player's current balance
2. Prompts user for a wager which must be greater than 0 and less than
the player's current balance.
3. If this input is invalid, prompts the user for another input using a
different prompt statement.
4. After input is validated, a craps game is played using random number
generators.
5. Another function performs the addition or subtraction, dependant on
the gameStatus being WON or LOST.
6. After each game, the player is prompted whether he would like to
play another game, assuming balance > 0.

My current problems:
1. I can output the current player's balance, but I don't know if it
will still work if the balance itself changes.
2. Since I'm using only local variables, I'm kind of stumped out how to
have multiple functions play around with the same variable. I think I
finally have a clear example of this for demonstration:

int getWager()
{
int wager;
int balance; /* user's current balance */

balance = 1000;

printf("Balance = $%d.00\n",balance);

printf("Enter wager: ");
scanf("%d", &wager);

while (wager > balance || wager <= 0)
{
printf("Your wager must not exceed your current balance.\n");
printf("Enter a new wager: ");
scanf("%d", &wager);
}
return wager;
}


void adjustBalance()
{

if (gameStatus = WON)
{
balance = balance + wager;
}
else
{
balance = balance - wager;
}
}

As you can see, both functions need to interpret the same balance and
wager values, but I can't do it with a global variable so I need a way
to pass both the balance and wager from getWager() to adjustBalance().
This is the krux of my problems in this program actually, so I'll just
leave it there for now. gameStatus is based out of my original program
posted earlier, which the function adjustBalance() also needs to be
able to understand.

I'm still not perfectly clear on your exact requirements, so I put
together a simple 'guessing game' program that I feel does address
many of your questions about passing data among several functions.
Study the code, compile it and see how it behaves.

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

/* Arbitrary beginning balance, adjust to taste. */
#define BEGIN_BALANCE 1000

/* Throws away extraneous characters from input. */
void discard(void)
{
int c = 0;

while((c = getchar()) != '\n' && c != EOF)
; /* no-op */
}

/* Ask for wager amount. */
int getWager(void)
{
unsigned int amount = 0;

printf("Amount of wager: ");
fflush(stdout);
scanf("%u", &amount);
discard();
return amount;
}

/* Pose question: I'm thinking of a number, what is it? */
/* returns 1 for correct guess, -1 for incorrect guess. */
int guess(void)
{
int result = 0;
int answer = rand(); /* I'm thinking of a random number */
int try = 0; /* will store user's guess */

/* ***** */
/* following line is a 'cheat' line, to let you watch the */
/* balance increase for correct answers. Remove it for a */
/* 'real' game. */
printf(" [answer == %d]\n", answer); /** CHEAT **/

printf("Guess a number between 0 and %d: ", RAND_MAX);
fflush(stdout);
scanf("%d", &try);
discard();

if(answer == try)
puts("Correct!");
else
puts("Wrong!");

fflush(stdout);

if(answer == try)
result = 1;
else
result = -1;

return result;

}

/* Adjusts given balance by multiplying wager amount with */
/* guess result (1 or -1), then subtracting product from */
/* given balance. Returns new balance. */
unsigned int adjust(unsigned int balance, unsigned int wager)
{
unsigned int new_bal = balance;

/* only play if wager not zero. */
if(wager)
{
if(wager <= balance)
new_bal = balance + wager * guess();
else
puts("Insufficient funds");
}

printf("Your new balance is %u\n", new_bal);
return new_bal;
}

/* Loop: Asks for wager amount, adjusting balance with game */
/* result. Continues as long as user answers 'Y' or 'y' to */
/* "play again" prompt, and balance is greater than zero. */
void play()
{
unsigned int balance = BEGIN_BALANCE;
char again = 'Y';

srand((unsigned int)time(0)); /* seed random number generator */

/* call adjust() with 0 wager for initial display of balance amount */
adjust(balance, 0);

while((again == 'Y' || again == 'y') && balance)
{
/* get wager, play game, adjust balance */
/* according to game result */
unsigned int wager = getWager();
balance = adjust(balance, wager);

/* check balance, ask to play again if greater than zero */
if(balance)
{
printf("Play again? ");
fflush(stdout);
scanf("%c", &again);
discard();
}
else
puts("You're broke. Good bye!");
}
}

int main()
{
play(); /* Let's gamble! */
return 0;
}

-Mike
 
T

tigrfire

Mike said:
tigrfire said:
I'll give it a try Mike, let me set it all up then.

I have my current program, as is, listed above, which I want to perform
as follows:
1. Outputs player's current balance
2. Prompts user for a wager which must be greater than 0 and less than
the player's current balance.
3. If this input is invalid, prompts the user for another input using a
different prompt statement.
4. After input is validated, a craps game is played using random number
generators.
5. Another function performs the addition or subtraction, dependant on
the gameStatus being WON or LOST.
6. After each game, the player is prompted whether he would like to
play another game, assuming balance > 0.

My current problems:
1. I can output the current player's balance, but I don't know if it
will still work if the balance itself changes.
2. Since I'm using only local variables, I'm kind of stumped out how to
have multiple functions play around with the same variable. I think I
finally have a clear example of this for demonstration:

int getWager()
{
int wager;
int balance; /* user's current balance */

balance = 1000;

printf("Balance = $%d.00\n",balance);

printf("Enter wager: ");
scanf("%d", &wager);

while (wager > balance || wager <= 0)
{
printf("Your wager must not exceed your current balance.\n");
printf("Enter a new wager: ");
scanf("%d", &wager);
}
return wager;
}


void adjustBalance()
{

if (gameStatus = WON)
{
balance = balance + wager;
}
else
{
balance = balance - wager;
}
}

As you can see, both functions need to interpret the same balance and
wager values, but I can't do it with a global variable so I need a way
to pass both the balance and wager from getWager() to adjustBalance().
This is the krux of my problems in this program actually, so I'll just
leave it there for now. gameStatus is based out of my original program
posted earlier, which the function adjustBalance() also needs to be
able to understand.

I'm still not perfectly clear on your exact requirements, so I put
together a simple 'guessing game' program that I feel does address
many of your questions about passing data among several functions.
Study the code, compile it and see how it behaves.

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

/* Arbitrary beginning balance, adjust to taste. */
#define BEGIN_BALANCE 1000

/* Throws away extraneous characters from input. */
void discard(void)
{
int c = 0;

while((c = getchar()) != '\n' && c != EOF)
; /* no-op */
}

/* Ask for wager amount. */
int getWager(void)
{
unsigned int amount = 0;

printf("Amount of wager: ");
fflush(stdout);
scanf("%u", &amount);
discard();
return amount;
}

/* Pose question: I'm thinking of a number, what is it? */
/* returns 1 for correct guess, -1 for incorrect guess. */
int guess(void)
{
int result = 0;
int answer = rand(); /* I'm thinking of a random number */
int try = 0; /* will store user's guess */

/* ***** */
/* following line is a 'cheat' line, to let you watch the */
/* balance increase for correct answers. Remove it for a */
/* 'real' game. */
printf(" [answer == %d]\n", answer); /** CHEAT **/

printf("Guess a number between 0 and %d: ", RAND_MAX);
fflush(stdout);
scanf("%d", &try);
discard();

if(answer == try)
puts("Correct!");
else
puts("Wrong!");

fflush(stdout);

if(answer == try)
result = 1;
else
result = -1;

return result;

}

/* Adjusts given balance by multiplying wager amount with */
/* guess result (1 or -1), then subtracting product from */
/* given balance. Returns new balance. */
unsigned int adjust(unsigned int balance, unsigned int wager)
{
unsigned int new_bal = balance;

/* only play if wager not zero. */
if(wager)
{
if(wager <= balance)
new_bal = balance + wager * guess();
else
puts("Insufficient funds");
}

printf("Your new balance is %u\n", new_bal);
return new_bal;
}

/* Loop: Asks for wager amount, adjusting balance with game */
/* result. Continues as long as user answers 'Y' or 'y' to */
/* "play again" prompt, and balance is greater than zero. */
void play()
{
unsigned int balance = BEGIN_BALANCE;
char again = 'Y';

srand((unsigned int)time(0)); /* seed random number generator */

/* call adjust() with 0 wager for initial display of balance amount */
adjust(balance, 0);

while((again == 'Y' || again == 'y') && balance)
{
/* get wager, play game, adjust balance */
/* according to game result */
unsigned int wager = getWager();
balance = adjust(balance, wager);

/* check balance, ask to play again if greater than zero */
if(balance)
{
printf("Play again? ");
fflush(stdout);
scanf("%c", &again);
discard();
}
else
puts("You're broke. Good bye!");
}
}

int main()
{
play(); /* Let's gamble! */
return 0;
}

-Mike

Thanks Mike for the great code to study. I've been really trying to
reproduce your methodization, but am still having some difficult. I've
re-written most of the program as the following code shows (read after
for problems) :

#include <stdio.h>
#include <stdlib.h>
#include <time.h> /* contains prototype for function time */

#define beginbalance 1000

/* enumeration constants represent game status */
enum Status { CONTINUE, WON, LOST };

int rollDice(void); /* rollDice function prototype */
int playGame(void); /* playGame function prototype */
int getWager(void);
int adjustBalance(int balance, int wager);
void getYesOrNo(int balance);

int main()
{
playGame();
return 0;
}


/* PRE: none
POST: returns to the caller one of the enumatered constants WON or
LOST */

int playGame (void)
{
int sum; /* sum of rolled dice */
int myPoint; /* point earned */
int result = 0; /* integer defining whether or not last game was WON
or LOST */
int balance = beginbalance;

printf("Balance = $%d.00\n",balance);

int wager = getWager();

enum Status gameStatus; /* can contain CONTINUE, WON, or LOST */

/* randomize random number generator using current time */
srand( time( NULL ) );

sum = rollDice(); /* first roll of the dice */

/* determine game status based on sum of dice */
switch( sum ) {

/* win on first roll */
case 7:
case 11:
gameStatus = WON;
break;

/* lose on first roll */
case 2:
case 3:
case 12:
gameStatus = LOST;
break;

/* remember point */
default:
gameStatus = CONTINUE;
myPoint = sum;
printf( "Point is %d\n", myPoint );
break; /* optional */
} /* end switch */

/* while game not complete */
while ( gameStatus == CONTINUE ) {
sum = rollDice(); /* roll dice again */

/* determine game status */
if ( sum == myPoint ) { /* win by making point */
gameStatus = WON; /* game over, player won */
} /* end if */
else {

if ( sum == 7 ) { /* lose by rolling 7 */
gameStatus = LOST; /* game over, player lost */
} /* end if */

} /* end else */

} /* end while */

/* display won or lost message */
if ( gameStatus == WON ) { /* did player win? */
printf( "Player wins\n" );
result = 1;
} /* end if */
else { /* player lost */
printf( "Player loses\n" );
result = -1;
} /* end else */

adjustBalance(balance, wager);
getYesOrNo(balance);

return result;
}


/* roll dice, calculate sum and display results */
int rollDice(void)
{
int die1; /* first die */
int die2; /* second die */
int workSum; /* sum of dice */

die1 = 1 + ( rand() % 6 ); /* pick random die1 value */
die2 = 1 + ( rand() % 6 ); /* pick random die2 value */
workSum = die1 + die2; /* sum die1 and die2 */

/* display results of this roll */
printf( "Player rolled %d + %d = %d\n", die1, die2, workSum );

return workSum; /* return sum of dice */

} /* end function rollRice */


/* PRE: player inputs a dollar amount to wager on next game
POST: function checks wager, if wager is invalid, prompt user to
enter new wager. when valid
wager is entered, returns to the calling function */

int getWager(void)
{
int amount = 0;

printf("Enter wager: ");
scanf("%d", &amount);

return amount;
}


/* PRE: checks whether or not the last game was WON or LOST
POST: either adds or subtracts the wager from the player's current
balance */

int adjustBalance(int balance, int wager)
{
int newbalance = balance;

if (wager)
{
if (wager <= balance)
{
newbalance = balance + wager * playGame();
}
else
{
printf("Your wager must not exceed your current balance.\n");
getWager();
}
}

printf("Balance = $%d.00\n",newbalance);

return newbalance;
}


/* PRE: asks if the user desires to play another game of craps
POST: function checks the response to make sure it is either 'y' or
'n'.
the function will repeatedly ask until one of these conditions is
satisfied
and upon a valid answer, return to the calling function */

void getYesOrNo(int balance)
{
char ch;

printf("Do you want to play another game? (y or n): ");

ch = getchar();
while (getchar() != '\n');

if (getchar() == 'y')
{
playGame();
}
else if (getchar() == 'n')
{
printf("\n\nYour final balance is $%d.00",balance);
}
else
{
printf("You must answer y or n.");
getYesOrNo(balance);
}
}

--------------

This code, if you compile it, introduces some problems.
1. getYesOrNo doesn't function properly either reading the user input,
or showing up after each game at the appropriate time. A little
difficult understanding my wording, more obvious if compiled.

2. If balance < wager, program does not output current balance on next
game.

3. Balance, despite my best efforts with your code, doesn't seem to
ever change, staying at $1000. I'm sure this is due to some poor
writing on my part trying to do things your way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top