Using the C Math Library    

Example - Managing Array Memory (ex2.c) 

This example program demonstrates how to write functions that use automated memory management. Apply this technique to every function you write.

This section presents an annotated example; Example Without Automated Memory Management shows comparable code that does uses explicit memory management.

Each of the numbered sections of code is explained in more detail below. You can find the code for the example in <matlab>/extern/examples/cmath/ex2.c where <matlab> represents the top-level directory of your installation. See Building Stand-Alone C Applications in Chapter 2 for information on building the examples.

The example is split into two parts. (In a working program, both parts would be placed in the same file.) The first part includes header files, declares two file static variables, and defines a routine that demonstrates how the library manages array memory. The second section contains the main program.

The numbered items in the list below correspond to the numbered comments in the code example:

  1. Include header files. matlab.h declares the mxArray data structure and the prototypes for all the functions in the MATLAB C Math Library.  stdlib.h contains the definition of EXIT_SUCCESS.
  2. Define the interface for your function. This function, Automated_Mem_Example(), takes two inputs and returns two outputs. It has one return value, one output array argument (mxArray **z_out), and two input array arguments (mxArray *x_in and mxArray *y_in). The definition of the function follows the MATLAB C Math Library calling conventions where output arguments precede input arguments. You can write functions that follow these calling conventions or implement your own.

    The body of Automated_Mem_Example() performs three calculations that illustrate how the library manages the memory allocated for the arrays. The first two calculations operate on the two input arguments; the third on two local arrays that store the results from the previous calculations. The function returns one result in the output argument and the other result as the return value from the function.

  1. Initialize the local variables to NULL or to valid arrays. result_local will be used to store the function's return value. q_local will be used in a local calculation.

  1. Call mlfEnterNewContext() to create a new memory context for your function. mlfEnterNewContext() is always paired with a call to mlfRestorePreviousContext(), which appears at the end of the function.

    The first integer argument, 1, specifies the number of output array arguments (not including the return value) passed to Automated_Mem_Example(); the second integer argument, 2, specifies the number of input array arguments. The arrays themselves (mxArray** for output arguments, mxArray* for input arguments), z_out, x_in, and y_in, are passed next, in the same order as they were passed to the function. You do not need to terminate the list with NULL. Note that mlfEnterNewContext() can take any number of arguments.

    mlfEnterNewContext() changes the state of any temporary input arrays from temporary to bound enabling them to persist for the duration of the function. If they are passed as input arguments to other functions, they are passed as bound arrays.

  1. The first calculation passes the input argument x_in to the MATLAB C Math Library functions mlfSin() and mlfCos(). These two calls return temporary arrays, which are passed to another library function, mlfPlus(). The temporary array returned from the call to mlfPlus() is then passed to the library function mlfSqrt().

    In this series of nested calls only the return from mlfSqrt() is assigned to a variable via the mlfAssign() function. That array, result_local, becomes a bound array. The temporary arrays returned from mlfSin() and mlfCos() and passed to mlfPlus() are automatically deleted by mlfPlus(); mlfSqrt() deletes the temporary array returned from mlfPlus().

  1. Calls to mlfAssign() now appear as frequently as the assignment operator (=). The array on the left-hand side of the assignment (the first argument to mlfAssign()) becomes a bound array and persists. You must explicitly delete it; the library does not.

    These calculations again illustrate the automated memory management provided by the library. If you do not want to keep the array returned from a library function, just nest the call as an argument to a function. The return from the call (a temporary array) will be deleted by the other function.

    In these calculations, q_local and z_out, are each the targets of an assignment statement. Both are marked as bound arrays. Since q_local is a local variable, it must be explicitly deleted within this function. z_out is an output array argument that will be explicitly deleted in the calling function.

    See Assigning Arrays to mxArray* Variables to learn how mlfAssign() determines whether to delete the contents of the target argument and whether to make a shared data copy of the source argument.

  1. Free any local, bound array variables. If you've assigned (by calling mlfAssign()) a value to any local variable that is an array, you must destroy it by calling mxDestroyArray().

  1. Call mlfRestorePreviousContext() to restore the memory context that existed prior to the function call. Supply the same arguments that you passed to mlfEnterNewContext().

    Before ending your function and returning a value, you must call mlfRestorePreviousContext() to reestablish the state (temporary or bound) of input arguments prior to the function call. Any input argument that becomes temporary is then deleted by mlfRestorePreviousContext(). If you fail to call mlfRestorePreviousContext(), your program will leak memory.

    If an input array is bound when it is passed to a function, it will never be destroyed automatically by that function or any function that it calls.

  1. Return a temporary array. mlfReturnValue() marks its argument as temporary. You must pass any mxArray* that your function returns to mlfReturnValue() before passing it to the return statement. If you forget this step, the automated memory management of the library will be disrupted for the variable that you return, and memory will leak.

The second section of code contains the main program.

The numbered items in the list below correspond to the numbered comments in the code example:

  1. Initialize any local array variables to NULL. MATLAB C Math Library functions that use automated memory management require that you initialize any output arguments to NULL or a valid array. For example, before you call mlfAssign(), you must initialize its first argument, an output argument, to NULL or a valid array. Note that if you pass a pointer to a valid array, the contents of that array will be deleted before the assignment to the output argument takes place.
  2. Pass 0 as the first and second argument to mlfEnterNewContext(), indicating that the main() routine does not have any array output or input arguments.
  3. Call mlfAssign() to assign the return from the MATLAB C Math Library function mlfDoubleMatrix() to the array variable mat0 (a pointer to an mxArray). mlfDoubleMatrix() returns a 2-by-3 temporary array initialized with the data contained in the static C array, real_data1. mat0 becomes a bound array and will persist until explicitly deleted.
  4. Call mlfAssign() to assign the return from a user-defined function to an array variable. Automated_Mem_Example() uses the automated memory management provided by the MATLAB C Math Library functions.

    mat0 is a bound array when it is passed as an input argument to Automated_Mem_Example(). The return value from mlfDoubleMatrix() is a temporary array. After the call to Automated_Mem_Example(), mat0 still exists; the temporary array has been deleted by Automated_Mem_Example().

  1. Print the arrays. mlfPrintMatrix() returns void rather than an array (mxArray *). Both mlfPrintMatrix() and mlfPrintf() use the installed print handling routine to display their output. Because this example does not register a print handling routine, all output goes through the default print handler. The default print handler uses printf. See the section Defining a Print Handler in Chapter 8 for details on registering print handlers.
  2. Free each local, bound array by calling mxDestroyArray(). Note that mxDestroyArray() can handle a NULL argument if you inadvertently pass a pointer to an array that has already been destroyed and set to NULL.
  3. End the function by calling mlfRestorePreviousContext(). Pass 0 as the first and second argument to indicate that main() has no input and output arguments.

    Output

When run, the program produces this output.


 Returning an Array Example Without Automated Memory Management