Memory management in C programming

Published: Last Edited:

This essay has been submitted by a student. This is not an example of the work written by our professional essay writers.

[edit]Memory Management

In C, you have already considered creating variables for use in the program. You have created some arrays for use, but you may have already noticed some limitations:

§ the size of the array must be known beforehand

§ the size of the array cannot be changed in the duration of your program

Dynamic memory allocationin C is a way of circumventing these problems.


#include <stdlib.h>

void *calloc(size_t nmemb, size_t size);

void free(void *ptr);

void *malloc(size_t size);

void *realloc(void *ptr, size_t size);

The C functionmallocis the means of implementing dynamic memory allocation. It is defined in stdlib.h or malloc.h, depending on what operating system you may be using. Malloc.h contains only the definitions for the memory allocation functions and not the rest of the other functions defined in stdlib.h. Usually you will not need to be so specific in your program, and if both are supported, you should use <stdlib.h>, since that is ANSI C, and what we will use here.

The corresponding call to release allocated memory back to the operating system isfree.

When dynamically allocated memory is no longer needed,freeshould be called to release it back to the memory pool. Overwriting a pointer that points to dynamically allocated memory can result in that data becoming inaccessible. If this happens frequently, eventually the operating system will no longer be able to allocate more memory for the process. Once the process exits, the operating system is able to free all dynamically allocated memory associated with the process.

Let's look at how dynamic memory allocation can be used for arrays.

Normally when we wish to create an array we use a declaration such as int array[10];

Recallarraycan be considered a pointer which we use as an array. We specify the length of this array is 10ints. After array[0], nine other integers have space to be stored consecutively.

Sometimes it is not known at the time the program is written how much memory will be needed for some data. In this case we would want to dynamically allocate required memory after the program has started executing. To do this we only need to declare a pointer, and invoke malloc when we wish to make space for the elements in our array,or, we can tell malloc to make space when we first initialize the array. Either way is acceptable and useful. Previous Page|Next Page


Operating Systems


1. Introduction

2. Abbreviated Boot

3. The Boot Process

4. Startup and Run Levels

5. Initialization Scripts

6. Runlevel Scripts

7. Login Process

8. Bash Shell

9. Filesystems

10. LILO, Kernel and Root Filesystem

11. The Kernel

12. Passwords, Users, Groups, and Quotas

13. The Environment

14. The /etc/sysconfig directory

15. The /proc filesystem

16. Process Control

17. Devices

18. Daemons Services

19. Inetd and Network Services

20. Programs and Libraries

21. Security and PAM

22. The printer services

23. Mouse support with gpm

24. Mail

25. News

26. UUCP

27. LDAP

28. NFS and RPC

29. Samba, NetBIOS, WINS, nmbd

30. Identd (auth)

31. Telnet and FTP

32. Apache web server

33. DNS and named

34. How X Works

35. X Scripts

36. Support for Text

37. Keymapping for Programs

38. Keycode Table

39. Example Keymap File

40. Terminfo Commands

41. VT100 ESC sequences

42. Kernel Revisited

43. Configuration Files

44. Credits


Operating Systems


Linux Process management

Process control and the ability for inter process communication is handled by the Linux kernel.

Tools for working with processes

* accton - Turns process accounting on and off. Uses the file /var/log/pacct. To turn it on type "accton /var/log/pacct". Use the command with no arguments to turn it off.

* kill - Kill a process by number

* killall - Send a signal to a process by name

* lastcomm (1) - Display information about previous commands in reverse order. Works only if process accounting is on.

* nice - Set process priority of new processes.

* ps(1) - Used to report the status of one or more processes.

* pstree(1) - Display the tree of running processes.

* renice(8) - Can be used to change the process priority of a currently running process.

* sa(8) - Generates a summary of information about users' processes that are stored in the /var/log/pacct file.

* skill - Report process status.

* snice - Report process status.

* top - Displays the processes that are using the most CPU resources.

Process Scheduling

Computer time on Linux systems is allocated in jiffies. A jiffie is a microprocessor time slice. On most Linux systems it is 1/100 of a second. On some systems it is 1/1024 of a second. The Linux kernel controls process scheduling. There are three types of scheduling:

