【问题标题】:How to generate unique numbers in range 0001 - 2000 with rand() in C如何在 C 中使用 rand() 生成 0001 - 2000 范围内的唯一数字
【发布时间】:2018-03-11 13:30:35
【问题描述】:

我正在尝试生成包含以下两项的数据集:(i) 包含随机生成的值 (0001 到 2000) 的学生 ID,以及 (ii) 与学生 ID 相对应的年龄 (18 到 30)。这些随机值保存在它们各自的 array[1000] 中,您可以在 Code

中看到

我遇到了 rand() 的问题,我已指定我想为学生 ID 生成从 1 到 2000 的随机数,但我遇到了我认为是整数溢出的问题。我认为问题可能来自以下之一:

  • 我的函数是 int 类型的,我可能需要尝试其他类型?
  • 我实现 rand() % 声明的方式有问题
  • 其他一些我不知道的问题

您可以在 Output

中看到我遇到的问题

代码:

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

int createDataSet(void)
{
    srand(time(NULL));             // generates the random numbers

    int i = 0, x, p, count;

    char arrayId[1000];      // array that holds the ID's of 1000 students
    char arrayAges[1000];        // array that holds the ages of 1000 students

    for (count = 0; count < 1000; count++) // Init the "age" and "id" arrays
    {
        arrayId[count] = rand() % 2000 + 1;              // ID range 0001 - 2000
        arrayAges[count] = rand() % (30 + 1 - 18) + 18;   // Age range 18 - 30
    }

    while(i<1000){
        int r=rand() % (2000 + 1 - 0001) + 0001;

        for (x = 0; x < i; x++)
        {
            if(arrayId[x]==r){
                break;
            }
        }
        if(x==i){
            arrayId[i++]=r;
        }
    }

    for (p = 0; p < 1000; p++)
    {
        printf("ID Number: %d       Age: %d\n", arrayId[p], arrayAges[p]);
    }
    return 0;
}

输出:

ID Number: 115       Age: 28
ID Number: 104       Age: 21
ID Number: -113       Age: 25
ID Number: -3       Age: 18
ID Number: -41       Age: 20
ID Number: -94       Age: 28
ID Number: -4       Age: 19
ID Number: 4       Age: 28
ID Number: -112       Age: 23
ID Number: 33       Age: 20
ID Number: -119       Age: 30
ID Number: 12       Age: 23
ID Number: -96       Age: 27
ID Number: -88       Age: 30
ID Number: -105       Age: 20

我的目标是尝试获取数组中的值,如 ID 号所示:显示 1 到 2000 之间的随机值并且是无符号类型。任何帮助表示赞赏。感谢您的宝贵时间!

【问题讨论】:

标签: c random


【解决方案1】:

虽然对于尝试将 char 范围之外的整数值分配给 char 变量的初始问题,您已经有了一个很好的答案,但仍有大量小问题尚未解决。

首先,不要在代码中使用幻数。如果您需要常量,可以使用#define 或使用全局enum 来定义它们,例如

/* if you need a constants, define them */
enum { MINA = 18, MAXA = 30, MAXS = 1000, MAXID = 2000 };

(其中MINAMINIMUMAGE 的缩写,MAXSMAXIMUMSTUDENTS 的缩写等)

这样,如果您需要更改范围或限制,您可以在代码顶部有一个简单的位置来进行更改,而不必挑选所有循环限制和变量声明。

接下来,createDataset 中的 return 0; 毫无意义。如果你没有要返回的值,并且你没有在函数中做任何需要返回来衡量成功/失败的事情,那么将你的函数声明为void。同样,该函数可能会生成一个数据集并将值打印到stdout,但如果您的代码的其余部分需要该数据集,则无法使用它。为什么?您的所有数组 char arrayId[].. 都声明为函数的本地,并且当函数返回时,它们存储的内存将被销毁(释放以供重用)。您可能需要重构代码以在 main() 中声明数组并将数组以及元素数量传递给您的函数以进行初始化。

