提问人:PRACTICAL PIG 提问时间:10/23/2023 最后编辑:JabberwockyPRACTICAL PIG 更新时间:10/23/2023 访问量:73
如何调试运行时检查失败#2?
How to debug Run-Time Check Failure #2?
问:
运行以下代码以计算随机七张扑克牌中没有对、一对、两对、三对、满屋和四张的概率时,Visual Studio 在最后一行返回警告“运行时检查失败 #2 - 围绕变量”hand_counts“的堆栈已损坏”。但是,程序仍然可以通过单击“继续”来输出结果。我已经检查了程序是否存在越界数组访问,但没有找到任何访问。可能导致错误的原因是什么?
#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;
}
我尝试在其他 IDE 中运行相同的代码,但没有警告。结果的计算速度也比在 Visual Studio 中更快。我不确定我的源代码中是否存在错误,或者是否是 Visual Studio 本身的问题。
答:
对不起,但末尾的多个循环和变量有点难以理解。我稍微剥离了一些内容,并放入了一个特定的测试用例;4张王牌:possibility()
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;
}
结果:
12 0 0 0 0 1 2
Suspicion: count1 = 0 count2 = 7 // <<<<
hand type 0
然后:
int hand_type = possibility(hand);
hand_counts[hand_type - 1]++;
将增加位置...绝对是禁忌。hand_counts[ 0 - 1 ]
你需要回到那个嵌套循环,弄清楚如何避免重复计算。4-of-a-a-kind 可以发生在任何位置。循环中发生了太多的重复计数。for()
建议你研究一下卡片的“直方图”计数(这将是一个开始。然后,在手上传递一次,就会得到你需要的计数。int cnt[13] = {0};
"或者如果这是 Visual Studio 本身的问题。虽然这总是有可能的,但一个可怜的工匠一开始就责怪他/她的工具。
你知道的...如果你没有尝试使用一个精确为 6 和只有 6 个“类型”的数组,然后继续减去 1 以使用从 0 开始的索引,你自己可能已经发现了这一点......
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);
}
(刚刚注意到您在打印报表中“添加 1”!太多的“聪明”溢出而变得“愚蠢”......
加班:很感兴趣,这里有一个精简版本,可能适合详细说明成更大的内容:
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;
}
评论
:-)
qsort()
:-)
qsort()
评论
hand_counts
possibility()
返回等于 0 到 6,但随后您这样做了,因此在 0 时,您将覆盖来自其他地方的内存,这是未定义的行为。另外,在这里搜索或谷歌搜索更简单但更彻底的洗牌算法。hand_type
hand_counts[hand_type - 1]++;