1. normal - Referred to as other, this is the scheduling type set for normal programs

2. FIFO - This is a real time scheduling priority. The FIFO term means the first process started (first in) will be the first done (first out). The only time this type of process exits is if it sleeps, is rescheduled, or if it must wait on other kernel priorities to be done.

3. RR - This is a round robin type of scheduling, where each task gets a certain amount of time then it must exit, yield control to the next task and get back into the task queue. This is a real time scheduling priority.

Linux processes have the following characteristics:

1. policy - normal or real time. Real time processes have a higher priority than normal processes.

2. priority - The process priority. It is a number between -20 and 19. The value of -20 is the highest, and 19 is the lowest priority. Process priority can be set with the nice(1) command and changed using the renice(8) command.

Inter-Process Communication

The types of inter process communication are:

1. Signals - Sent by other processes or the kernel to a specific process to indicate various conditions.

2. Pipes - Unnamed pipes set up by the shell normally with the "|" character to route output from one program to the input of another.

3. FIFOS - Named pipes operating on the basis of first data in, first data out.

4. Message queues - Message queues are a mechanism set up to allow one or more processes to write messages that can be read by one or more other processes.

5. Semaphores - Counters that are used to control access to shared resources. These counters are used as a locking mechanism to prevent more than one process from using the resource at a time.

6. Shared memory - The mapping of a memory area to be shared by multiple processes.

Message queues, semaphores, and shared memory can be accessed by the processes if they have access permission to the resource as set up by the object's creator. The process must pass an identifier to the kernel to be able to get the access.


Linux Signals are:

Signal Name





Hangup (POSIX)



Terminal interrupt (ANSI)



Terminal quit (POSIX)



Illegal instruction (ANSI)



Trace trap (POSIX)



IOT Trap (4.2 BSD)



BUS error (4.2 BSD)



Floating point exception (ANSI)



