0

Write a program which outputs 10 given numbers into two rows, one for odd and one for even numbers. Use arrays.

After declaring an input array for 10 numbers which the user enters, I tried declaring separate arrays for odd and even values which would later be sorted by a for-loop.

I get stuck when I need to assign these values n to odd or even arrays.

int input[10];
int odd[]{};
int even[]{};
int n;

for(n=0;n<10;n++)
{
    if ((input[n])%2==0)
    {
      odd[n] = n; 
    }
    else
    {
      even[n] = n;
    }
nocomment
  • 119
  • 6
  • I afraid you cannot do that in that way. Your `int odd[]` array is not dynamic one. You should use rather STL containers, or know the size of `odd` and `even` arrays at compile time. – vahancho May 29 '19 at 12:29
  • The size of an array on the stack needs to be known at compile time, otherwise, the compiler doesn't know how much space it needs to allocate. – mfnx May 29 '19 at 12:40
  • Please expand on "I get stuck". What specific problem do you encounter? – Lightness Races in Orbit May 29 '19 at 13:44

4 Answers4

3

You don't need dynamic allocation for this. We can just make two arrays and fill them as needed.

static constexpr std::size_t N = 10;
const int input[N] = { /* user input here */ };

int odd[N] = {};
int even[N] = {};

std::size_t countOdd = 0;
std::size_t countEven = 0;

for (std::size_t i = 0; i < N; i++)
{
    if (input[i] % 2 == 0)
       even[countEven++] = input[i];
    else
       odd[countOdd++] = input[i];
}

There will be exactly N (10) elements "wasted" at the end of odd and even in total (with some unknown distribution), but who cares? Ten automatic-storage ints! That's nothing. As long as we keep track of how many odds and how many evens we "care about", everything's fine.

Now for the two-row output:

for (std::size_t i = 0; i < countOdd; i++)
    std::cout << odd[i] << ' ';
std::cout << '\n';

for (std::size_t i = 0; i < countEven; i++)
    std::cout << even[i] << ' ';
std::cout << '\n';

Easy!

I used std::size_t where appropriate for array indices, rather than int, but you could ignore that for now if you like. I also fixed your modulo operation, and you were storing the indices of the even/odd values, not the values themselves.


Full program example:

#include <iostream>
#include <cstddef>  // for std::size_t

int main()
{
    static constexpr std::size_t N = 10;
    const int input[N] = { 1,5,9,14,3,99,82,42,43,70};

    int odd[N] = {};
    int even[N] = {};

    std::size_t countOdd = 0;
    std::size_t countEven = 0;

    for (std::size_t i = 0; i < N; i++)
    {
        if (input[i] % 2 == 0)
           even[countEven++] = input[i];
        else
           odd[countOdd++] = input[i];
    }

    for (std::size_t i = 0; i < countOdd; i++)
        std::cout << odd[i] << ' ';
    std::cout << '\n';

    for (std::size_t i = 0; i < countEven; i++)
        std::cout << even[i] << ' ';
    std::cout << '\n';
}

// g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
// 1 5 9 3 99 43 
// 14 82 42 70 

(live demo)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • What if the user need to give an input of thousands of values ? What I mean is, this works well in our scenario, with a known input of fixed size, but can your solution be adapted to a more generic scenario (like unknown input size for example). And can't the "wasted" memory be a problem if we need a larger array ? – DrosvarG May 29 '19 at 14:14
  • 1
    @DrosvarG Yes, it can, but the OP said 10. – Lightness Races in Orbit May 29 '19 at 14:25
  • @LightnessRacesinOrbit Thank you for the solution, it helped me solve the problem. However, I'd like to know whether the problem could be solved using similar noncomplex methods for values that are larger and by which we don't waste the memory of the array, as DrosvarG pointed out. Thanks in advance. – nocomment Jun 02 '19 at 12:13
  • @LightnessRacesinOrbit Also, in the very problem example, do the new arrays, odd and even, allocate values straight to index of 1, instead of 0, given that value of countOdd and countEven is set to 0 and has an increment of 1 in the if loop? – nocomment Jun 02 '19 at 12:16
  • @nocomment No, it's a post-increment, so `0` comes first – Lightness Races in Orbit Jun 03 '19 at 00:20
2

A nice trick to avoid dynamic allocation or any additional storage is to partition the set. This appears in algorithms such as quicksort, so every computer scientist should learn it.

All you have to do is start with two indexes or pointers, one moving forward and one backward. As long as an item is in the correct partition, move the pointer past it. Once both pointers have found elements in the wrong partition, swap them and continue. Once the pointers converge, the partition is complete.

Or, if you want to leave the input unchanged, this allows you to do a single allocation equal to the size of the entire input, without reallocation or moving already-processed items to a new buffer.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thank you for your reply. Would you be able to go into more detail or exemplify the mentioned above, as I am a beginner and do not quite understand it? – nocomment Jun 02 '19 at 12:04
1

As vahancho said in a comment, both odd[] and even[] are static arrays. That means once created you can't change the size of any of them. Moreover, when declaring the array, the size cannot be "dynamic", ie int odd[n]; is only valid when n is a compile time constant (note that some compiler offer it as extension but it is not standard c++).

So here we get a bit stuck, and most would consider using the usual std::vector which have a variable size. Unfortunately, you specified "Use arrays" in your question. Erf, back to square one.

Let's think a little bit and remember that arrays can be seen as pointers. In the following image, we define an array arr[5]. Then arr is a pointer to the adress 1000, the first value of your array :

Spoiler alert : You can create a dynamic array with this property. Ok, so let's define a pointer for our two arrays of odd and even numbers and let's declare their associated size:

int * odd_array = NULL;
int * even_array = NULL;

int odd_array_size = 0, even_array_size = 0;

Now, the idea is to increase the size of the good array when we find an odd or even number and use the C function void* realloc(void* ptr, size_t size) offered by <cstdlib>to increase the size allocated for your array. In your case you probably want to do that as you are looping over your input array. Here is an exemple of what you can have in your case :

for (int n = 0; n < 10; n++)
{
    if ((input_array[n]) % 2 != 0) // We find an odd number
    {
        odd_array_size++; // Increase the size of the array
        odd_array = (int*)realloc(odd_array, odd_array_size * sizeof(int)); // Reallocate more memory
        odd_array[odd_array_size-1] = input_array[n]; // Add the value in your new allocated memory
    }
    else
    {
        // Same here, but in the case of an even number
        even_array_size++;
        even_array = (int*)realloc(even_array, even_array_size * sizeof(int));
        even_array[even_array_size-1] = input_array[n];
    }
}

With this, you get your two arrays odd_array and even_array, filled respectively with the odd and even numbers of your input_array, which both have their associated size odd_array_size and even_array_size

This is basically a C way to do this. You may probably consider smart pointers (in order to be safe with freeing the memory) and, if you were allowed, std::vectors which are the best way to deal with this problem. So don't forget to free your two arrays at the end of your program if you use this.

I hope this will be helpful and clear, don't hesitate to ask me clarifications in comment if needed.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
DrosvarG
  • 483
  • 3
  • 14
  • "neither initialize them with a variable like beginners could naively think (with a syntax like int odd[n])" this is either wrong or misleading, at least unclear. Nothing wrong with `int odd[n];` as long as `n` is a compile time constant – 463035818_is_not_an_ai May 29 '19 at 13:47
  • @formerlyknownas_463035818 As far as i know, and as specified in [this topic](https://stackoverflow.com/a/15013295/11502610), `int odd[n];` is not valid in proper C++ if `n` is a variable. Though, this same link explain different methods to initialize an array with a variable. But I don't think that one of them is consistant in our case – DrosvarG May 29 '19 at 14:00
  • 1
    "variables" are commonly also called "variables" when they are actually constants. `const size_t n = 10; int odd[n];` is perfertcly fine, what you refer to i guess is `int n = 10; int odd[n];` which is not standard c++ – 463035818_is_not_an_ai May 29 '19 at 14:02
  • dont get me wrong, I am just nitpicking, specifically about the "with a syntax like int odd[n]" because with the syntax there is definitely nothing wrong – 463035818_is_not_an_ai May 29 '19 at 14:04
  • @formerlyknownas_463035818 This is exactly what I refer to, but I don't know how to explain it better. Feel free to edit if you think this make my answer too unclear – DrosvarG May 29 '19 at 14:16
  • 1
    edited, I dont think it made the whole question "too unclear", though it was adding a bit of confusion already at the beginning of the answer, so I thought it is worth a fix – 463035818_is_not_an_ai May 29 '19 at 14:43
0

You need to have a dynamic array for odd and even.
Moreover you made a mistake, if the modulo equals zero, the number is even and not odd. And you want to add input[n] and not n.

I think you should use STL containers instead of raw arrays, it will make it easier.

You can do as follows:

std::array<int, 10> input {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // fill the array with anything you want

std::vector<int> odd, even;

for(unsigned int n = 0; n < input.size(); ++n)
{
    (input[n]%2) ? (odd.push_back(input[n])) : (even.push_back(input[n]));
}

You can replace the ternary conditional operator condition ? action_if_true : action_if_false by:

if(input[n]%2)
    odd.push_back(input[n]);
else
    even.push_back(input[n]);

I hope it can help.

Fareanor
  • 5,900
  • 2
  • 11
  • 37