Deallocate memory allocated by C

Hi

Overview:

  • I have a C program that allocates memory to an array of integers
  • I am calling this program in Swift

Questions:

  • Am I deallocating the memory correctly or am I deallocating only the first element in the array ? Refer: box.array.deallocate()
  • If I am deallocating incorrectly could you point out what is wrong and how to fix it ?
  • Is this (using parameter with a pointer) a good way there a better way to receive values from C or there a better way ?

Thanks.

main.swift

func doSomething() {
    
    var box = Box()
    
    populateBox(&box)

    for index in 0 ..< box.count {
        
        let element = box.array[index]
        
        print("element = \(element)")
    }
    
    //1. Will the following deallocate all the allocated memory locations in array or just the first ?
    box.array.deallocate()
}

doSomething()

Box.h

#ifndef Box_h
#define Box_h

#include <stdio.h>

typedef struct {
    
    int *array;
    size_t count;
    
} Box;

void populateBox(Box *box);

#endif /* Box_h */

Box.c

#include "Box.h"
#include <stdlib.h>

void populateBox(Box *box) {
 
    //Assume n is a value known at runtime
    int n = 5;
    
    box->array = malloc(sizeof(int) * n);
    box->count = n;
    
    for (int index = 0; index < 5; index++) {
        box->array[index] = index * 10;
    }
}

The way you're deallocating the memory will probably work in practice (i.e. deallocates the entire array rather than the first element), but since malloc should generally be paired with free, it's better to call free instead in this particular case. Even better is to declare a freeBox(Box*) function in C and call that. This matters more in cases where e.g. the C source files are linked to a different C standard library than the Swift source – having the freeBox function in the same compilation unit as the allocation function makes sure both calls use the same allocation/deallocation routines.

Apart from having populateBox/freeBox (or equivalent) functions, the other common solution for C code is to let the caller allocate the memory. For example:

var itemCount: Int = 0
populateBox(nil, &itemCount)

// itemCount now contains the number of elements that array should have capacity for.
let array = UnsafeMutablePointer<Int32>.allocate(capacity: itemCount)
populateBox(array, &itemCount)

// Do something with array and itemCount
print(itemCount > 0 ? array[0] : .max)

array.deallocate()
3 Likes

You should definitely use free() if you use malloc() to allocate the memory. You should always appropriately pair your allocation/deallocation of memory.

On Apple devices and the Linux distros I have used Swift on, your code happens to work but is not guaranteed to work.

1 Like

@Torust and @Braden_Scothern Thanks a lot !!

After some reading understood the following:

When memory allocation is done, the actual heap space allocated is one word larger than the requested memory. The extra word is used to store the size of the allocation and is later used by free( )

@Torust I liked the suggestions regarding having a C function to free up the memory. I will try that.

In my case the number of elements is actually computed by the C program.

Question:

Is it common practice to declare box in swift and allow the C function to populate the contents of it (like what I am doing now) or pass a parameter of type **Box which the C program would initial use with a new box ?

There are two common patterns for “a C library has a type that needs to be created and initialised”.

The first is the one you started with: define the structure, and provide a type_init function. Yours is called populate, but the common C library practice would be init. This function is usually paired with a destroy or close or clean or equivalent, which must be called when the user is done with the type, and will free any state the library has associated with the object.

The advantages of this approach are that it allows structures to be stack allocated, avoiding unnecessary extra heap allocations. The downside is that it makes it almost impossible to evolve the API of the type, as you necessarily expose basically everything about the structure’s shape.

The other common approach is to define the type as an opaque structure, and then have a create function. This function will call malloc and return the allocated pointer. It is usually paired with a free function that should be called when the user is done with the type.

The advantage here is that the type is freely evolve able, can change shape and add/remove members. The downside is that code to work with the type is a bit more verbose, it looks ugly in Swift, and it forces extra heap allocations.

The third one (pass a **) is essentially never used: it’s just a more awkward way of returning a value than just returning it.

2 Likes

Thanks a lot @lukasa for the detailed answer.

In my scenario, I am wrapping this inside a Swift type, so this is only interaction with C. Also personally I felt more comfortable dealing with a known structure (UnsafeMutablePointer) rather than an OpaquePointer.

Thanks once again for detailing the advantages / disadvantages of each approach.

I initially started with returning a pointer I guess then realised could easily be ignored if not careful and would result in a memory leak. Then moved to a parameter instead.

Working with C really helped to understand memory management better and also appreciate how much Swift does to make it easier.