-3

Here's the code for my program. it's supposed to get two numbers from user then generate random numbers using rand function. but when I compile it, the numbers are not random.

I also wrote this in java, and that one works perfectly.

C version:

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

EDIT: srand was inside the loop, people said it's not supposed to be called more than once. so i took it out but that wasn't helpful.

Java version:

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)
            {}
     }

}

edit 2:

c output: (is not random, sorted)

enter image description here

java output: (is random, sorted)

enter image description here

edit 3:

as i stated in comments values are : n= 55 m= 9808

also i'm using codeblocks so header files are not really an issue. they are automatically loaded by codeblocks.

edit 4:

I'm really impressed by what people suggest. qsort doesn't change a thing in generating random numbers. it just sorts the array. so even if i remove it, it doesn't change nothing.

In an array of random numbers we would expect that the difference between any two adjacent elements would also be random. This property is preserved under sorting. I sort the random numbers in both the C and Java could to check this property. As you can see, in the C code the differences between adjacent elements are all the same. This leads me to believe that the C code is not generating random numbers, but that the Java code is.

edit 5:

and i'm sure there should be no difference in algorithm between java and c.

edit 6:

I'm sorry that i'm not a professional. i'm just trying to make a C version of the Java program i have. A fixed code would be very appreciated.

****edit final:** Finally got it working. arrays "numbers" and "result" storing n and m respectively should store m and n instead. that's all. in addition to that i changed their names with what people suggested. some folks told me to switch the variables m and n with array dims. that just wasn't the case. here is the fixed code for anyone interested:**

#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 );
}
LW001
  • 2,452
  • 6
  • 27
  • 36
