3

Edit: Thank you so so much (everyone!) for your comments! I was able to fix the win percentage and the wonky array numbers with your guidance. however, I have yet to fix the average # of bets it takes to win or lose. I updated my code, now below.

Begin original post:

Thank you in advance to anyone who reads this or reaches out with advice!

So I am doing the stereotypical gamble until you win or it is all gone dealie for an intro to programming course. The code works great, except when I actually add the heads or tails part - then my array that holds numbers of bets gets messed up. When I use notes to hide the actual coin toss part, the array works fine. When I run it with the coin toss, the betArray stores really wonky numbers (negative integers, integers in the billions).

Here is the code so far:

#include<stdio.h>
#include<stdlib.h> /*Enables use of rand()*/

int main () {

    setvbuf(stdout, NULL, _IONBF, 0); /*Allow me to use repl.it*/

    /*Enter Gambler's name*/

    char gambleName[15] = "";
    printf("Enter gambler's name:\n");
    scanf("%s", gambleName);
    printf("\nWelcome, ");
    printf("%s! \n", gambleName);

    /*Enter Stakes*/
    int availableFunds;
    int goalFunds;
    printf("We'll be betting $1 per bet. Enter your available funds:\n");
    scanf("%d", &availableFunds); /* Saves stakes as availableFunds */
    int seedVal=4;
    srand(seedVal);
    /*Butter the gamblers up*/
    if(availableFunds>=1) {
        printf("%d? Wow, %s - that's a great start!\n",availableFunds, gambleName); 
        /*Enter Goal*/
        printf("How much do you want to win today? Enter a value up to 10000 with no commas, decimals or spaces:\n"); /*Saves goal as goalFunds*/
        scanf("%d",&goalFunds);
        /*Recognize ambitious gamblers*/
        if (goalFunds > 10*availableFunds) {
            printf("Wow, ambitious! Let's get started.\n");
        }
        else {
            printf("OK, let's get started!\n");
        }
        printf("\n");
        /*begin gambling problem*/
        int betArray[1000]={0};
        int game = 0;
        int bet=0;
        float wins = 0;
        int losses = 0;
        for (game=0 ; game<1000; game++) {
            if (availableFunds>0 && availableFunds<goalFunds) { 
                int toss = rand()%2;
                bet+=1;
                /*losing bet*/
                if (toss == 0) {
                    availableFunds -= 1;
                    losses += 1;
                }
                /*winning bet*/
                else {
                    availableFunds += 1;
                    wins += 1;
                }
                betArray[game+1] = bet;
            }   
            else {
                break;
            }
        }
        int sumBet = 0;
        for (game=0;game<1000;game++) {
            sumBet+=betArray[game];
        }
        float betAverage = sumBet/1000;
        float winOutOfGames = wins/1000;
        float winPercent = winOutOfGames*100;
        /*print totals*/
        printf("%d games played with:\n",game); 
        printf("%.f goals reached\n",wins); 
        printf("%d down-and-out losses.\n",losses);
        printf("You won ~%.1f%% of your games.\n",winPercent);
        printf("On average, it took you %.f bets to win or go broke.\n",betAverage);
        printf("\n");
        printf("Thanks for playing!\n");
        for (game = 1; game <= 50; game++) {
            printf("Bets in game [%d] = %d\n",game,betArray[game]); 
        }   
    }
    /* Send the broke guys packing*/
    else {
        printf("$%d...? You may need to stop at an ATM... ¯\\_(ツ)_/¯ See you next     time!\n", availableFunds);
    }
    return 0;
}

Sorry if the code is a little messy, I added some stuff to try and wanted to send the latest version.

Thanks!

sokkyoku
  • 2,161
  • 1
  • 20
  • 22
