Hassan
Hassan

Reputation: 21

Dynamically changing array size in C++

I need to transform an array from {4, 2 ,5} to {4, 2, 5, 4, 2, 5}. Here's my output: {4, 2, 5, 3.21143e-322, 0, 2}, which is obviously incorrect. But I cannot seem to figure out the issue in my logic. Perhaps another perspective can find that issue.


This is my code:

void repeatArray(double* oldArray, int size) {
    int newSize = size * 2;
    double* newArray = new double[newSize];
    for (int i = 0; i < size; i++) {
        newArray[i] = oldArray[i];
    }
    for (int i = 0; i < size; i++) {
        newArray[size+i] = oldArray[i];
    }
    oldArray = newArray;
    delete [] newArray;
}

int main() {
    double* oldArray = new double[3];
    oldArray[0] = 4;
    oldArray[1] = 2;
    oldArray[2] = 5;
    repeatArray(oldArray, 3);
    for (int i=0; i<6; i++)
        cout << oldArray[i] << endl;
    delete []oldArray;
    return 0;
}

Upvotes: 1

Views: 16203

Answers (3)

schorsch312
schorsch312

Reputation: 5694

Since you said C++, I suggest you use a proper container, e.g. std::vector.

If you don't have a very good reason to do your own memory management, than you should avoid using new and delete, see here for an elaborated explanation.

Using templates enhances the possibility to reuse the repeat function with other types than double.

Thus, your code is reduced to the following and is easier to read.

#include <vector>
#include <iostream>
template <typename T>
std::vector<T> repeat(const std::vector<T>& originalVec) {
    auto repeatedVec = originalVec;
    repeatedVec.insert(repeatedVec.end(), originalVec.begin(), originalVec.end());

    return repeatedVec;
}

int main() {
    std::vector<double> oldArray {4,2,5};

    const auto newArray = repeat(oldArray);

    for (const auto item : newArray) {
        std::cout << item << std::endl;
    }

    return 0;
}

Upvotes: 0

Jorge Bellon
Jorge Bellon

Reputation: 3106

The problem is that repeatArray parameters are local to the function, so if you change their value, the change won't be seen past the function call. You can use a pointer to pointer double** oldArray to change what oldArray is pointing to, or return the pointer of the new array location.

However, this is C++, where you can use STL containers. Your code would become much more simple and readable.

void repeat( std::vector<double>& numbers ) {
   // Reserve rellocates the vector if there is not enough space
   // otherwise, the iterators first and last could be invalidated.
   numbers.reserve( numbers.size() * 2 );

   auto first = numbers.begin();
   auto last = numbers.end();
   std::copy( first, last, std::back_inserter(numbers) );
}

int main() {
   std::vector<double> nums({4, 2, 5});
   repeat(nums);
   for( double num : nums ) {
      std::cout << num << '\n';
   }
   return 0;
}

std::vector takes care of your allocation, reallocation and copy of the elements, and the deallocation of the resources it makes use.

Upvotes: 1

Minas Mina
Minas Mina

Reputation: 2107

The problem is that merely assigning the new array to the pointer in repeatArray() does not change it from the outside.

What you can do in repeatArray() is to return the newly created array.

double* repeatArray(double* oldArray, int size) {
    int newSize = size * 2;
    double* newArray = new double[newSize];
    for (int i = 0; i < size; i++) {
        newArray[i] = oldArray[i];
    }
    for (int i = 0; i < size; i++) {
        newArray[size+i] = oldArray[i];
    }
    delete [] oldArray;
    return newArray;
}

And in main():

oldArray = repeatArray(oldArray, 3);


A probably better approach would be to use std::vector that is resized automatically as needed.

Upvotes: 6

Related Questions