VSG24
  • 77
  • 7
  • May want to [read this](http://stackoverflow.com/questions/7343833/srand-why-call-it-only-once/). – WhozCraig Mar 13 '15 at 19:34
  • posted code is missing #include getch() is found in the conio.h (on windows)... strongly suggest using getchar() rather than getch() for amongst other reasons, conio.h is windows specific, so not portable – user3629249 Mar 13 '15 at 20:05
  • always check the returned value from calls to scanf() (and family) to assure the operation was successful – user3629249 Mar 13 '15 at 20:06
  • @VSG24: Shouldn't you be passing `m` as the second parameter of `qsort()`? You're currently passing `n`, the size of a completely different array. – Blastfurnace Mar 13 '15 at 20:07
  • C is not Java. Don't try to write code in it as if it were. `numbers[r] = numbers[m - 1];` does not do what you expect it to do. – Not a real meerkat Mar 13 '15 at 20:08
  • Any one who considers arithmetical methods of producing random digits is, of course, in a state of sin. – Richard Mar 13 '15 at 20:11
  • in the prototype for cmpfunc() function, the parameter types are not stated, so (most) compilers will assume any parameters are 'int', not 'const void *' – user3629249 Mar 13 '15 at 20:13
  • @user3629249 any such compiler would be broken; that code is correct (although poor style). `()` in a function declaration means to make no assumptions about the arguments – M.M Mar 13 '15 at 20:15
  • qsort doesn't matter. pls read end of the post again. – VSG24 Mar 13 '15 at 20:16
  • 2
    @VSG24: I have a suggestion. Can you edit your question to include a minimal example that reproduces the problem? The current buggy, awful code seems to be a distraction. By the way, `rand()` actually does work. – Blastfurnace Mar 13 '15 at 20:18
  • the array numbers[] is being set with values ranging from 1...m, but numbers is only n long, so if m>n then values are written past the end of the array numbers[], resulting in undefined behaviour and possibly a seg fault event. This is the offending line: 'for(i=0;i – user3629249 Mar 13 '15 at 20:19
  • 1
    If `qsort` doesn't matter, you should not have included it in your question. The best questions are those which present the minimal amount of code necessary to demonstrate the problem. Spending more time up-front crafting a good question will save your time and our energy. Also, consider rewording the title of your question. C is making random numbers, it is your usage of them that is wrong. – Richard Mar 13 '15 at 20:19
  • suggest filling array result[i], not from number[] (which can be eliminated from the code), but rather from rand() % m' – user3629249 Mar 13 '15 at 20:22
  • regarding this line: 'm--;' if m is <= n then the rand() % m will be using negative values for m, which will lead to problems with the modulo operation. suggest not decrementing m – user3629249 Mar 13 '15 at 20:24
  • Here's a hint. instead of using `n` and `m` later in the code, use the actual dimension of the array you are trying to operate on. If you update your Java code to use `n` and `m` in the same places where you actually use the array dimension expression then you'll probably get the same output. – M.M Mar 13 '15 at 20:26
  • @VSG24: The two versions are obviously not the same. Just look at the usage of `m` and `n`. You've swapped how they're used between the C++ and Java, completely breaking the C++ code. (Hi Matt McNabb!) – Blastfurnace Mar 13 '15 at 20:26
  • 1
    another idea would be to use meaningful variable names such as `num_numbers` and `num_result`, then you will be less likely to mismatch the dimensions with the arrays – M.M Mar 13 '15 at 20:27
  • it doesn't thats a random number between 0 and m-1 – Steve Cox Mar 13 '15 at 20:32
  • @VSG24 have you read my answer? your main mistake has now been pointed out by multiple people and you haven't acknowledged it. – M.M Mar 13 '15 at 20:43
  • "I also wrote this in java, and that one works perfectly." - you mean someone else wrote it in Java, and you don't really understand how it works or how arrays work – M.M Mar 13 '15 at 21:13
  • I understand both versions . C and JAVA but C code is just not working as it should be. I believe the method should be the same as java. if you pass a small number as n, like 5 and for example 55 for m, it does generate random numbers (at least i think it does). but for larger integers, it just doesn't work in C. – VSG24 Mar 14 '15 at 06:40

5 Answers5

3

srand(time(NULL)); is used to seed the random number generator. It needs to be called only once. You need to move that out of the for loop.

If you seed every time, you're going to end up with the same number being produced by rand().

Also, time() is prototyped in time.h.

Next, as mentioned by @Blastfurnace, you should be passing m instead of n as the second argument to qsort().

Then,

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

may (will) lead to UB by producing out-of-bound access for numbers array.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • @VSG24 what are the values for `m` and `n`? – Sourav Ghosh Mar 13 '15 at 19:35
  • n=55, m=9808. doesn't matter what number. result is not random. – VSG24 Mar 13 '15 at 19:37
  • errm... `srand()` is not within the same loop as `rand()` – Weather Vane Mar 13 '15 at 19:43
  • sorry, upvoted instead of down. Hope that gives you +9 not +-0 – Weather Vane Mar 13 '15 at 19:45
  • pls stop talking about srand. it was inside the loop, he said to get it out, i did it and it wasn't helpful. so srand is not the issue. – VSG24 Mar 13 '15 at 19:48
  • @VSG24 can you please let us know what is your output? how it is not random? also, what is the purpose of _sorting_ a random number array? – Sourav Ghosh Mar 13 '15 at 19:53
  • @SouravGhosh, in an array of random numbers we would expect that the difference between any two adjacent elements would also be random. This property is preserved under sorting. By sorting the random number array, OP has demonstrated that his C code violates this property and, therefore, that its output is "non-random". The Java output, on the other hand, preserves the property. It's a useful comparison. – Richard Mar 13 '15 at 20:22
2

In your Java code:

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

In your C code:

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

The size of the arrays are reversed. The code seems to work when I match the definition on the C code to that of your Java code.

MysticXG
  • 1,437
  • 10
  • 10
1

Question says:

n= 55 m= 9808

However the code includes:

int numbers[n];

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

After i passes 55 then this is a buffer overflow, causing undefined behaviour.

The second loop has the same bug (n and m swapped); Another bug is that the wrong dimension is passed to qsort.


To fix these errors, stop using m and n in the code after the point where you declared the arrays. Instead, use the dimension of the array. One way is to write:

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

and then you can use it:

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

This way there is no chance of mixing up which variable goes with which array.

You'll have to do the same thing for the second loop, and the qsort dimension.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I read your answer. I only want to make it work when m>n. and I know this is not best styled code ever but it HAS to work. as it does in java. – VSG24 Mar 13 '15 at 20:47
  • @VSG24 it is broken when `m > n` (as my answer and others point out) – M.M Mar 13 '15 at 20:55
  • would you share the fixed code. could not fix it using your advice. – VSG24 Mar 13 '15 at 21:08
  • @VSG24 no, you have to make a little bit of effort. At a minimum all you need to do is change `m` to `n` and change `n` to `m` in your code where you currently are using the wrong one. Apply your brain. For example when you have `for(i=0;i – M.M Mar 13 '15 at 21:11
  • got it. but it doesn't work any better now. for god's sake pls give me the fixed code so i can study it. this program is not an assignment or anything. i was just going to do in in like 5 minutes but it turned out to be this monster. – VSG24 Mar 13 '15 at 21:20
  • @VSG24 step through your code in a debugger if you're sure that you have got all your array dimensions correct. If you've only made minor changes then you could edit your question (but make sure you include the **exact** code you are running) – M.M Mar 13 '15 at 21:30
0

Because it's easier than pointing to each error, here's a transliteration of the Java code into C with some more meaningful variable names (Horstmann should know better) but without the sorting code (which was becoming a distraction):

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

Sample sessions:

[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

Be careful when using variable-length arrays like this; if you put in large enough values for your range or sample size you'll overrun your stack space and get a runtime error. It would be safer to allocate the space using malloc or calloc, but for small ranges and sample sizes this is definitely easier and less hassle.

Also, you should add some code to make sure your sample size is always less than your value range. or Bad Things™ will happen.

John Bode
  • 119,563
  • 19
  • 122
  • 198
-1
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
user3629249
  • 16,402
  • 1
  • 16
  • 17