0

I am working on a hashtable data structure, and I've come across a problem with a memory leak. Basically I have this code:

int main(int argc, char const *argv[])
{

        // -----------------------------+
        // record 0                     |
        // -----------------------------+
        rec_t *r = malloc(sizeof(rec_t));
        r->key = "name";
        r->value = "evgeny";
        // -----------------------------+

        // -----------------------------+
        // record 1                     |
        // -----------------------------+
        rec_t *r2 = malloc(sizeof(rec_t));
        r2->key = "lastName";
        r2->value = "Danilenko";
        // -----------------------------+

        // -------------------------------+
        // dictionary struct              |
        // params :     uint length       |
        //              rec_t **records   |
        // -------------------------------+
        dct_t* dict = malloc(sizeof(dct_t));
        dict->records = malloc(sizeof(rec_t*) * 20);

        dict->records[0] = r;
        dict->records[1] = r2;


        // free(dict->records[0]);      // DONT WANT TO DO THIS! O(n)
        // free(dict->records[1]);

        free(*dict->records);            // clears only 1st element cuz pointer
        free(dict->records);
        free(dict);

        return 0;
}

How would I got about free()'ing all of the elements with 'one shot'? I had a look a this link but it didn't help - How to free a struct that contains only pointers

I want to emphasise that I don't want to loop through all the elements and freeing the one-by-one.

Community
  • 1
  • 1
Evgeny Danilenko
  • 181
  • 2
  • 10
  • 1
    You can't. Apparently you `malloc` multiple blocks, so you have to `free` each block. But as you have fixed width inner arrays, Why don't you use a 2D array in the `struct` itself? – too honest for this site Dec 22 '16 at 20:02
  • The lazy way, if you never have to `free` and `malloc` more memory in a dynamic way, is not to `free` any of it, and let the memory be handed back to the system at program exit. – Weather Vane Dec 22 '16 at 20:12
  • 1
    Thats bad. Cuz memory leak. – Evgeny Danilenko Dec 22 '16 at 20:13
  • Not on my system. All the memory allocated is given back to the OS. But as I said, won't work in a dynamic situation. – Weather Vane Dec 22 '16 at 20:17
  • Oh sorry I miss-interpreted what you've said. Yea i know that non-dynamically allocated memory is give back to the system, as the things allocated on the stack will be completely gone when the stack frame is 'destroyed'. this is not ideal for me as I need to hold references to memory addresses which will contain garbage data after the function is returned. – Evgeny Danilenko Dec 22 '16 at 20:23
  • I wasn't talking about local automatic allocations on the stack. Typically `malloc` memory is allocated from the heap. My first comment was a throw-away remark, about how the system handles memory allocation. By "dynamic" I meant memory needing to be freed and more allocated as an ongoing process. If you simply need to allocate memory for the requirements, you can just let it go. But it's lazy. – Weather Vane Dec 22 '16 at 20:25
  • @WeatherVane: Not freeing allocated memory is bad programming style. And tools like Valgrind will report that correctly as leaks. – too honest for this site Dec 22 '16 at 20:57
  • Possible duplicate of [How to free a struct that contains only pointers](http://stackoverflow.com/questions/4915369/how-to-free-a-struct-that-contains-only-pointers) – Random Davis Dec 22 '16 at 20:58
  • @Olaf yes, I did say it was lazy. The automatic variables were not my idea, but a mis-read by the OP. – Weather Vane Dec 22 '16 at 20:58
  • You must do so iteratively. – David Hoelzer Dec 22 '16 at 20:59

2 Answers2

4

I don't want to loop through all the elements and freeing the one-by-one.

Too bad.

If you allocated them with separate calls to malloc, you have to free them with separate calls to free.

The alternative is to use something like apr_pool_t from LibAPR, which is a pool allocator which lets you free the entire pool at once. But this is a rather drastic solution to a simple, ordinary problem.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
1

Short answer:

There's no default way of one-shot approach, you have to call free() on all the pointers returned by memory allocator function (whether you like it or not.)

Elaborate:

You can , however, alter the data structure to include a member to hold the number of allocation calls, and use the value to allocate (and deallocate) the memory, in a loop. Something like

 dict->numRecords = n;

 // allocate, use, something else......

 for (int i = 0; i < dict->numRecords; i++)
      free (dict->(records[i]) );

Point to note, you are freeing the elements one-by-one in the later approach, too, we're just making the code concise using the loop.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • hmm thats an interesting thought. Although that would work if the stored records were stored sequentially. which is not the case with a hash table. the index i've given where just for testing. i have hashing function which hashes the keys and stores them in the respected index. i.e. 'asd' = 23 – Evgeny Danilenko Dec 22 '16 at 20:04
  • 1
    I can store the used indices in an array and loop through it though. I am going to do that, I think. – Evgeny Danilenko Dec 22 '16 at 20:10