Search code examples
cdesign-patternsfunction-parameter

How to hint users to do the allocation in out parameter?


Assum I have some pure C code like this.

It is not the real code, just for an example.

struct Param {
  struct InParam {
    int a;
    int b;
  } in; 
  struct OutParam {
    int *c;
  } out;
};

void MakeArray(struct Param *param) {
  // just for filling the output param
  for (int i = 0; i < param->in.a; ++i) {
    param->out.c[i] = param->in.b;
  }
}

int main() {
  int *p = NULL;
  special_memory_alloc(&p, sizeof(int) * 3));  // assume never failed

  struct Param param = { {3, 4}, {p} };  
  MakeArray(&param);

  special_memory_free(p);
}

The function MakeArray could within an independent module. I need the caller (eg. main in this example) allocate the memories in out param for me.

So is there some way to hint users to do the allocation for the output param?


Solution

  • This design seems a bit confused about allocation overall. The struct you pass to MakeArray is passed by value, so it's just a local copy stored on the stack and not the memory allocated. Though as it happens, it has a copy of the pointer c pointing at the allocated heap memory.

    Some rules of thumb you should follow:

    • Never pass structs by value. Always by reference through a pointer.
    • The one who allocates memory for an item is also the one responsible for freeing it. Don't "outsource" allocation/clean-up to the user of your library, that's very bad design.
    • Memory allocation should ideally be encapsulated with the functions handling the struct. This could be referred to as an "abstract data type" (ADT) or a "class" if you prefer OO terminology - it boils down to similar things. A "constructor" function and a "destructor" function. Since C doesn't support automatic calls of constructors/destructors (RAII), they have to be called manually. But C programmers are used to expect such, so it's not a problem.
    • Keep in mind that if there's a need to implement a destructor, there's likely also a need to implement some manner of copy function. Similar to the C++ "rule of three" if that's familiar.

    The professional way to implement this would be through so-called opaque type. Examples of how to do that can be found here: How to do private encapsulation in C?