【问题标题】:Why do while loop doesn't work correctly?为什么while循环不能正常工作?
【发布时间】:2019-07-09 17:50:14
【问题描述】:

我编写了一些 C 代码来生成一个随机字符并检查该字符是否存在于数组中。如果存在,我想重新生成一个新字符。我使用标志作为指示符并使用do/while 循环来检查此标志,但不幸的是,代码无法按预期工作,并且我得到了一个已存在于数组中的字符。

我需要你的帮助来理解和解决这个问题。

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

int main() {
    char c;
    int num;
    int flag = -1;
    char temp[5] = { '3', '2', '5', '9', '1' };
    srand(time(NULL));
    do {
        num = rand() % 5;
        c = num;
        for (int i = 0; i < 5; i++) {
            if (temp[i] == c) {
                flag = 0;
                break;
            } else {
                flag = 1;
            }
        }
    } while (0 == flag);

    printf("number is : %d\n", c);
    return 0;
}

【问题讨论】:

  • 5 是一个数字。 '5' 是一个字符。两者的区别是'0'。 IE。 '5' == 5 + '0'
  • 那么,我应该怎么做是将for循环中的条件修改为c if(temp[i] == c+'0' ) 或什么? :D 如果你给我一个例子,我会很感激 :)
  • ^ 这是解决方案之一。
  • @Ahmedhamdy:您可以通过点击分数下方的灰色复选标记来接受答案

标签: c loops random srand


【解决方案1】:

有多个问题:

  • 5'5' 不是一回事。 '5' 是一个字符值,而 5 是一个数值。字符值取决于字符编码,很可能是当前系统上的 ASCII,其中'5' 的数值为53 (0x35)。
  • C 标准保证'0''9' 的字符数字是连续的,因此您可以通过将'0' 添加到随机数来绘制字符数字。
  • 您应该在for 循环之前将flag 设置为1,并且只有在找到字符时才将其清除。
  • 请注意,您在01234 之间绘制一个字符。您可能希望包含所有字符数字?

这是修改后的版本:

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

int main() {
    char temp[] = { '3', '2', '5', '9', '1' };
    const size_t temp_len = sizeof(temp) / sizeof(temp[0]);
    char c;
    int flag;

    srand(time(NULL));

    do {
        // select a random digit character 
        c = '0' + rand() % 10;
        flag = 1;
        for (size_t i = 0; i < temp_len; i++) {
            if (temp[i] == c) {
                flag = 0;
                break;
            }
        }
    } while (flag == 0);

    printf("character is: %c\n", c);
    return 0;
}

请注意,您可以使用memchr() 来搜索字符,并避免使用容易引起混淆的do/while 循环。这是一个更简单的选择:

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

int main() {
    char temp[] = { '3', '2', '5', '9', '1' };
    char c;

    srand(time(NULL));

    for (;;) {
        // select a random digit character 
        c = '0' + rand() % 10;
        if (!memchr(temp, c, sizeof temp))
            break;
    }
    printf("character is: %c\n", c);
    return 0;
}

【讨论】:

  • 对第二种解决方案的建议:使用sizeof(temp) 而不是常量5,尤其是因为您建议更改temp 的大小。要求维护者弄清楚程序中的哪些常量应该是temp 的大小或temp 的一半大小,以及其他含义,这只是在询问错误。甚至sizeof(temp)/sizeof(temp[0]),如果可能的话,算法可以更改为使用宽字符。如果输入太多,#define NDIGITS (sizeof(temp)/sizeof(temp[0])) 之类的。
  • 看起来好多了,虽然作为文体选择,我从不写for (;;)。我更喜欢while (true)。在这种情况下,我个人会写do {/*...*/} while (memchr(temp, c, sizeof temp));
  • @Davislor:你的替代方案很好,但我强烈反对do/while:这种结构经常被新手程序员和有时精明的程序员滥用。我也不喜欢while (true),原因有两个:true 是标准的最新成员,for (;;) 是引人注目的。
  • @Davislor:既然我们在吹毛求疵,我肯定更喜欢countof(temp)const size_t ndigits = sizeof(temp) / sizeof(temp[0]) 而不是#define NDIGITS (sizeof(temp)/sizeof(temp[0]))
  • 我不认为那些替代品是标准 C11?但是,是的,在 C++ 中,我肯定会为ndigits 编写一个constexpr 表达式。我通常使用有符号数学和ptrdiff_t 作为我的索引以避免臭名昭著的3U &lt; -1 之类的错误。
猜你喜欢
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
  • 2015-05-14
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 2012-11-04
  • 2022-01-06
相关资源
最近更新 更多