views:

134

answers:

3

In a program I allocate a huge multidimensional array, do some number-crunching, then only the first part of that array is of further interest and I'd like to free just a part of the array and continue to work with the data in the first part. I tried using realloc, but I am not sure whether this is the correct way, given I must preserve the data in the array and preferably avoid copying of that chunk in memory.

#include <cstring>
#include <cassert>
#include <iostream>

using namespace std;

void FillArrayThenTruncate(char* my_array, const int old_size, int* new_size);

int main() {
    const int initial_size = 1024*1024*1024;
    char* my_array = static_cast<char*>(malloc(initial_size));
    assert(my_array);
    int new_size;
    FillArrayThenTruncate(my_array, initial_size, &new_size);
    for(int i = 0; i < new_size; ++i) cout << static_cast<int>(my_array[i]) << endl;
}

void FillArrayThenTruncate(char* my_array, const int old_size, int* new_size) {
    //do something with my_array:
    memset(my_array, 0, old_size);
    for(int i = 0; i < 10; ++i) my_array[i] = i % 3;
    //cut the initial array
    *new_size = 10;
    void* new_array = realloc(my_array, *new_size);
    cout << "Old array pointer: " << static_cast<void*>(my_array) << endl;
    cout << "New array pointer: " << new_array << endl;
    my_array = static_cast<char*>(new_array);
    assert(my_array != NULL);
}

UPDATE:
* Please do not bother to suggest to use STL. The question is about C array.
* Thanks to "R Samuel Klatchko" for pointing out the bug in the code above.

+4  A: 

I assume you're using this for learning... otherwise I'd recommend you look into std::vector and the other STL containers.

The answer to the title question is No. You have to either compact the existing elements, or you need to allocate new space and copy the data you want. realloc will either extend/contract from the end or allocate new space and copy the existing data.

If you're working with such a large data set, you might as well just have a collection of chunks rather than a monolithic set. Maybe avoid loading the whole thing into ram to begin with if you only need certain parts.

Cogwheel - Matthew Orlando
+1 for suggesting a collection of chunks. This can be particularly useful if you can know in advance how much you're going to want to preserve. Then, you can have two chunks, and just throw away the second half when you're done with it. You trade a slight penalty when accessing individual elements for a guarantee that there's no extraneous allocations/moves later.
Dennis Zickefoose
+2  A: 

Yes, if you allocate with malloc, you can resize with realloc.

That said, realloc is allowed to move your memory so you should be prepared for that:

// Only valid when shrinking memory
my_array = realloc(my_array, *new_size);

Note that if you are growing memory, the above snippet is dangerous as realloc can fail and return NULL in which case you will have lost your original pointer to my_array. But for shrinking memory it should always work.

R Samuel Klatchko
Thank you for the correction -- I was too inattantive reading the funciton description and thought, that realloc will modify my_array, while it happen to return a new value.
mezhaka
+2  A: 

For C++, use STL containers instead of handling your memory manually. For C, there is realloc().

DevSolar
Given the specific problem he asked for help with, nothing in the standard library would really help out of the box. Vectors don't shrink, they only grow.
Dennis Zickefoose
There is a simple idiom that can be used to easily shrink vectors. http://stackoverflow.com/questions/586634/shrinking-a-vector/586682#586682I agree with this answer. There is no reason to use realloc in C++. Use vectors.
Dragontamer5788