Kevin W.
  • 31
  • 5
  • 1
    Have you used a debugger? – kaylum Oct 05 '16 at 03:03
  • I feel bad, but I don't really know what that means. I'm on Mac OSX, any suggestions on a debugger? – Kevin W. Oct 05 '16 at 03:05
  • 1
    Inside the `if (availableFunds>0 && availableFunds – M.M Oct 05 '16 at 03:07
  • I did post the code (I think? At least, it returns very weird array results in repl.it). I supplied Kevin for gamblerName, 50 for availableFunds and 200 for goalFunds. Edit: Didn't realize enter meant submit. Thank you! I will check into that. – Kevin W. Oct 05 '16 at 03:07
  • @KevinWestermann That's like a carpenter not knowing what a hammer is :-) I don't use OSX so can't recommend anything but your friend google is likely to know so go ahead and ask. – kaylum Oct 05 '16 at 03:08
  • @kaylum I literally feel so silly in this class. I'm in civil engineering - I've done HTML and stuff for marketing jobs in the past, but even basic C is making my head implode. I will start looking for a debugger. – Kevin W. Oct 05 '16 at 03:11
  • @M.M I fixed what you mentioned, and it did work to make the array less insane - however, now it just outputs the number of games played. – Kevin W. Oct 05 '16 at 03:11
  • You have to show exactly what and how you fixed it. We can't comment on code we can't see. – kaylum Oct 05 '16 at 03:12
  • @kaylum I moved `betArray[game]` (i.e., deleted it from `else if`) up to the `if (availableFunds>0 && availableFunds – Kevin W. Oct 05 '16 at 03:15
  • Click "edit" under your question and add a new section with the updated code. External links are not good as they can go away and code in comments is unreadable or easily missed by others. – kaylum Oct 05 '16 at 03:16
  • Your new code will assign a 1 larger value to each array cell than the previous time, until array funds reaches 0 or too big in which case you stop assigning and so will end up with garbage in the array again... if you aren't going to step through in a debugger then you need to at least step through the loop in your head and see what each line is doing – M.M Oct 05 '16 at 03:18
  • On macOS Sierra, and on Mac OS X (prior to Sierra), the `lldb` debugger is provided with XCode. You can compile GDB easily enough, but you have to sign the binary before you can use it. – Jonathan Leffler Oct 05 '16 at 04:53
  • 1
    Note that `int winRatio = wins/game;` will be zero unless the punter was fabulously lucky and actually won every single game. The values are all integers. You need to coerce at least one of `wins` or `game` to a floating point type, and `winRatio` should be a floating point type too. You probably need a `break;` in `else if (availableFunds == 0 || availableFunds >= goalFunds) { }` and I think you should omit the `if` condition; it is just the `else` clause compared to the 'if it is OK to gamble' condition before it. – Jonathan Leffler Oct 05 '16 at 04:57
  • @M.M So I see what you said, but I don't understand how to fix it. I've walked myself through the loop a thousand times, but I just don't see where the problem is - while `game` is counting up from 0 to 999 and the loop is checking for the value of `availableFunds`, it should be betting and winning/losing `bet` number of times - but I am not even sure it's doing that. Thanks for everyone's help, I have to sleep on this one I think. – Kevin W. Oct 05 '16 at 05:07
  • Think about what will happen to `gambleName` if you enter your full name, which is 16 characters. – Karsten Koop Oct 05 '16 at 07:21

2 Answers2

2

C that compiles fine without any warnings, as yours does, can still contain many memory problems that will cause bizarre and difficult to reproduce behavior. To find them, use a memory checker such as Valgrind.

Running your game with Valgrind reveals a problem...

...
Bets in game [27] = 28
==27110== Conditional jump or move depends on uninitialised value(s)
==27110==    at 0x1001F08A7: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1002166C0: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x100216952: __xvprintf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EC381: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EA21B: printf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x100000CAB: main (test.c:75)
==27110== 
==27110== Conditional jump or move depends on uninitialised value(s)
==27110==    at 0x1001F0E90: __ultoa (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EE364: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1002166C0: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x100216952: __xvprintf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EC381: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EA21B: printf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x100000CAB: main (test.c:75)
==27110== 
==27110== Syscall param write(buf) points to uninitialised byte(s)
==27110==    at 0x1002F7612: write$NOCANCEL (in /usr/lib/system/libsystem_kernel.dylib)
==27110==    by 0x1001EB1F9: _swrite (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001E3724: __sflush (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x100216966: __xvprintf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EC381: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x1001EA21B: printf (in /usr/lib/system/libsystem_c.dylib)
==27110==    by 0x100000CAB: main (test.c:75)
==27110==  Address 0x104800e14 is on thread 1's stack
==27110==  in frame #3, created by __xvprintf (???:)
==27110== 
Bets in game [28] = 0
...

Those are all stack traces. You generally read them from the bottom up to figure out where the source of the problem is. Valgrind has detected that you're passing an uninitialized value to printf on line 75.

test.c lines 74-76 are this:

for (game = 0; game < 50; game++) {
    printf("Bets in game [%d] = %d\n",game,betArray[game]); 
}

The problem is betArray. Looking at where it's initialized reveals the problem.

int betArray[1000];

This only allocates the memory, but it doesn't initialize it. betArray contains whatever garbage happened to be in that memory location. Thus your wonky numbers. You have to initialize it to something. The following for loop is supposed to set every element, but it doesn't.

for (game=0 ; game<1000 ; game++) {
    if (availableFunds>0 && availableFunds<goalFunds) { 
        ...blah blah blah...
        betArray[game] = bet;
    }   
    else if (availableFunds == 0 || availableFunds >= goalFunds) {
    }
}

But your for loop only sometimes sets betArray initialized. Other times it doesn't. It looks like you intended to fill in some more code, but decided to try things out. So you were left with a partially initialized betArray.

The simple solution is to initialize betArray immediately upon declaring it.

int betArray[1000] = {0};

This will initialize all elements to 0 and fix your wonky numbers problem.

Schwern
  • 153,029
  • 25
  • 195
  • 336
1

As was mentioned in the comments to your question, the problem at the moment seems to be integer division. In C, when you divide two integers you get, for example, 489 / 1000 = 0, but 489 % 1000 = 489 gives the remainder. When operating on integer types in C, / is integer division, and % is the modulus operator. You attempt to divide two ints here:

int winRatio = wins / game;

So winRatio will be 0 unless the player wins every game (or more games than are played!) You should change winRatio to a float, and you probably want winPercent to be a float:

float winRatio = (1.0 * wins) / game;
float winPercent = winRatio * 100;

In the first statement, while wins and game are ints, the expression (1.0 * wins) is a float, because of the multiplication with the float literal 1.0. For the same reason, the entire expression is of type float, and this value can be assigned to the float variable winRatio. This is called "type coercion" or "type conversion". Since winRatio is a float, the value of the expression winRatio * 100 is also a float, and can be assigned to float winPercent.

You don't calculate betAverage, and I am not really sure what you are calculating here. Finally, as was also pointed out in the comments, the bet is incremented with each game, but the payout is $1 for each game. You probably want to keep the bet at $1 per game, but maybe you want to increase the payout to keep pace with the increasing bets?

ad absurdum
  • 19,498
  • 5
  • 37
  • 60
  • This helped a lot, thank you. I thought that the code `bet+=1;` inside my first `if (availableFunds>0 && availableFunds – Kevin W. Oct 05 '16 at 14:20