【问题标题】:Random numbers in C aren't randomC中的随机数不是随机的
【发布时间】:2015-03-13 19:24:27
【问题描述】:

这是我的程序的代码。它应该从用户那里获取两个数字,然后使用 rand 函数生成随机数。 但是当我编译它时,数字不是随机的。

我也用java写过这个,而且效果很好。

C 版:

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

int cmpfunc();

int main()
{
   puts("How many numbers do you want to generate?");
   int n;
   scanf("%d", &n);
   int numbers[n];

   puts("What should be the largest number possible?");
   int m, i;
   scanf("%d", &m);
   int result[m];

   for(i=0;i<m;i++)
       numbers[i] = i + 1;

       srand(time(NULL));
   for(i=0;i<n;i++)
   {
       int r = rand() % m;

       result[i] = numbers[r];
       numbers[r] = numbers[m - 1];
       m--;

   }

   qsort(result, n, sizeof(int), cmpfunc); //sorting the result array

   for(i=0;i<n;i++)
   {
       printf("%d\n", result[i]);
   }

    getch();
    return 0;
}

int cmpfunc (const void * a, const void * b)
{
   return ( *(int*)a - *(int*)b );
}

编辑:srand 在循环中,人们说它不应该被多次调用。所以我把它拿出来了,但这没有用。

Java 版本:

import java.util.*;

public class RandomNumberGenerator {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);

        System.out.println("How many numbers do you want to generate?");
        int n = in.nextInt();

        System.out.println("What should be the largest number possible?");
        int m = in.nextInt();

        int numbers[] = new int[m];
        for(int i=0;i<numbers.length;i++)
            numbers[i] = i + 1;

        int result[] = new int[n];
        for(int i=0;i<result.length;i++)
        {
            // make a random index between 0 and n - 1
            int r = (int) (Math.random() * m );

            result[i] = numbers[r];
            // move the last element into the random location
            numbers[r] = numbers[m - 1];
            m--;
        }

        System.out.println("Do you want the result to be sorted? (1 for Yes, others for No)");
        int ans = in.nextInt();

        if(ans==1)
            Arrays.sort(result);

          System.out.println("Result:");
          for (int r : result)
             System.out.println(r);

          pressAnyKeyToContinue();

    }

    private static void pressAnyKeyToContinue()
     { 
            System.out.println("Press Enter to continue.");
            try
            {
                System.in.read();
            }  
            catch(Exception e)
            {}
     }

}

编辑 2:

c 输出:(不是随机的,排序的)

java 输出:(随机、排序)

编辑 3:

正如我在 cmets 中所述的值是: n= 55 m= 9808

我也在使用代码块,所以头文件并不是一个真正的问题。它们由代码块自动加载。

编辑 4:

人们的建议给我留下了深刻的印象。 qsort 在生成随机数时不会改变任何事情。它只是对数组进行排序。所以即使我删除它,它也不会改变任何东西。

在随机数数组中,我们期望任何两个相邻元素之间的差异也是随机的。此属性在排序下保留。我对 C 和 Java 中的随机数进行排序以检查此属性。如您所见,在 C 代码中,相邻元素之间的差异都是相同的。这让我相信 C 代码不会生成随机数,但 Java 代码会。

编辑 5:

我确信java和c之间的算法应该没有区别。

编辑 6:

对不起,我不是专业人士。我只是想制作我拥有的 Java 程序的 C 版本。一个固定的代码将不胜感激。

****编辑最终结果:** 终于让它工作了。分别存储 n 和 m 的数组“数字”和“结果”应该存储 m 和 n。就这样。除此之外,我根据人们的建议更改了他们的名字。有些人告诉我用数组暗淡切换变量 m 和 n。事实并非如此。 这是任何有兴趣的人的固定代码:**

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

int cmpfunc();

int main()
{
   puts("How many numbers do you want to generate?");
   int  num_numbers;
   scanf("%d", &num_numbers);

   puts("What should be the largest number possible?");
   int num_maximum, i;
   scanf("%d", & num_maximum);


   int numbers[num_maximum];
   int result[num_numbers];

   for(i=0;i<num_maximum;i++) // making
       numbers[i] = i + 1;

       srand(time(NULL)); // seeding rand

   for(i=0;i<num_numbers;i++)
   {
       int r = rand() %  num_maximum; // generates random number between 0 and m-1

       result[i] = numbers[r]; //

       numbers[r] = numbers[ num_maximum - 1];
        num_maximum--;

   }

   puts("Do you want the result to be sorted?");
   int ans;
   scanf("%d", &ans);

   if (ans==1)
   qsort(result,  num_numbers, sizeof(int), cmpfunc); //sorting the result array

   for(i=0;i< num_numbers;i++)
   {
       printf("%d\n", result[i]);
   }

    getch();
    return 0;
}