您可以在函数中使用此临时存储来防止重复 ID。您可以简单地声明一个长度为MAXID 的字符数组(例如char filled[MAXID] = "";),初始化为全零,并在生成每个相应的ID 时,将该索引处的值设置为1(或某个非零值)。这使得重复检查成为if (filled[r]) { /* regenerate ID */ }的简单测试

当您考虑重构代码时,您希望将每个函数的功能分成逻辑单元。您的组合生成 ID/年龄和输出可能适合您的直接需求,但请考虑将生成函数和输出分离为单独的函数。

虽然不是错误,但 C 的标准编码风格避免使用 camelCaseMixedCase 变量名,以支持所有小写,同时保留大写 用于宏和常量的名称。这是一个风格问题——所以这完全取决于你,但不遵循它可能会在某些圈子中导致错误的第一印象。

将这些部分放在一起,您可以将当前函数重构为单独的生成和打印函数,如下所示:

void createdataset (unsigned short *ids, char *ages, int count)
{
    char filled[MAXID] = {0};           /* array preventing duplicates */

    for (count = 0; count < MAXS; count++)  /* for each student */
    {
        /* generate an ID */
        unsigned short r = (unsigned short)(rand() % MAXID + 1);
        while (filled[r])   /* while a duplicate, regenerate */
            r = (unsigned short)(rand() % MAXID + 1);
        filled[r] = 1;      /* set filled[index] to 1 */
        ids[count] = r;     /* assign ID to student */
        ages[count] = (char)(rand() % (MAXA - MINA + 1) + MINA);
    }
}

void prndataset (unsigned short *ids, char *ages, int count)
{
    int i = 0;

    for (i = 0; i < count; i++)
        printf ("ID Number: %4hu       Age: %2hhd\n", ids[i], ages[i]);
}

注意: srand 只能在您的代码中调用一次。因此,如果您可能生成多个数据集,则应将其放在 main() 中以确保仅调用一次。

当您开发的代码必须满足特殊标准时,例如 ID 介于 1-2000 和年龄介于 18-30 之间时,请考虑编写一个简单的验证检查,以验证您的所有值都在范围内。例如,您可以在此处执行以下操作:

int validateset (unsigned short *ids, char *ages, int count)
{
    int i = 0, err = 0;

    for (i = 0; i < count; i++) {
        if (ids[i] < 1 || ids[i] > MAXID) {
            fprintf (stderr, "error: arrayid[%d] : %hu out of range.\n", 
                    i, ids[i]);
            err = 1;
        }
        if (ages[i] < MINA || ages[i] > MAXA) {
            fprintf (stderr, "error: arrayages[%d] : %hhd out of range.\n", 
                    i, ages[i]);
            err = 1;
        }
    }

    return err;
}

