简体   繁体   中英

How to expand dynamically allocated array in C++?

I have tried to implement solution to dynamical expansion of array as user is entering new data in main as shown:

ComplexNumber** nizKompl = new ComplexNumber*[1];
bool unos = true;

while(unos){
  cout << "Unesite novi kompleksni broj(realni imaginarni): ";

  if(cin >> re >> im){ 
    nizKompl[brojUnesenih] = new ComplexNumber(re,im);
    ++brojUnesenih;

    ComplexNumber** nizTemp = new ComplexNumber*[brojUnesenih+1];
    copy(nizKompl, nizKompl+brojUnesenih, nizTemp);

    for(int i=0; i<brojUnesenih; ++i){
      delete nizKompl[i];
    }

    delete [] nizKompl;
    nizKompl = nizTemp; 
  } else {
    cout << endl << endl;
    unos = false;
  }
}

ComplexNumber is custom type. ComplexNumber works fine but I am having problem with double free or corruption error as I am entering new data and creating new ComplexNumbers in program.

Is there some better way to achieve this? I need to use my own dynamical array instead of std::vector because It is for educational purpose.

As I understand double free error occurs when you try to free memory which is already free'd. But It seems that I just can't resolve the issue, as I can see no double free should happen.

Is something happening in memory of which I have no knowledge? Is it problem with std::copy as I am copying array of pointers of pointers?

I would really appreciate any help or suggestion. Thank you!

If you really need not to use std::vector (for educational reasons), then your problem is here:

for(int i=0; i<brojUnesenih; ++i){
  delete nizKompl[i];
}

you just copied those pointers to your new, slightly bigger array. If you delete the objects they point to, your new array is full of unusable dangling pointers.

The proximate fixes are:

  1. just don't delete these objects. Consider ownership transferred to the new array and keep them alive. Delete the three lines quoted above.
  2. OR if you really want to delete the originals, you need to copy them first - this means a deep copy of the object rather than a shallow copy of the pointer, so your new array should be populated like

     // shallow copy: // copy(nizKompl, nizKompl+brojUnesenih, nizTemp); // deep copy: transform(nizKompl, nizKompl+brojUnesenih, nizTemp, clone); 

    with the function

     ComplexNumber* clone(ComplexNumber *original) { return new ComplexNumber(*original); } 

    NB. I can't think of any good reason to do this, it's just wasteful.

Use std::vector<ComplexNumber> and use push_back to allocate memory dynamically.

Your code will look something like this:

std::vector<ComplexNumber> nizKompl;

while(true) {
  cout << "Unesite novi kompleksni broj(realni imaginarni): ";

  if(cin >> re >> im){
    nizKompl.push_back({re,im});
  } else {
    cout << endl << endl;
    break;
  }
}

As already mentioned, using std::vector would be the right approach.

But wrt your exact question:

for(int i=0; i<brojUnesenih; ++i){
    delete nizKompl[i];
}

This is what causes the double delete, since you copy the same pointers to your new array and also delete them. When entering the first number, you'll create an array of size one and create an object. On the second number, you'll allocate a new array of size two, copy the first element over to the new array, but also delete it. And once you add the third element, you'll create a new array of size three, copy the first two pointers and again try to delete them, but the first pointer was already deleted.

It is unclear why you are not using the standard class std::vector and using pointers instead of objects themselves.

Nevertheless it seems you mean something like the following

#include <iostream>
#include <algorithm>
#include <memory>

struct ComplexNumber
{
    ComplexNumber() : ComplexNumber( 0, 0 ) {}
    ComplexNumber( int re, int im ) : re( re ), im( im ) {}
    int re;
    int im;
};

int main() 
{
    ComplexNumber **nizKompl = nullptr;
    size_t brojUnesenih = 0;
    bool unos;

    do
    {
        std::cout << "Unesite novi kompleksni broj(realni imaginarni): ";

        int re, im;

        if( ( unos = !!( std::cin >> re >> im ) ) )
        { 
            ComplexNumber **nizTemp = new ComplexNumber * [brojUnesenih + 1];

            std::copy( nizKompl, nizKompl + brojUnesenih, nizTemp );
            nizTemp[brojUnesenih] = new ComplexNumber( re, im );

            ++brojUnesenih;

            delete [] nizKompl;
            nizKompl = nizTemp;
        }
    } while ( unos );

    for ( size_t i = 0; i < brojUnesenih; i++ )
    {
        std::cout << "{ " << nizKompl[i]->re 
                  << ", " << nizKompl[i]->im
                  << " } ";
    }
    std::cout << std::endl;

    if ( nizKompl )
    {
        std::for_each( nizKompl, nizKompl + brojUnesenih, std::default_delete<ComplexNumber>() );
    }

    delete [] nizKompl;

    return 0;
}   

The program output might look like

Unesite novi kompleksni broj(realni imaginarni): 1 1
Unesite novi kompleksni broj(realni imaginarni): 2 2
Unesite novi kompleksni broj(realni imaginarni): 3 3
Unesite novi kompleksni broj(realni imaginarni): 4 4
Unesite novi kompleksni broj(realni imaginarni): 5 5
Unesite novi kompleksni broj(realni imaginarni): a
{ 1, 1 } { 2, 2 } { 3, 3 } { 4, 4 } { 5, 5 } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM