Static vs. Dynamic Allocation
- "Static" allocation of space is straightforward, with variables or arrays declared locally or globally.
char myarray[1000];
char *ptr=0;
for (ptr=myarray; (ptr-myarray) < 1000; ptr++)
// do something with each entry of myarray
Dynamic allocation asks the OS for space for the pointer to access
#include <stdlib.h>
char *myarray=0;
char *ptr=0;
myarray = (char *)malloc(1000); // ask for 1000 Byte block
for (ptr=myarray; (ptr-myarray) < 1000; ptr++)
// do something with each entry of myarray
Note the cast from malloc() -- this is because malloc returns void *
calloc()
- Another variation of malloc() is calloc(3c)
#include <stdlib.h>
int *ptr = (int *)calloc(sizeof(int), 10000);
if (!ptr) {
printf("Calloc() failed in myfunc, exiting.\n");
exit(-1);
}
Works much like malloc, except contents are cleared (set to 0) first.
Essential to remember that malloc/calloc can fail -- not all memory requests will succeed, and so you must check to be certain the result is not null.
Potential Problem
int myfunc(void) {
int *ptr = (int *)malloc(10000 * sizeof(int));
if (!ptr)
exit(-1);
[some computation using space in ptr]
return ptr[0];
}
Important to realize that allocated space persists, even if no
pointers point to it. (C does not have automatic garbage collection.)
Nothing "potential" here -- this is definitely a problem.
Returning memory
- Eventually, the space allocated via malloc may no longer be useful to your program. Perhaps
- the program is shutting down
- the pointer to the data is going away
- you want to be able to continue to allocate memory in the future
Returning memory
- Memory that has been malloc()ed is returned to the OS via free(3c)
#include <stdlib.h>
int *ip = (int *)malloc(1000 * sizeof(int));
...
free(ip);
ip = 0;
Note the null pointer assignment.
Note also that free() will succeed even if you
- free memory that was already free()d
- free random memory locations that were never malloc()ed
but either one will eventually cause your program to crash!
realloc()
- Even at run-time you may not know the size needed for allocation.
- realloc(3c) allows you to change the size of your allocation.
- Needs current pointer, new size (larger or smaller)
int *newp=0, *ip=0;
ip = (int *)malloc(100 * sizeof(int));
// check success
...
newp = (int *)realloc(ip, 200 * sizeof(int));
if (newp != NULL)
ip = newp;
else {
printf("out of memory\n");
/* exit or return */
/* but ip still points at 100 ints */
}
malloc/calloc/realloc all return a contiguous block.
If the space does not exist to match the request,
realloc will not change the contents and returns a NULL pointer.
Automatic array expansion
- Consider the design of a function expand()
- When a passed in (malloc'd) array is full, we want to make it larger
- Might want to double its size so we don't have to do this often
- Certainly can use realloc(ptr, 2 * oldsize)
- What does the rest of the function look like?
Need to use pointers to pointers!
Code review of rdice.c
- If we have time, let's look at what you did in lab on Wednesday.