(成功时将返回0,如果在输出任何违规值后有任何值超出范围,则返回1

此外,当您打印值时,请确保您的格式说明符与您输出的值的类型相匹配。虽然提升规则将使用%d%u 格式说明符处理将较小的值(例如short)转换为int,但如果您的编译器支持h 修饰符,则应使用它们来指定正确的输出大小(例如,打印unsigned short,使用%hu 或打印unsigned char,使用%hhu)。

将所有部分放在一个简短的示例中,您可以重构代码并添加类似于以下内容的验证检查:

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

/* if you need a constants, define them */
enum { MINA = 18, MAXA = 30, MAXS = 1000, MAXID = 2000 };

void createdataset (unsigned short *ids, char *ages, int count)
{
    char filled[MAXID] = {0};           /* array preventing duplicates */

    for (count = 0; count < MAXS; count++)  /* for each student */
    {
        /* generate an ID */
        unsigned short r = (unsigned short)(rand() % MAXID + 1);
        while (filled[r])   /* while a duplicate, regenerate */
            r = (unsigned short)(rand() % MAXID + 1);
        filled[r] = 1;      /* set filled[index] to 1 */
        ids[count] = r;     /* assign ID to student */
        ages[count] = (char)(rand() % (MAXA - MINA + 1) + MINA);
    }
}

void prndataset (unsigned short *ids, char *ages, int count)
{
    int i = 0;

    for (i = 0; i < count; i++)
        printf ("ID Number: %4hu       Age: %2hhd\n", ids[i], ages[i]);
}

int validateset (unsigned short *ids, char *ages, int count)
{
    int i = 0, err = 0;

    for (i = 0; i < count; i++) {
        if (ids[i] < 1 || ids[i] > MAXID) {
            fprintf (stderr, "error: arrayid[%d] : %hu out of range.\n", 
                    i, ids[i]);
            err = 1;
        }
        if (ages[i] < MINA || ages[i] > MAXA) {
            fprintf (stderr, "error: arrayages[%d] : %hhd out of range.\n", 
                    i, ages[i]);
            err = 1;
        }
    }

    return err;
}

int main (void) {

    unsigned short arrayid[MAXS] = {0}; /* size your type to your needed */
    char arrayages[MAXS] = {0};         /* range and enforce the range */

    srand(time(NULL));                  /* initialize random number seed */

    createdataset (arrayid, arrayages, MAXS);   /* initialize dataset */
    if (validateset (arrayid, arrayages, MAXS)) /* validate dataset */
        exit (EXIT_FAILURE);
    prndataset (arrayid, arrayages, MAXS);      /* output dataset */

    return 0;
}

(通过添加验证检查,您可以确信如果您的代码运行时没有显示错误,则数据集已正确生成)

使用/输出示例

$ ./bin/createdataset > dat/dataset1.txt

$ head -n 10 dat/dataset1.txt; echo "..."; tail -n 10 dat/dataset1.txt
ID Number: 1049       Age: 29
ID Number:  743       Age: 21
ID Number:  915       Age: 22
ID Number: 1539       Age: 19
ID Number:  793       Age: 18
ID Number: 1166       Age: 21
ID Number:  372       Age: 28
ID Number: 1763       Age: 19
ID Number:  782       Age: 20
ID Number: 1490       Age: 30
...
ID Number:  186       Age: 30
ID Number: 1389       Age: 23
ID Number: 1630       Age: 22
ID Number:  432       Age: 27
ID Number:  240       Age: 24
ID Number:  152       Age: 25
ID Number: 1598       Age: 22
ID Number: 1408       Age: 24
ID Number:  834       Age: 24
ID Number: 1699       Age: 25

虽然您的主要问题是在char 问题中存储int,但还有许多其他更微妙的问题需要考虑。如果您有任何其他问题,请查看并告诉我。

【讨论】:

    【解决方案2】:

    arrayId 声明为无符号短数组,因为unsigned char arrayId[index] 不会在每个arrayId[index] 中发挥最大作用,您只能存储255,但您希望最多存储2000

    unsigned short arrayId[1000]; /* try to store negative number, cyclic flow will happen  */
    
    unsigned char arrayAges[1000];
    

    【讨论】:

    • 嗯...int r=rand() % (2000 + 1 - 1) + 1; 不能给出负数。范围是1-2000?也许您的意思是如果分配给char
    【解决方案3】:

    使用此代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
        srand(time(NULL));             
    
        int i = 0, x, p, count;
    
        unsigned arrayId[1000];   //You Can USE :unsigned int or unsigned short 
        char arrayAges[1000];     
    
        for (count = 0; count < 1000; count++) 
        {
            arrayId[count] = rand() % 2000 + 1;             
            arrayAges[count] = rand() % (30 + 1 - 18) + 18;  
    

    }

        for (p = 0; p < 1000; p++)
        {
            printf("%d.ID Number: %ld       Age: %d\n",p+1, arrayId[p], arrayAges[p]);
        }
        return 0;
    }
    

    输出:

    1.ID Number: 1467       Age: 27
    2.ID Number: 1316       Age: 21
    3.ID Number: 1213       Age: 19
    4.ID Number: 171       Age: 29
    5.ID Number: 661       Age: 21
    6.ID Number: 297       Age: 27
    7.ID Number: 853       Age: 23
    8.ID Number: 67       Age: 29
    9.ID Number: 500       Age: 20
    10.ID Number: 274       Age: 24
    11.ID Number: 821       Age: 25
    12.ID Number: 355       Age: 19
    13.ID Number: 1797       Age: 23
    14.ID Number: 1036       Age: 30
    15.ID Number: 1637       Age: 18
    16.ID Number: 385       Age: 22
    17.ID Number: 1574       Age: 24
    18.ID Number: 1305       Age: 20
    19.ID Number: 1658       Age: 24
    20.ID Number: 794       Age: 29
    21.ID Number: 1758       Age: 24
    22.ID Number: 1239       Age: 27
    23.ID Number: 989       Age: 30
    24.ID Number: 1449       Age: 22
    25.ID Number: 1390       Age: 26
    26.ID Number: 1731       Age: 25
    27.ID Number: 1465       Age: 26
    28.ID Number: 792       Age: 20
    29.ID Number: 1974       Age: 24
    30.ID Number: 1674       Age: 23
    31.ID Number: 533       Age: 19
    32.ID Number: 1078       Age: 28
    33.ID Number: 571       Age: 25
    34.ID Number: 48       Age: 20
    35.ID Number: 115       Age: 19
    36.ID Number: 345       Age: 24
    .
    .
    .
    
    979.ID Number: 35       Age: 30
    980.ID Number: 965       Age: 29
    981.ID Number: 457       Age: 26
    982.ID Number: 615       Age: 24
    983.ID Number: 667       Age: 26
    984.ID Number: 1381       Age: 19
    985.ID Number: 1032       Age: 20
    986.ID Number: 534       Age: 26
    987.ID Number: 1372       Age: 27
    988.ID Number: 1299       Age: 24
    989.ID Number: 1463       Age: 24
    990.ID Number: 880       Age: 18
    991.ID Number: 1928       Age: 28
    992.ID Number: 867       Age: 23
    993.ID Number: 1580       Age: 29
    994.ID Number: 917       Age: 18
    995.ID Number: 237       Age: 28
    996.ID Number: 384       Age: 19
    997.ID Number: 356       Age: 20
    998.ID Number: 327       Age: 27
    999.ID Number: 1768       Age: 18
    1000.ID Number: 148       Age: 27
    
    Process returned 0 (0x0)   execution time : 1.832 s
    Press any key to continue.
    

    它也会帮助你

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
        srand(time(NULL));             // generates the random numbers
    
        int i = 0, x, p, count;
    
         int arrayId[1000];      // array that holds the ID's of 1000 students
        char arrayAges[1000];        // array that holds the ages of 1000 students
    
        for (count = 0; count < 1000; count++) // Init the "age" and "id" arrays
        {
            //arrayId[count] = rand() % 2000 + 1;              // ID range 0001 - 2000
            arrayId[count] =rand() % (2000 + 1 - 1) + 1;
            arrayAges[count] = rand() % (30 + 1 - 18) + 18;   // Age range 18 - 30
        }
    
        while(i<1000){
            int r=rand() % (2000 + 1 - 0001) + 0001;
    
            for (x = 0; x < i; x++)
            {
                if(arrayId[x]==r){
                    break;
                }
            }
            if(x==i){
                arrayId[i++]=r;
            }
        }
    
        for (p = 0; p < 1000; p++)
        {
            printf("%d.ID Number: %ld       Age: %d\n",p+1, arrayId[p], arrayAges[p]);
        }
        return 0;
    }
    

    【讨论】:

    • “使用此代码”“试试这个” 不是有用的答案。以清晰易懂的语言努力说明原始代码中的错误之处,以及为什么您做出了您在提供更正时所做的选择。这将使您的回答不仅在此处有所帮助,而且对其他遇到类似问题的人也有所帮助。
    猜你喜欢
    • 2011-12-22
    • 2011-05-15
    • 2011-09-20
    • 2020-06-26
    • 2011-08-02
    • 2012-03-18
    • 2011-05-16
    • 2016-11-19
    • 2012-10-24
    相关资源
    最近更新 更多