When running the following code to calculate the probability of no pair, one pair, two pair, three of a kind, full house and four of a kind in a random seven-card poker hand, Visual Studio returns the warning "Run-Time Check Failure #2 - Stack around the variable 'hand_counts' was corrupted" on the last line. However, the program can still output the results by clicking "Continue". I have checked the program for out-of-bounds array accesses, but have not found any. What could be causing the error?
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
typedef enum suit
{
spades,
hearts,
diamonds,
clubs
} suit;
typedef struct card
{
suit suit;
short pip;
} card;
void deck_shuffle(card deck[52])
{
srand(time(NULL));
for (int i = 0; i < 52; i++)
{
const int j = rand() % 52;
const card temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
int possibility(card hand[7])
{
int pair_type = 0;
int count = 0;
for (int i = 0; i < 6; i++)
{
for (int j = i + 1; j < 7; j++)
{
if (hand[i].pip == hand[j].pip)
{
count++;
}
}
}
// check for no pairs.
if (count == 0)
{
pair_type = 1;
}
// check for one pair.
if (count == 1)
{
pair_type = 2;
}
// check for two pair.
if (count == 2)
{
pair_type = 3;
}
// check for three of a kind.
if (count == 3)
{
pair_type = 4;
}
// check for full house.
int rank1 = 0;
int rank2 = 0;
int temp1 = hand[0].pip;
int temp2;
int count1 = 0;
int count2 = 0;
for (int i = 0; i < 6; i++)
{
for (int j = i + 1; j < 7; j++)
{
if (hand[i].pip == hand[j].pip)
{
rank1 = hand[j].pip;
if (temp1 == rank1)
{
count1++;
temp1 = rank1;
}
else
{
temp2 = rank2;
rank2 = hand[j].pip;
if (temp2 == rank2)
{
count2++;
}
}
}
}
}
count2 += 1;
if ((count1 == 3 && count2 == 1) || (count1 == 3 && count2 == 3))
{
pair_type = 5;
}
// check for four of a kind.
if (count1 == 6 || count2 == 6)
{
pair_type = 6;
}
return pair_type;
}
int main(void)
{
card deck[52];
for (int i = 0; i < 52; i++)
{
deck[i].suit = i / 13;
deck[i].pip = i % 13;
}
int hand_counts[6] = { 0 };
for (int i = 0; i < 1000000; i++)
{
deck_shuffle(deck);
card hand[7];
for (int j = 0; j < 7; j++)
{
hand[j] = deck[j];
}
int hand_type = possibility(hand);
hand_counts[hand_type - 1]++;
}
for (int i = 0; i < 6; i++)
{
printf("The probability of hand type %d: is %f\n", i + 1, (double)hand_counts[i] / 1000000);
}
return 0;
}
I tried running the same code in other IDEs, and there were no warnings. The results were also calculated faster than in Visual Studio. I am not sure if there is an error in my source code, or if it is a problem with Visual Studio itself.
Sorry, but the multiple loops and variables toward the end of possibility()
are somewhat difficult to follow. I stripped things down somewhat and put in a particular test case; 4 aces:
int possibility( int hand[7]) {
int pair_type = 0;
/* ... */
for (int k = 0; k < 7; k++) printf( "%d ", hand[k] );
int rank1 = 0;
int rank2 = 0;
int temp1 = hand[0];
int temp2;
int count1 = 0;
int count2 = 0;
for (int i = 0; i < 6; i++) {
for (int j = i + 1; j < 7; j++) {
if (hand[i] == hand[j]) {
rank1 = hand[j];
if (temp1 == rank1) {
count1++;
temp1 = rank1;
} else {
temp2 = rank2;
rank2 = hand[j];
if (temp2 == rank2)
count2++;
}
}
}
}
count2 += 1;
printf( "\nSuspicion: count1 = %d count2 = %d\n", count1, count2 );
/* ... */
return pair_type;
}
int main(void) {
int hand[7] = { 12, 0, 0, 0, 0, 1, 2 };
printf("hand type %d\n", possibility(hand) );
return 0;
}
Result:
12 0 0 0 0 1 2
Suspicion: count1 = 0 count2 = 7 // <<<<
hand type 0
Then:
int hand_type = possibility(hand);
hand_counts[hand_type - 1]++;
Will increment the location hand_counts[ 0 - 1 ]
... Definitely a No-No.
You need to go back to that nested for()
loop and figure out how to avoid double counting. 4-of-a-kind can occur in any locations. There's too much double counting happening in your loops.
Suggest you look into "histogram" tallying of the cards (int cnt[13] = {0};
would be a start. Then a single pass over the hand will give you the tallies you need.
"or if it is a problem with Visual Studio itself." While that's always a possibility, it's a poor craftsman who starts by blaming his/her tools.
Y'know... If you'd not tried to use an array dimensioned for precisely 6-and-only-6 "types", then gone on to subtract 1 to use 0-based indexing, you might have caught this yourself...
int hand_counts[ 27 ] = { 0 }; // why not?
/* ... */
for (int i = 0; i < sizeof hand_counts/sizeof hand_counts[0]; i++)
{
printf("The probability of hand type %d: is %f\n", i, (double)hand_counts[i] / 1000000);
}
(Just noticed you "add 1" in your print statement! Too much "clever" overflows to become "dumb"...)
Overtime:
Intrigued, here's a stripped down version that may be suitable for elaborating into something bigger:
void deck_shuffle( int deck[] ) {
for( int i = 0; i < 52; i++ ) {
const int j = rand() % 52;
const int temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
int cmp( const void *a, const void *b ) {
return *(int*)b - *(int*)a; // descending sqnc
}
enum { nada, four, three, two, twoPair, fullhouse, nTallies };
int possibility( int hand[] ) {
int cnt[13] = { 0 };
for( int i = 0; i < 7; i++ ) {
printf( "%c ", "A234567890JQK"[ hand[i] ] );
++cnt[ hand[i] ];
}
// qsort( cnt, sizeof cnt[0], 13, cmp ); // Wrong!
qsort( cnt, 13, sizeof cnt[0], cmp ); // descending
if( cnt[0] == 4 ) return four;
if( cnt[0] == 3 )
if( cnt[1] == 2 )
return fullhouse;
else
return three;
if( cnt[0] == 2 )
if( cnt[1] == 2 )
return twoPair;
else
return two;
return nada;
}
int main( void ) {
srand(time(NULL));
int deck[52];
for (int i = 0; i < 52; i++)
deck[i] = i % 13;
int hand_counts[ nTallies ] = { 0 };
for( int r = 0; r < 100; r++ ) {
deck_shuffle( deck );
int p = possibility( deck ); // look at top 7 cards
printf( " ... %2d\n", p );
++hand_counts[ p ];
}
for( int out = 0; out < nTallies; out++ )
printf("The probability of hand type %d: is %f\n", out, (double)hand_counts[out] / 100);
return 0;
}