1

Hi I'm pretty new to C++ and I need to dynamicacally allocate two-dimensional array. No error but in runtime when I set a order and first row then I get a runtime error: "Segmentation Fault"...Here's code:

#include <iostream>

using namespace std;

double ** allocateDynamicArray(int &order){
    double ** arr = new double *[order];
    for(int i = 0;i < order; i++){
            *arr = new double[order+1];
    }
    return arr;
}
void deallocateDynamicArray(double **arr, int order){
    for(int i=0; i<order; i++){
        delete [] arr[i];
    }
    delete [] arr;
}

void addAndPrintArray(double **arr, int order){
    cout << "Zadejte prvky pole radu " << order << endl;
    for(int i=0; i< order; i++){
        for(int j=0; j< order+1; j++){
            cout << "Pole[" << i << "][" << j << "]: ";
            cin >> arr[i][j];
        }
    }

    for(int i=0; i< order; i++){
        for(int j=0; j< order+1; j++){
            cout << arr[i][j] << " ";
            if(arr[i][j] < 10 && arr[i][j] > -10){
                cout << " ";
            }
            cout << endl;
        }
    }
}
int main()
{
    int order;
    cin >> order;
    double **dynArray = allocateDynamicArray(order);
    addAndPrintArray(dynArray, order);
    deallocateDynamicArray(dynArray, order);
    return 0;
}
6
  • 2
    You're almost certainly better off using a vector<vector<double>>. Much less complicated to work with, since there are no allocation/deallocation headaches. Commented Dec 11, 2014 at 14:28
  • *arr = should be arr[i] = Commented Dec 11, 2014 at 14:34
  • Yeah but what if I want to use this? I just need to know what's bad in this code... Commented Dec 11, 2014 at 14:34
  • One reason why you shouldn't use this is that there is no check to see if new[] fails anywhere in that loop. If it fails, you have a memory leak due to new[] throwing an exception. Commented Dec 11, 2014 at 14:41
  • Ok, so I just need to use this: arr[i] or rather always use vectors? Commented Dec 11, 2014 at 14:44

2 Answers 2

4

You forgot to increment arr in your initialization loop:

for(int i = 0;i < order; i++){
     *arr = new double[order+1];

Do this instead:

for(int i = 0;i < order; i++){
     arr[i] = new double[order+1];

Also, unless your going to change the dimensions of one of the rows, the method above is inefficient compared to this way of allocating a 2 dimensional array:

double ** allocateDynamicArray(int &order){
    double ** arr = new double *[order];
    int cols = order+1;
    double *pool = new double [order * cols];
    for(int i = 0;i < order; i++, pool += cols){
           arr[i] = pool;
    }
    return arr;
}

void deallocateDynamicArray(double **arr){
        delete [] arr[0];
        delete [] arr;
    }

Just two calls to new[] and only two calls to delete[] are needed, regardless of the number of rows and columns.

The other reason why the second form above should be favored over the first form is in the case where new[] may throw an exception.

Using the first form, if somewhere in that loop, new[] throws an exception, you have to keep track of all of the previous successful allocations, and "roll them back" by issuing delete[] calls. Not nice.

Using the second form, if the first call to new[] fails, then there is no harm as the exception will be thrown without leakage (since no memory was successfully allocated). If the second call to new[] fails, all you need to do is to provide (inside of a catch block) the deletion of the first call to new[].

double ** allocateDynamicArray(int &order) {
    double ** arr = new double *[order];
    int cols = order+1;
    try {   
       double *pool = new double [order * cols];
    }
    catch (std::bad_alloc& e)
    {
       delete [] arr;  // delete previous allocation
       return nullptr;  // or rethrow the exception here
    }
    for(int i = 0;i < order; i++, pool += cols)
        arr[i] = pool;
    return arr;
}

Note that std::vector does all of this work for you. However if for some reason you can't use vector, and the two dimensional array will remain the same size throughout its lifetime, use the second form.

In addition, the second method lessens memory fragmentation of the heap. Instead of rows calls to the allocator, only one call is made to the allocator to allocate the data. If rows were, say 1,000 or 10,000, you see right away it is better to make 2 calls to new[] instead of 10,000 calls to new[].

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that's what I want. :D
2

Replace

double ** arr = new double *[order];
for(int i = 0;i < order; i++){
        *arr = new double[order+1];

with

double ** arr = new double *[order];
for(int i = 0;i < order; i++){
        arr[i] = new double[order+1];

In your present code you initialize only first array element.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.