int cmpfunc (const void * a, const void * b)
{
   return ( *(int*)a - *(int*)b );
}

【问题讨论】:

  • 可能想read this
  • posted code is missing #include getch() is found in the conio.h (on windows)...强烈建议使用 getchar() 而不是 getch()原因,conio.h 是特定于 Windows 的,因此不可移植
  • @VSG24:我有一个建议。您可以编辑您的问题以包含一个重现问题的最小示例吗?当前的错误、糟糕的代码似乎让人分心。顺便说一句,rand() 确实有效。
  • 如果qsort 无关紧要,您不应该将其包含在您的问题中。最好的问题是那些提供演示问题所需的最少代码量的问题。花更多的时间预先制定一个好问题将节省您的时间和精力。另外,考虑改写问题的标题。 C 正在生成随机数,是你对它们的使用是错误的。
  • 另一种想法是使用有意义的变量名称,例如num_numbersnum_result,这样您就不太可能将维度与数组不匹配

标签: c random


【解决方案1】:

srand(time(NULL)); 用于种子随机数生成器。它只需要调用一次。您需要将其移出 for 循环。

如果你每次都播种,你最终会得到rand()产生的相同数字。

另外,time() 的原型是 time.h

接下来,正如 @Blastfurnace 所述,您应该将 m 而不是 n 作为第二个参数传递给 qsort()

那么,

for(i=0;i<m;i++)
   numbers[i] = i + 1;

可能()通过为numbers 数组生成越界访问导致 UB。

【讨论】:

  • @VSG24 mn 的值是什么?
  • n=55,m=9808。什么号码都无所谓。结果不是随机的。
  • errm... srand()rand() 不在同一个循环中
  • 对不起,赞成而不是反对。希望给你+9而不是+-0
  • 请停止谈论 srand。它在循环内,他说要把它拿出来,我做到了,但没有帮助。所以 srand 不是问题。
【解决方案2】:

在您的 Java 代码中:

int numbers[] = new int[m];
int result[] = new int[n];

在您的 C 代码中:

int numbers[n];
int result[m];

数组的大小是相反的。当我将 C 代码的定义与您的 Java 代码的定义相匹配时,该代码似乎可以工作。

【讨论】:

    【解决方案3】:

    问题说:

    n= 55 m= 9808
    

    但是代码包括:

    int numbers[n];
    
    for(i=0;i<m;i++)
       numbers[i] = i + 1;
    

    i 传递55 之后,这是缓冲区溢出,导致未定义的行为。

    第二个循环有同样的错误(nm 交换了);另一个错误是错误的维度被传递给qsort


    要修复这些错误,请在声明数组之后的代码中停止使用mn。相反,使用数组的维度。一种方法是写:

    #define dimof(ARR) ( sizeof(ARR) / sizeof (ARR)[0] )
    

    然后你就可以使用它了:

    for (int i = 0; i < dimof(numbers); ++i)
        numbers[i] = i + 1;
    

    这样就没有机会混淆哪个变量与哪个数组。

    您必须对第二个循环和 qsort 维度执行相同的操作。

    【讨论】:

    • 我看了你的回答。我只想让它在 m>n 时工作。而且我知道这不是最好的样式代码,但它必须工作。就像在 java 中一样。
    • @VSG24 当m &gt; n 时它坏了(正如我的回答和其他人指出的那样)
    • 你能分享固定代码吗?无法根据您的建议修复它。
    • @VSG24 不,你必须付出一点努力。至少您需要做的就是在您当前使用错误的代码中将m 更改为n 并将n 更改为m。运用你的大脑。例如,当您有 for(i=0;i&lt;m;i++) 时,i 可以采用哪些可能的值?你明白为什么result只有n元素,而in大,写result[i]是个问题吗?
    • 知道了。但它现在并没有更好的工作。看在上帝的份上,请给我固定的代码,以便我可以研究它。这个程序不是任务或任何东西。我本来打算在 5 分钟内完成,但结果却是这个怪物。
    【解决方案4】:

    因为它比指出每个错误更容易,所以这里将 Java 代码音译为 C 并带有一些更有意义的变量名(Horstmann 应该知道得更好),但没有排序代码(这会分散注意力):

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <time.h>
    
    int main( void )
    {
      int sampleSize, valueRange;
      printf( "How many samples do you want to take: " );
      fflush( stdout );
      scanf( "%d", &sampleSize );
    
      printf( "What is the range of values, starting from 1: " );
      fflush( stdout );
      scanf( "%d", &valueRange );
    
      /**
       * The numbers array contains your source values, ranging
       * from 1 to valueRange.  The result array contains a random,
       * non-repeating sample of the numbers array.
       */
      int numbers[valueRange];
      int result[sampleSize];
    
      for ( int i = 0; i < valueRange; i++ )
        numbers[i] = i + 1;
    
      srand( time( NULL ));
    
      for ( int i = 0; i < sampleSize; i++ )
      {
        int sampleIndex = rand() % valueRange;
        result[i] = numbers[sampleIndex];
        numbers[sampleIndex] = numbers[ valueRange - 1 ];
        valueRange--;
      }
    
      for ( int i = 0; i < sampleSize; i++ )
        printf( "result[%4d] = %d\n", i, result[i] );
    
      return 0;
    }
    

    示例会话:

    [fbgo448@n9dvap997]~/prototypes/rand: ./stackrand
    How many samples do you want to take: 10
    What is the range of values, starting from 1: 10
    result[   0] = 5
    result[   1] = 6
    result[   2] = 7
    result[   3] = 4
    result[   4] = 10
    result[   5] = 3
    result[   6] = 2
    result[   7] = 8
    result[   8] = 1
    result[   9] = 9
    [fbgo448@n9dvap997]~/prototypes/rand: ./stackrand
    How many samples do you want to take: 10
    What is the range of values, starting from 1: 10
    result[   0] = 9
    result[   1] = 3
    result[   2] = 7
    result[   3] = 1
    result[   4] = 4
    result[   5] = 8
    result[   6] = 2
    result[   7] = 5
    result[   8] = 6
    result[   9] = 10
    [fbgo448@n9dvap997]~/prototypes/rand: ./stackrand
    How many samples do you want to take: 10
    What is the range of values, starting from 1: 100
    result[   0] = 28
    result[   1] = 90
    result[   2] = 100
    result[   3] = 4
    result[   4] = 15
    result[   5] = 76
    result[   6] = 3
    result[   7] = 60
    result[   8] = 65
    result[   9] = 21
    

    像这样使用可变长度数组时要小心;如果您为您的范围或样本大小输入足够大的值,您将超出堆栈空间并获得运行时错误。使用malloccalloc 分配空间会更安全,但对于小范围和样本量,这绝对更容易,更省事。

    此外,您应该添加一些代码以确保您的样本量始终小于您的值范围。或 Bad Things™ 会发生。

    【讨论】:

    • 感谢分享,但我通过简单地切换数组值来修复它。
    【解决方案5】:
    the following code may be what your looking for:
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <time.h>
    
    int cmpfunc (const void * a, const void * b);
    
    int main()
    {
        puts("How many numbers do you want to generate?");
        int n;
        scanf("%d", &n);
    
        puts("What should be the largest number possible?");
        int m;
        scanf("%d", &m);
        int result[n];
    
        int i;
    
        srand(time(NULL));
    
        for(i=0;i<n;i++)
        {
            result[i] = rand() % m;
        }
    
        qsort(result, n, sizeof(int), cmpfunc); //sorting the result array
    
        for(i=0;i<n;i++)
        {
            printf("%d\n", result[i]);
        }
    
        getchar();
        return 0;
    } // end function: main
    
    
    int cmpfunc (const void * a, const void * b)
    {
        return ( *(int*)a - *(int*)b );
    } // end function: cmpfunc
    

    【讨论】:

    • 这个实现可以重复随机数。问题中的代码试图提供 n 个唯一的随机数
    • @MattMcNabb 确切地说,集合的每个元素都必须是唯一的,因为它是单调的
    猜你喜欢
    • 2011-11-07
    • 1970-01-01
    • 2014-04-27
    • 2015-09-10
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    相关资源
    最近更新 更多