-1

Everything seems to run okay up until the return part of shuffle_array(), but I'm not sure what.

 int * shuffle_array(int initialArray[], int userSize)
 {
     // Variables
     int shuffledArray[userSize];       // Create new array for shuffled
     srand(time(0));

     for (int i = 0; i < userSize; i++)     // Copy initial array into new array
    {
          shuffledArray[i] = initialArray[i];
    }

     for(int i = userSize - 1; i > 0; i--)
    {
         int randomPosition = (rand() % userSize;
         temp = shuffledArray[i];
         shuffledArray[i] = shuffledArray[randomPosition];
         shuffledArray[randomPosition] = temp;
    }

    cout << "The numbers in the initial array are: ";
    for (int i = 0; i < userSize; i++)
    {
         cout << initialArray[i] << " ";
    }
    cout << endl;
    cout << "The numbers in the shuffled array are: ";
    for (int i = 0; i < userSize; i++)
    {
        cout << shuffledArray[i] << " ";
    }
    cout << endl;
    return shuffledArray;
}

Sorry if spacing is off here, not sure how to copy and past code into here, so I had to do it by hand. EDIT: Should also mention that this is just a fraction of code, not the whole project I'm working on.

Jacob E
  • 9
  • 2
  • 2
    use std::vector – pm100 Oct 09 '18 at 23:37
  • 3
    `int shuffledArray[userSize];` is not valid C++. It is a GCC extension which is, like all extensions, a bad one, and will make your code completely non-portable. –  Oct 09 '18 at 23:40
  • Unrelated: `srand(time(0));` is not usually a good thing to have in any function but `main`. It seeds and starts the random number generator. You almost never want to call it more than once, and if you ever find yourself in a case where you need to call it more than once, `rand` and `srand` are almost certainly insufficient for whatever you're doing. – user4581301 Oct 09 '18 at 23:40
  • This code cannot "Getting sementation fault (core dumped)" because it wont compile in the first place. – Swordfish Oct 09 '18 at 23:42
  • 3
    [Your Rubber Duck](https://en.wikipedia.org/wiki/Rubber_duck_debugging) wants you to know how many times `for(int i = userSize - 1; i < userSize; i++)` can iterate. – user4581301 Oct 09 '18 at 23:42
  • To copy/paste code here, you can copy from your editor, paste in the question text field, select the code that you just pasted and click the "code" button in the editor toolbar. – zneak Oct 09 '18 at 23:43
  • 1
    If you want to really annoy your instructor, use [std::shuffle](https://en.cppreference.com/w/cpp/algorithm/random_shuffle). – user4581301 Oct 09 '18 at 23:52
  • 1
    @JacobE Also, I don't see why a function named shuffle_array() should ever allocate memory and copy things. It should operate on the array given to it. If the user of the function needs a copy of the original data he can make one himself. What you are trying to do is copy and_shuffle_array(). which violates the single responsibility principle (SRP). btw ... `std::rand()` should be only called once at the beginning of your `main()`. – Swordfish Oct 09 '18 at 23:53

4 Answers4

4

There are several issues of varying severity, and here's my best attempt at flagging them:

int shuffledArray[userSize];

This array has a variable length. I don't think that it's as bad as other users point out, but you should know that this isn't allowed by the C++ standard, so you can't expect it to work on every compiler that you try (GCC and Clang will let you do it, but MSVC won't, for instance).

srand(time(0));

This is most likely outside the scope of your assignment (you've probably been told "use rand/srand" as a simplification), but rand is actually a terrible random number generator compared to what else the C++ language offers. It is rather slow, it repeats quickly (calling rand() in sequence will eventually start returning the same sequence that it did before), it is easy to predict based on just a few samples, and it is not uniform (some values have a much higher probability of being returned than others). If you pursue C++, you should look into the <random> header (and, realistically, how to use it, because it's unfortunately not a shining example of simplicity).

Additionally, seeding with time(0) will give you sequences that change only once per second. This means that if you call shuffle_array twice quickly in succession, you're likely to get the same "random" order. (This is one reason that often people will call srand once, in main, instead.)

for(int i = userSize - 1; i > 0; i--)

By iterating to i > 0, you will never enter the loop with i == 0. This means that there's a chance that you'll never swap the zeroth element. (It could still be swapped by another iteration, depending on your luck, but this is clearly a bug.)

int randomPosition = (rand() % userSize);

You should know that this is biased: because the maximum value of rand() is likely not divisible by userSize, you are marginally more likely to get small values than large values. You can probably just read up the explanation and move on for the purposes of your assignment.

return shuffledArray;

This is a hard error: it is never legal to return storage that was allocated for a function. In this case, the memory for shuffledArray is allocated automatically at the beginning at the function, and importantly, it is deallocated automatically at the end: this means that your program will reuse it for other purposes. Reading from it is likely to return values that have been overwritten by some code, and writing to it is likely to overwrite memory that is currently used by other code, which can have catastrophic consequences.

Of course, I'm writing all of this assuming that you use the result of shuffle_array. If you don't use it, you should just not return it (although in this case, it's unlikely to be the reason that your program crashes).

Inside a function, it's fine to pass a pointer to automatic storage to another function, but it's never okay to return that. If you can't use std::vector (which is the best option here, IMO), you have three other options:

  • have shuffle_array accept a shuffledArray[] that is the same size as initialArray already, and return nothing;
  • have shuffle_array modify initialArray instead (the shuffling algorithm that you are using is in-place, meaning that you'll get correct results even if you don't copy the original input)
  • dynamically allocate the memory for shuffledArray using new, which will prevent it from being automatically reclaimed at the end of the function.

Option 3 requires you to use manual memory management, which is generally frowned upon these days. I think that option 1 or 2 are best. Option 1 would look like this:

void shuffle_array(int initialArray[], int shuffledArray[], int userSize) { ... }

where userSize is the size of both initialArray and shuffledArray. In this scenario, the caller needs to own the storage for shuffledArray.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • Thanks for the detailed description, to answer a few of the things you said: Im still in college and this is for a relatively low level c++ course so declaring an array as int shuffledArray[userSize]; – Jacob E Oct 10 '18 at 00:12
  • Thanks for the detailed description, to answer a few of the things you said: Im still in college and this is for a relatively low level c++ course so declaring an array as "int shuffledArray[userSize];" is the only way i know how to. rand/srand are the only ways that we've been taught to randomize numbers. And as far as returning it, our professor gave us a small outline: Required functions: void initialize_array(int [], int); int * shuffle_array(const int [], int); void print_array(const int [], int); So i assume that that means I need to return shuffledArray? – Jacob E Oct 10 '18 at 00:18
  • @JacobE, I understand that your assignment probably has several constraints of that type, so consider that feedback extra enrichment instead of criticism of how you did it. Regarding `int shuffledArray[userSize]`, the standard-compliant thing to say would be, for instance, `int shuffledArray[10]` (where 10 is constant, not a variable). – zneak Oct 10 '18 at 00:21
  • 1
    The only safe way to implement `int* shuffle_array(const int[], int)` is to use the `new` operator: you'd replace `int shuffledArray[userSize];` with `int* shuffledArray = new int[userSize];`, so that kind of locks it. You then need to use `delete[]` after you're done with the result of `shuffle_array` to let your program reclaim the memory. – zneak Oct 10 '18 at 00:24
  • shuffledArray[userSize] is a variable because it needs to be. The project asks me to have a user input a number for the size of the array, then a normal array is created, and this function that I've been struggling with is supposed to shuffle this array. So the only way I see is working correctly is to have it as a variable rather than a constant. – Jacob E Oct 10 '18 at 00:25
  • @JacobE, the standard way to do that without `std::vector` is to use the `new` operator (see comment above). The `new` expression is always allowed to use a variable as the array size. – zneak Oct 10 '18 at 00:26
2

You should NOT return a pointer to local variable. After the function returns, shuffledArray gets deallocated and you're left with a dangling pointer.

Kon
  • 4,023
  • 4
  • 24
  • 38
  • so use std::vector – pm100 Oct 09 '18 at 23:40
  • I'm not sure that I follow what you mean? For reference, this is just a fraction of my program, where I'm going to need to be able to call from that array later. – Jacob E Oct 09 '18 at 23:43
  • @pm100, I'm doing this for a project in school, and have not gotten to vectors yet, so I'm not familiar with how to use them. – Jacob E Oct 09 '18 at 23:44
  • @JacobE, the storage that you return is automatically allocated when the function starts executing, and automatically deallocated when the function returns. – zneak Oct 09 '18 at 23:44
  • @JacobE you can't return a plain-old array. It [decays to a pointer](https://stackoverflow.com/questions/1461432/what-is-array-decaying) and that pointer refers to data lost when the function returned. – user4581301 Oct 09 '18 at 23:44
  • @JacobE - so read up on them and wow your teacher, earn extra credit. They are ez to use – pm100 Oct 09 '18 at 23:45
  • @JacobE `std::vector shuffledArray(userSize);` -- That is the "dynamic array" in C++. Using `int shuffledArray[userSize]` is **not** C++, plain and simple. The other alternative, using `new[]`, introduces a potential for memory leaks and potentially hard-to-maintain code. – PaulMcKenzie Oct 10 '18 at 01:03
1

When you define any non static variables inside a function, those variables will reside in function's stack. Once you return from function, the function's stack is gone. In your program, you are trying to return a local array which will be gone once control is outside of shuffle_array().

To solve this, either you need to define the array globally (which I won't prefer because using global variables are dangerous) or use dynamic memory allocation for the array which will create space for the array in heap rather than allocating the space on the function's stack. You can use std::vectors also, if you are familiar with vectors.

To allocate memory dynamically, you have to use new as mentioned below.

int *shuffledArray[] = new int[userSize];

and once you completed using shuffledArray, you need to free the memory as below.

delete [] shuffledArray;

otherwise your program will leak memory.

kadina
  • 5,042
  • 4
  • 42
  • 83
  • Micronag: Use "Automatic Storage" rather than "Stack". C++ can be implemented without stacks (and heaps). – user4581301 Oct 09 '18 at 23:45
  • So do I need to define it outside of this function, before this function is called? – Jacob E Oct 09 '18 at 23:46
  • You could, but your other options are dynamic storage (`int * shuffledArray = new int[userSize];`, and remember to `delete[]` it when done) or use a `std::vector`. If you are not allowed to use `std::vector`, you can write your own poor-man's `vector` in a few hour's time. It's good practice for when you have to do it later in the semester. – user4581301 Oct 09 '18 at 23:49
  • @NeilButterworth: I was typing hurry, I missed the pointer. You should have edited the post instead of saying bad question and answer. I think people are more interested to give negative comments or down voting in stack overflow. – kadina Oct 10 '18 at 01:01
1

You cannot return a local array. The local array's memory is released when you return (did the compiler warn you about that). If you do not want to use std::vector then create yr result array using new

int *shuffledArray = new int[userSize];

your caller will have to delete[] it (not true with std::vector)

pm100
  • 48,078
  • 23
  • 82
  • 145
  • @JacobE instaead of the declaration you currently have for shuffledArray – pm100 Oct 09 '18 at 23:53
  • `int shuffledArray[] = new int[userSize];` - nope, not valid C++. And who is upvoting all these bad answers and questions here? –  Oct 10 '18 at 00:03
  • in my defense I was not sure of the syntax ( iwanted to make the least source changes) and I saw that kadina had it too so I thought - yup i got it right :-( a bad excuse tho – pm100 Oct 10 '18 at 00:06
  • @pm100 Always compile the code before posting it here. –  Oct 10 '18 at 00:17
  • @NeilButterworth wrist well slapped – pm100 Oct 10 '18 at 00:22