Ethical Hacking Programming, Blogging, Hosting, All Computer Software, PC Software Download, JAVA in hindi, HTML, PHP, C, C++, Free Learning, Software's Download, Technical Videos, Technical Tricks and Tips, How Make Money

Dynamic Memory Management in C programming Class 32

9.3 Dynamic Memory Management

Dynamic memory management is the responsibility of the application programmer, with virtually no help from the compiler. The programmer must keep track of various quantities such as object lifetimes, pointers to di erent memory locations, lengths of arrays, and so forth. Without good coding practices and careful implementation, dynamic memory can be a rich source of runtime errors which are often notoriously di cult to debug.

Consider, for example, the following function, which makes a copy of the string passed to it and returns a pointer to the copy.


1 char *string duplicate(char *s)

2 /* Dynamically allocate a copy of a string. User must remember to free this memory. */

3   {

4char *p = malloc(strlen(s) + 1); /* +1 for ’\0’ */

5return strcpy(p, s);

6   }


Notice that using dynamic allocation allows us to allocate exactly the right amount of memory to contain the string. The expression strlen(s)+1 is a common idiom for this operation with +1 to cater for the ’\0’ character. Notice, also, that the return value of strcpy() makes for a convenient return of the copy. However, this function is flawed because it fails to check the return value of malloc(), which, if NULL, will crash the program during the copy operation. A corrected version, adapted from [KR88, page 143], is shown below.


1 char *string duplicate(char *s)

2 /* Dynamically allocate a copy of a string. User must remember to free this memory.*/

3   {
4 char *p;

5

6p = (char *) malloc(strlen(s) + 1); /* +1 for ’\0’ */

7if (p != NULL)

8 strcpy(p, s);

9 return p;

10   }


This version detects NULL and passes it back to the calling function to perform error handling. While this function is internally correct, it still leaves the responsibility of freeing the dynamic memory to the caller.

char *s;

s = string_duplicate("this is a string");

...

free(s); /* Calling function must remember to free s. */

Neglecting the free(s) statement means that the memory is not released even when s goes out-of-scope, after which the memory becomes non-recoverable. This sort of error is known as a “memory leak”, and can accumulate large quantities of dead memory if the program runs for a long period of time or allocates large data-structures.

Some common errors related to dynamic memory management are listed below.

Dereferencing a pointer with an invalid address. If a pointer is not initialised when it is defined, it will contain an arbitrary value, such that it points to an arbitrary memory location. The result of dereferencing this pointer will depend on where it points (e.g., no e ect, intermittent strange values, or program crash). Writing to memory via an invalid pointer is known as “memory corruption”.

Dereferencing a pointer that has been freed. This is a special case of the previous error. Once a memory block is released by calling free(p), the pointer p is no longer valid, and should not be dereferenced.

Dereferencing a NULL pointer. This typically occurs because a system function returns NULL to indicate a problem and the calling function fails to implement appropriate checking. (For many compilers, dereferencing a NULL pointer is a simple bug to find as it causes the program to crash immediately, but this behaviour is not standard.)

Freeing memory that has already been freed. Passing a previously freed pointer to free() will cause the function to dereference an invalid address.

Freeing a pointer to memory that was not dynamically allocated. Memory that is not allocated on the heap, but on the stack or constant data area, say, cannot be released by free(). Attempting to do so will have undefined results.

Failing to free dynamically allocated memory. Dynamic memory exists until it is explicitly released by free(). Failing to do so results in a “memory leak”.

Attempting to access memory beyond the bounds of the allocated block. Out-of-bounds errors occur if arrays are not properly bounds checked. A particularly common problem is the “o -by-one” array indexing error, which attempts to access elements one-before-the-beginning or one-past-the-end of an array, due to indexing arithmetic being not quite correct.

Good programming practices exist avoid these memory management errors, and following these rules will greatly reduce the risk of dynamic memory related bugs.

Every malloc() should have an associated free(). To avoid memory leaks and memory corruption, there should be a one-to-one mapping of calls to malloc() and calls to free(). Preferably the call to free() should appear in the same function as the call to malloc() (rather than have one function return a pointer to dynamically allocated memory and expect the calling function to release it). Alternatively, one might write a create() function that allocates memory for an object and a companion destroy() function that frees it.

Pointers should be initialised when defined. A pointer should never hold an arbitrary value, but should be initialised with either a valid address or NULL, which explicitly marks a pointer as “points nowhere”.

Pointers should be assigned NULL after being freed. A pointer that has the value NULL cannot be accidentally freed twice, as free(NULL) has no e ect.

free(p);

p = NULL;

...

free(p); /* OK, no effect. */





Share:

No comments:

Post a Comment

Follow On YouTube