Kill(can't be caught or ignored) (POSIX)



User defined signal 1 (POSIX)



Invalid memory segment access (ANSI)



User defined signal 2 (POSIX)



Write on a pipe with no reader, Broken pipe (POSIX)



Alarm clock (POSIX)



Termination (ANSI)



Stack fault



Child process has stopped or exited, changed (POSIX)



Continue executing, if stopped (POSIX)



Stop executing(can't be caught or ignored) (POSIX)



Terminal stop signal (POSIX)



Background process trying to read, from TTY (POSIX)



Background process trying to write, to TTY (POSIX)



Urgent condition on socket (4.2 BSD)



CPU limit exceeded (4.2 BSD)



File size limit exceeded (4.2 BSD)



Virtual alarm clock (4.2 BSD)



Profiling alarm clock (4.2 BSD)



Window size change (4.3 BSD, Sun)



I/O now possible (4.2 BSD)



Power failure restart (System V)

As noted above, processes can ignore, block, or catch all signals except SIGSTOP and SIGKILL. If a process catches a signal, it means that it includes code that will take appropriate action when the signal is received. If the signal is not caught by the process, the kernel will take default action for the signal.


FIFOs are permanent objects and can be created using the mkfifo(1) or mknod(1) command. Inside the program, the FIFO can be created using the mknod command, then opened and read from or written to just like a normal file. The FIFO is normally in blocking mode when attempting to perform read operations.

We also need to know how much an int takes up in memory in order to make room for it; fortunately this is not difficult, we can use C's builtinsizeofoperator. For example, ifsizeof(int)yields 4, then oneinttakes up 4 bytes. Naturally,2*sizeof(int)is how much memory we need for 2ints, and so on.

So how do we malloc an array of tenints like before? If we wish to declare and make room in one hit, we can simply say

int *array = malloc(10*sizeof(int));

We only need to declare the pointer;mallocgives us some space to store the 10ints, and returns the pointer to the first element, which is assigned to that pointer.

Important note!mallocdoesnotinitialize the array; this means that the array may contain random or unexpected values! Like creating arrays without dynamic allocation, the programmer must initialize the array with sensible values before using it. Make sure you do so, too. (See later the functionmemsetfor a simple method.)

It is not necessary to immediately call malloc after declaring a pointer for the allocated memory. Often a number of statements exist between the declaration and the call to malloc, as follows:

int *array = NULL;

printf("Hello World!!!");

/* more statements */

array = malloc(10*sizeof(int)); /* delayed allocation */

/* use the array */

[edit]Error checking

When we want to usemalloc, we have to be mindful that the pool of memory available to the programmer isfinite. As such, we can conceivably run out of memory! In this case,mallocwill returnNULL. In order to stop the program crashing from having no more memory to use, one should always check that malloc has not returnedNULLbefore attempting to use the memory; we can do this by

int *pt = malloc(3 * sizeof(int));

if(pt == NULL)


fprintf(stderr, "Out of memory, exiting\n");



Of course, suddenly quitting as in the above example is not always appropriate, and depends on the problem you are trying to solve and the architecture you are programming for. For example if program is a small, non critical application that's running on a desktop quitting may be appropriate. However if the program is some type of editor running on a desktop, you may want to give the operator the option of saving his tediously entered information instead of just exiting the program. A memory allocation failure in an embedded processor, such as might be in a washing machine, could cause an automatic reset of the machine. For this reason, many embedded systems designers avoid dynamic memory allocation altogether.


Thecallocfunction allocates space for an array of items and initilizes the memory to zeros. The callmArray = calloc( count, sizeof(struct V))allocatescountobjects, each of whose size is sufficient to contain an instance of the structurestruct V. The space is initialized to all bits zero. The function returns either a pointer to the allocated memory or, if the allocation fails,NULL.


Thereallocfunction changes the size of the object pointed to byptrto the size specified bysize. The contents of the object shall be unchanged up to the lesser of the new and old sizes. If the new size is larger, the value of the newly allocated portion of the object is indeterminate. Ifptris a null pointer, thereallocfunction behaves like themallocfunction for the specified size. Otherwise, ifptrdoes not match a pointer earlier returned by thecalloc,malloc, orreallocfunction, or if the space has been deallocated by a call to thefreeorreallocfunction, the behavior is undefined. If the space cannot be allocated, the object pointed to byptris unchanged. Ifsizeis zero andptris not a null pointer, the object pointed to is freed. Thereallocfunction returns either a null pointer or a pointer to the possibly moved allocated object.


Memory that has been allocated usingmalloc,realloc, orcallocmust be released back to the system memory pool once it is no longer needed. This is done to avoid perpetually allocating more and more memory, which could result in an eventual memory allocation failure. Memory that is not released withfreeis however released when the current program terminates on most operating systems. Calls tofreeare as in the following example.

int *myStuff = malloc( 20 * sizeof(int));

if (myStuff != NULL)


/* more statements here */

/* time to release myStuff */

free( myStuff );


[edit]free with recursive data structures

It should be noted thatfreeis neither intelligent nor recursive. The following code that depends on the recursive application of free to the internal variables of astructdoes not work.

typedef struct BSTNode


int value;

struct BSTNode* left;

struct BSTNode* right;

} BSTNode;

// Later: ...

BSTNode* temp = (BSTNode*) calloc(1, sizeof(BSTNode));

temp->left = (BSTNode*) calloc(1, sizeof(BSTNode));

// Later: ...

free(temp); // WRONG! don't do this!

The statement "free(temp);" will *not* free temp->left, causing a memory leak.

Because C does not have a garbage collector, C programmers are responsible for making sure there is afree()exactly once for each time there is amalloc(). If a tree has been allocated one node at a time, then it needs to be freed one node at a time.

[edit]Don't free undefined pointers

Furthermore, usingfreewhen the pointer in question was never allocated in the first place often crashes or leads to mysterious bugs further along.

To avoid this problem, always initialize pointers when they are declared. Either use malloc() at the point they are declared (as in most examples in this chapter), or set them to NULL when they are declared (as in the "delayed allocation" example in this chapter).[1]

Previous: Pointers and arrays