CPSC 120 Lecture Notes, Wednesday, Feb 25, 1998

ASSIGNMENTS/ANNOUNCEMENTS

DYNAMIC MEMORY ALLOCATION

Java does dynamic memory allocation for you. That means that while your program is running, memory is assigned to the process as it is needed. This happens whenever you call "new" in Java -- the relevant space is allocated.

In Java there is strict distinction between primitive types and object types. Every variable is either of primitive type or object type (i.e., a reference).

In C, there is not the distinction between primitive types and object types. Every type has the possibility of being allocated statically or dynamically. To allocate it statically, you just declare a variable of the type, and the space is allocated when that function begins executing (and goes away when it finishes). You have to do a little more work to get space allocated automatically; and you have to do the bookkeeping yourself to get rid of the space.

To allocate space in C, there is a function called malloc.

For instance, to dynamically allocate space for an integer:
int* p;
p = (int*) malloc(sizeof(int));	/* cast the result to int* */
if (p == NULL) {		/* to be on the safe side */
    printf("malloc failed!");
} else {
    *p = 33;
    printf("%i", *p);
}
Normally, you don't need to allocate a single integer at a time. Typically, you would use malloc to:

You can allocate space for a structure like this: (Remember the struct Student which holds an int and a double.)

Student* sptr;
sptr = (Student*) malloc(sizeof(Student));
sptr->age = 20;
sptr->grade_point = 3.4;
*** draw memory diagram ***

ALLOCATING AN ARRAY DYNAMICALLY

To allocate an array dynamically, you will have a pointer into the memory allocated. To indicate the space, multiply the sizeof parameter to malloc with the desired number of entries in the array.
int i;
int* p;
p = (int*) malloc(100*sizeof(int));	/* 100 element array */
/* at this point, p points to the beginning of the array */
for (i = 0; i < 100; i++) 		/* initialize the array */
    p[i] = 0;				/* access the elements */

Similarly, you can allocate an array of structures:

int i;
Student* sptr;
sptr = (Student*) malloc(30*sizeof(Student));
for (i = 0; i < 30; i++) {
    sptr[i].age = 19;
    sptr[i].grade_point = 4.0;
}

ALLOCATING A LINKED LIST NODE DYNAMICALLY

Suppose you wanted to have a (singly) linked list of students. You could use these type declarations:
struct student {
    int age;
    double grade_point;
    struct student *link;	/* pointer to next student object */
}
typedef student Student;
Now you can allocate a node for the list:
Student* sptr;
sptr = (Student*) malloc(sizeof(Student));
And you can insert it after another node like this:
Student* cur;
/* Code to set cur to point to a node in a list goes here. */
/* Now insert the node pointed to by sptr after the node pointed to by cur: */
sptr = cur->link;	/* notice -> notation */
cur->link = sptr;
*** draw memory diagram ***

DEALLOCATING MEMORY DYNAMICALLY

When memory is allocated using malloc, it stays around until the program finishes, unless you get rid of it explicitly. You can get memory leaks because of this:
void sub() {
    int *p;
    p = (int*) malloc(100*sizeof(int));
    return;
}
Although the space for the pointer variable p goes away when sub finishes executing, the 100 ints do NOT go away! But they are completely useless after sub is done, since there is no way to get to them.

If you had wanted them to be accessible outside of sub, you would have to pass back a pointer to them:

int* sub() {
    int *p;
    p = (int*) malloc(100*sizeof(int));
    return p;
}

To deallocate memory when you are through with it, you call the function free. It takes as an argument a pointer to the beginning of a hunk of storage that was allocated dynamically, and returns nothing. The result of free is that all the space starting at the designated location will be returned to the operating system as available. The system keeps track of the size of this hunk of storage.

So in the above example, just before the return, you should say:

free(p);

DO NOT DO THIS! --

int *p;
p = (int*) malloc(100*sizeof(int));
p++;
free(p);
Now p is no longer pointing to the beginning of the allocated space.