2

I have a dynamically created array of integers. Now I have to remove all elements which have index %3 == 0. (for example, 3, 6, 9, ...). So, what is the best way to decrease array size? With malloc I can use realloc for the same part of memory, but what about new operator? What to do this way. Just slide all elements left, make zero to all another elements?

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
Max Frai
  • 61,946
  • 78
  • 197
  • 306
  • Use STL, it does all of this for you. – Nikolai Fetissov Dec 04 '11 at 17:17
  • In general, `realloc` doesn't reuse the same part of memory. – Oliver Charlesworth Dec 04 '11 at 17:18
  • 1
    Use the C++ Standard Library; it does all of this for you and is not decades-deprecated. – Lightness Races in Orbit Dec 04 '11 at 17:26
  • There is no "`renew`" in C++. I [asked about this](http://stackoverflow.com/questions/8003233/does-stdvector-have-to-move-objects-when-growing-capacity-or-can-allocator) once; apparently it wasn't deemed worthwhile. Note that `realloc()` in its C form cannot be used for C++, because you aren't allowed to move memory around for C++ objects. – Kerrek SB Dec 04 '11 at 18:32
  • Do you mean removing indecies 2, 5, 8....? Indecies start at 0, so that would be every third one. Your example in the Q looks like it should also remove index 0. – Mooing Duck Dec 04 '11 at 18:36

4 Answers4

3

#include <algorithm>
#include <iostream>
#include <vector>

bool IsDividedByThree (int i) { return ((i%3)==0); }

int RandomNumber () { return (rand()%100); }

int main()
{
    std::vector<int> myInts(50);

    std::generate(myInts.begin(), myInts.end(), RandomNumber);

    std::copy(myInts.begin(), myInts.end(), std::ostream_iterator<int>(std::cout, " "));

    myInts.erase(std::remove_if(myInts.begin(), myInts.end(), IsDividedByThree), myInts.end());

    std::copy(myInts.begin(), myInts.end(), std::ostream_iterator<int>(std::cout, " "));

}

Isn't so nice that STL takes care everything for you?

Hm didn't see comment, in which one is forced not to use STL.

The C version:

    int *temp = new int[NEW_SIZE];
    memcpy( temp , old_array, size_of_old_array * sizeof(int) );
    delete[] old_array;
    old_array = temp;
  1. create the array dynamically
  2. create a new array with the new size
  3. copy the elements from the first to the second array
  4. delete the first array
  5. redirect the pointer to the first array to the second

All these answer So, what is the best way to decrease array size? - I assumed you already knew how to solve the rest of your problem.

FailedDev
  • 26,680
  • 9
  • 53
  • 73
  • However this solution only is guaranteed to work for POD types. Use `std::copy` instead of `memcpy` for arrays of arbitrary (copyable) types. Also note that in C++11, you'll probably want to move the objects instead of copying them. – celtschk Dec 04 '11 at 20:30
  • @celtschk I think that OP is not allowed to use any STL therefore I deleted my original answer. – FailedDev Dec 04 '11 at 20:37
2

I'd simply allocate a new smaller array and then copy elements to it. Something like this (this includes the element at 0 index):

int* array = new int [original_size];

// fill array

size_t new_size = original_size - original_size / 3 - 1; // i think i got this right, untested
int* new_array = new int [new_size];

for (int i = 0, int j = 0; i < original_size; i++)
{
    if (i % 3 == 0)
    {
        new_array[j] = array[i];
        j++
    }
}

delete [] array;
array = new_array;
new_array = nullptr;

You can of course work in place and shift elements to the left. But you can't delete a part of array that was allocated via new[].

Since this is an exercise, and you can't use STL, why don't you try to implement a simple vector class yourself?

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
jrok
  • 54,456
  • 9
  • 109
  • 141
  • I think it's just `original_size - original_size / 3`. Check on sizes 0, 1, 2, 3, 4, 5, and 6. – Mooing Duck Dec 04 '11 at 18:20
  • Also, OP says "this is styduing part of exercise", so I'd treat it like homework and avoid giving straight code. – Mooing Duck Dec 04 '11 at 18:26
  • @MooingDuck Let's see, from array 0..6 (7 elements) we remove elements 0, 3, 6, that's 3 elements. New array has 4 elements, so 7 - 7/3 = 5 would be incorrect, right? – jrok Dec 04 '11 at 18:27
  • His example doesn't make sence, since he doesn't remove 0. Maybe we remove 2, 5, 8...? I put it back to how you had it since I'm not sure anymore – Mooing Duck Dec 04 '11 at 18:34
  • @MooingDuck Yes, it actually depends if you remove element at 0 or not. – jrok Dec 04 '11 at 18:37
0

Simply setting data elements to 0 wont free them. And when you allocate new memory for the resized array, you need to copy all of the elements from previous memory.

I would suggest you to implement it as a linked list.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
0

You can use placement new operator in C++. (#include <new> is required). For example

#include <new>

int main(int argc, char **argv) {
    double *b = new double[10];
    new(b) double[8];

    delete [] b;
}
Summer_More_More_Tea
  • 12,740
  • 12
  • 51
  • 83
  • 2
    First of all, that doesn't solve the issue. Second, it's really confusing. Third, it's undefined behavior. – Mooing Duck Dec 04 '11 at 18:23
  • @MooingDuck The first two reasons sounds ground. What about the third? Why this may result in undefined behavior? Could you please explain more? Thanks. – Summer_More_More_Tea Dec 04 '11 at 23:44
  • I can't quote the standard from my phone, but its undefined behavior do call a constructor on an already constructed object (and same for destructors). Actually, I think chars might be an exception, and if so it stands to reason other primitives or PODs might also be exceptions. We'd have to check the standard to see if this is UB. – Mooing Duck Dec 05 '11 at 02:58