System Heap

ECE 103 Engineering Programming
Chapter 47
Dynamic Memory Alocation
Herbert G. Mayer, PSU CS
Status 8/1/2016
Initial content copied verbatim from
ECE 103 material developed by
Professor Phillip Wong @ PSU ECE
Syllabus





Memory Allocation Functions
Creating a 1-D Array at Runtime
Creating a 2-D Array at Runtime
calloc, malloc, free
Dangers
Memory Allocation Functions

The size of arrays must be known at compile-time
(C90 limitation only; C99 supports variable length
arrays: VLAs).

A C program can also make a request at runtime for
a memory block of arbitrary size.

If the memory block is no longer needed, the system
can be told to release the memory.

To use C’s memory allocation functions, add
#include <stdlib.h> to the source file.
2
calloc
void * calloc( size_t N, size_t bsize );
Allocates a block of memory from the heap at runtime to use for
data storage.





Block can contain N items, each of size bsize.
Block is initialized to zero.
If successful, returns a pointer to the allocated memory.
If unsuccessful, returns the NULL value.
Storage persists until explicitly freed or the program terminates.
Example: Create a block of storage for 512 integers at runtime.
int *p;
p = (int *) calloc( 512, sizeof(int) );
3
malloc
void * malloc( size_t bsize );
Allocates a block of memory from the heap at runtime to use for
data storage.





Block is of size bsize.
Block is not initialized to zero (i.e., indeterminate values).
If successful, returns a pointer to the allocated memory.
If unsuccessful, returns the NULL value.
Storage persists until explicitly freed or the program terminates.
Example: Create a 1024 character memory block at runtime.
char *q;
q = (char *) malloc( 1024 * sizeof(char) );
4
realloc
void * realloc( void *p, size_t bsize );
Changes the size of a previously allocated memory block.
p is a pointer to the existing block.
 bsize is the desired new size.
 If successful, returns a pointer to the resized block.
 If unsuccessful, returns the NULL value.

Example:
Suppose p points to a 1024 char block created by malloc.
Change the new block’s size to 2048.
p_new = (char *) realloc( p, 2048*sizeof(char) );
5
free
void * free( void *p );
Releases memory that has been previously allocated by calloc(),
malloc(), or realloc() back to the heap.
p is a pointer to the existing block.
 If p is NULL, then free does nothing.

Example:
Suppose p points to a dynamically allocated memory block.
The storage is no longer needed, so free up the memory.
free( p );
6
Potential Dangers …
Dynamically allocated memory exists until it is released
by free(), or until the program terminates.
pointer “loses track” of a memory block, and
there are no other pointers still tracking that block,
then the block becomes inaccessible.
 If a
 Inaccessible
blocks still continue to use memory for
as long as the program is running (memory leak).
 Long
running programs can abort due to too many
memory leaks!
7
mem…
void * memset( void *ptr, int value, size_t num );
Sets first num bytes of the memory block pointed by ptr to the specified value.
void * memcpy( void *dst, const void *src, size_t num );
Copies the values of num bytes from the location pointed by src to the memory block
pointed by dst. No overlap is allowed. Returns dst.
void * memmove( void *dst, const void *src, size_t num );
Copies the values of num bytes from the location pointed by src to the memory block
pointed by dst. Overlap is allowed. Returns dst.
int memcmp( const void *ptr1, const void *ptr2, size_t num );
Compares the first num bytes of the memory block pointed by ptr1 to the first num
bytes pointed by ptr2. Returns zero if equal, or non-zero otherwise.
void * memchr( const void *ptr, int value, size_t num );
Searches within the first num bytes of the memory block pointed by ptr for the first
occurrence of value. If found, returns pointer to location, or NULL otherwise.
8
Creating a 1-D Array at Runtime

When declaring a normal array variable, the size of
the array must be specified at compile-time (C90).

Using dynamic memory allocation, an array can be
created whose size is determined at runtime.

The size of the desired block must be passed to
either calloc() or malloc().

The sizeof() operator can determine the block
size (in bytes) of a given datatype.
9

The pointer returned by calloc() or malloc()
must be cast to the correct datatype.

After allocation, the pointer should always be
tested for not being equal to NULL!

The allocated array can be accessed using array
notation.

