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.

Deanie
  • 2,316
  • 2
  • 19
  • 35
Anton Daneyko
  • 6,528
  • 5
  • 31
  • 59

3 Answers3

5

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
  • 22,781
  • 4
  • 49
  • 67
  • +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 Jul 01 '10 at 13:47
3

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

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 1
    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 Jul 01 '10 at 13:49
  • 1
    There is a simple idiom that can be used to easily shrink vectors. http://stackoverflow.com/questions/586634/shrinking-a-vector/586682#586682 I agree with this answer. There is no reason to use realloc in C++. Use vectors. – Dragontamer5788 Jul 01 '10 at 20:32
  • @Dragontamer5788, correct me if I am wrong but won't the idiom and "shrink_to_fit" reallocate in the best case? (i.e. copy all the elements to a new location). – alfC Dec 15 '17 at 05:24
  • 1
    @alfC Wow, 7-year comment comes back to bite me, eh? Anyway, my understanding (today, 7-years after I wrote the above comment...)... is that std::swap probably won't shrink the vector. I'd expect std::swap to just swap the internal pointers of the vector around. I'd have to test this to be sure however... – Dragontamer5788 Dec 15 '17 at 06:53
2

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
  • 74,869
  • 16
  • 134
  • 187
  • 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. – Anton Daneyko Jul 01 '10 at 12:05
  • In general, does this try to keep `my_array` in the same location? – alfC Dec 15 '17 at 05:25