C语言中的for循环和数组

3

编辑:非常感谢大家的评论!在你们的指导下,我成功修复了胜率和数组数字出现异常的问题。但是,我还没有修复赢或输需要的平均投注次数。我已经更新了我的代码,如下所示。

开始原始帖子:

预先感谢任何阅读此帖并提供建议的人!

所以,我正在为编程课程做一个典型的赌博游戏,直到你赢了或输光为止。代码运行良好,但当我添加正反面部分时,存储投注次数的数组就会出现问题。当我用注释隐藏实际的抛硬币部分时,数组就能正常工作。当我运行它与抛硬币时,betArray存储的数字就变得非常奇怪(负整数、十亿级整数)。

以下是目前的代码:

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

抱歉代码有些混乱,我添加了一些内容并想要发送最新版本。谢谢!

1
你用过调试器吗? - kaylum
1
if (availableFunds>0 && availableFunds<goalFunds) { 块中,你从未对 betArray[game] 进行任何赋值,因此你的大部分数组都是无用的。 - M.M
@KevinWestermann 这就像一个木匠不知道锤子是什么一样 :-) 我不使用OSX,所以无法推荐任何东西,但你的朋友谷歌可能会知道,所以去问吧。 - kaylum
@kaylum 我把 betArray[game](即从 else if 中删除)移到了 if (availableFunds>0 && availableFunds<goalFunds) { 块中,根据 M.M 的建议。这是完整代码的链接:https://repl.it/Do5j/2 - Kevin W.
1
请注意,除非投注者非常幸运并赢得了每一场比赛,否则int winRatio = wins/game;将为零。 这些值都是整数。 您需要将winsgame中的至少一个强制转换为浮点类型,并且winRatio也应该是浮点类型。 您可能需要在else if (availableFunds == 0 || availableFunds >= goalFunds) { }中使用break;,我认为您应该省略if条件; 它只是与之前“如果可以赌博”的条件相比的“否则”子句。 - Jonathan Leffler
显示剩余10条评论
2个回答

2

即使像您的代码一样没有任何警告编译通过,它仍然可能包含许多内存问题,这些问题会导致奇怪且难以复现的行为。为了找到它们,请使用诸如Valgrind之类的内存检查器。

使用Valgrind运行您的游戏会显示出一个问题...

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

这些都是堆栈跟踪。通常从下往上阅读,以找出问题的源头。Valgrind检测到您在第75行向printf传递了一个未初始化的值。

test.c的74-76行是这样的:

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

问题出在betArray上。查看它的初始化位置可以发现问题。
int betArray[1000];

这只是分配了内存,但没有初始化它。 betArray 包含该内存位置中的任何垃圾数据。因此你得到了奇怪的数字。你需要将其初始化为某些值。以下的 for 循环应该设置每个元素,但实际上并没有。

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

但是你的for循环有时只初始化了betArray。其他时候它没有。看起来你想填写更多的代码,但决定先试试。所以你留下了部分初始化的betArray
简单的解决方法是在声明betArray时立即初始化它。
int betArray[1000] = {0};

这将把所有元素初始化为0,并解决您的问题。与此同时,保留HTML标签,请参见这里

1
正如在您的问题评论中提到的那样,目前的问题似乎是整数除法。在C语言中,当您将两个整数相除时,例如,489 / 1000 = 0,但是489%1000 = 489会给出余数。在C语言中操作整数类型时,/是整数除法,%是模运算符。您尝试将两个int相除:
int winRatio = wins / game;

所以,除非玩家赢得每一场比赛(或比比赛多!),否则winRatio将为0。您应该将winRatio更改为float,并且您可能希望winPercent也是一个float
float winRatio = (1.0 * wins) / game;
float winPercent = winRatio * 100;

在第一条语句中,虽然和是整数,但表达式<(1.0 * wins)>是浮点数,因为乘以浮点字面值<1.0>。出于同样的原因,整个表达式的类型是<浮点数>,并且可以将此值分配给<浮点数>变量。这称为“类型强制转换”。由于是<浮点数>,表达式的值也是<浮点数>,可以分配给<浮点数>变量。
您没有计算,我不确定您在这里计算什么。最后,正如评论中指出的那样,随着每场比赛增加,但每场比赛的支付额为$1。您可能想保持每场比赛的赌注为$1,但也许您想增加支付以跟上增加的赌注?

这非常有帮助,谢谢。我以为在我的第一个 if (availableFunds>0 && availableFunds<goalFunds) { 中的代码 bet+=1; 会在每次下注时增加1个赌注,直到它用完所有的钱,然后在 if/else 语句之外的 betArray[game+1] = bet; 会将该特定游戏循环中进行的下注数量保存到数组中,但我想不是这样? - Kevin W.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接