A memory block should be freed when it is no longer
needed.
10
Example:
Create a 1-D array at runtime that holds 10 elements of
datatype float.
float *A;
Pointer to the allocated memory block
that will hold the 1-D array values.
A = (float *) calloc( 10, sizeof(float) );
Casts the pointer
returned by calloc()( to
the correct datatype
Desired 1-D
array size
Calculates size
of datatype
(in bytes)
Desired
datatype
11
Example:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{ //main
float *A;
int R;
int i;
/* Pointer to 1-D array
/* Size of the array */
/* Index */
*/
printf( "Enter size of the array: " );
scanf( "%d", &R );
// entering 5
/* Create the array at runtime */
if( ( A = (float *) calloc( R, sizeof(float) ) ) == NULL ) {
printf("Error: Could not allocate memory block.\n" );
exit(0 );
} //end if
/* Can now access using array notation */
for( i = 0; i < R; i++ ) {
A[i] = (float) i;
} //end for
free(A );
/* Free up the block */
return 0;
} //end main
12
Suppose the entered array size is R = 5 and the system uses
64 bit pointers and 32 bit single-precision float values.
Assume that calloc() returns 2000 as the start address of
the allocated memory block.
A→
Index
Address
Contents
0
2000
0.0
1
2004
1.0
2
2008
2.0
3
2012
3.0
4
2016
4.0
13
Creating a 2-D Array at Runtime

Creating a 1-D array using runtime memory
allocation requires a single level of indirection
(e.g., double *).

To create a 2-D array, two levels of indirection are
required (e.g., double **).
In other words, a pointer to a pointer is required.

14

The 2-D array is created in two phases:


The rows are created first. The return value is a
pointer to a pointer.
For each row, columns are created. The return value
in each case is a pointer.

The pointers should always be tested for NULL!

The block is released in reverse order, i.e., the
columns are freed first and then the rows.
15
Example:
Create a 2-D array (size: 5 rows by 3 columns) at runtime
that holds elements of type float.
float **A;
Pointer to the allocated row block that
contains pointers to the column blocks
/* Create array of pointers to the rows */
A = (float **) calloc( 5, sizeof(float *) );
/* Create the rows */
for( i = 0; i < 5; i++ ) (
A[i] = (float *) calloc( 3, sizeof(float) );
} //end for
16
Example:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{ //main
float **A;
int R = 5, C = 3;
int i, j;
/* Pointer to 2-D array */
/* Row and column sizes of the array */
/* Row and column indices */
/* Create the rows of the 2-D array */
if( ( A = (float **) calloc( R, sizeof(float *) ) ) == NULL ) {
printf("Error: Cannot allocate memory block.\n" );
exit( 0 );
} //end if
/* For each row, create the columns */
for( i = 0; i < R; i++ ) {
if( ( A[i] = (float *) calloc( C, sizeof(float) ) ) == NULL ) {
printf("Error: Cannot allocate memory block.\n" );
exit( 0 );
} //end if
} //end for
/* Can now access using array notation */
for( i = 0; i < R; i++ ) {
for( j = 0; j < C; j++ ) {
A[i][j] = i+j; // note 2 levels of indirection; better via [][]
} //end for
} //end for
for( i = 0; i < R; i++ ) {
free( A[i] );
/* Free up the columns a row at a time */
} //end for
free( A ); /* Free up the rows */
return 0;
} //end main
17
Suppose that R = 5, C = 3 and the system uses 64 bit pointers and 32 bit
float values.
Assume calloc returns 2000 as the start address of the row block.
Suppose that when creating columns, calloc returned 3000, 3012,
3024, 4000, and 4012 for the start addresses of the column blocks.
A→
0
1
2
Column
index
3000
3004
3008
Address
Row
Index
Address
Contents
0.0
0.0
0.0
0
2000
3000
3012
3016
3020
1
2008
3012
0.0
1.0
2.0
3024
3028
3032
2
2016
3024
0.0
2.0
4.0
3
2024
4000
4000
4004
4008
0.0
3.0
6.0
4
2032
4012
4012
4016
4020
0.0
4.0
8.0
Note: The non-contiguous allocation may be inefficient. Some prefer
using a 1-D allocated block and manually calculating 2-D offsets.
18
C99
VLA vs. Dynamic memory allocation
What are some pros and cons of using C99’s variablelength arrays versus dynamic memory allocation?
+ VLAs are easy to define
+ No pointers to create
+ Automated memory management (no need to free)
− VLAs are stored on the stack
→ Stack size is limited. Large VLA may overrun space.
− Not portable to all compilers
19