17. ADVANCED USES OF POINTERS. Dynamic Storage Allocation Many programs require dynamic storage...

21
17. ADVANCED USES OF POINTERS

Transcript of 17. ADVANCED USES OF POINTERS. Dynamic Storage Allocation Many programs require dynamic storage...

17. ADVANCED USES OF POINTERS

Dynamic Storage Allocation• Many programs require dynamic storage allocation: the ability to allocate storage as needed during program execution.

• Dynamically allocated storage may be used for any kind of data object.

• The objects most commonly allocated are:ArraysStringsStructures

• Dynamically allocated structures can be linked together to form lists, trees, andother data structures.

The malloc Function• The most important storage allocation function is named malloc. When called, malloc allocates a block of size bytes and returns a pointer to it:void *malloc(size_t size);

• malloc returns a “generic” pointer that is capable of pointing at an object of any type. malloc’s return value can be stored in a variable of any pointer type:int *pi;pi = malloc(sizeof(int)); /* allocate memory for an int */For portability, it is best to use sizeof when calling malloc .

• Memory allocated by malloc is not cleared.

The Null Pointer• When malloc cannot locate a memory block of the requested size, it returns a null pointer.

• The macro NULL represents the null pointer. It is defined in <locale.h>, <stdio.h>, <stdlib.h>, <string.h>, <stddef.h>, and <time.h>;

one of these must be included in any program that uses NULL.

• NULL actually stands for the value 0:#define NULL 0To avoid confusion with the integer 0, it’s usually best to use NULL instead of 0 to represent the null pointer.

The Null Pointer

• Since NULL is equivalent to 0, it tests false in if, while, do, and for statements:int *p;…if (p) … /* true if p is not NULL */

• It is illegal to apply the indirection operator to a null pointer:p = NULL;i = *p; /* illegal */

Dynamically Allocated Strings• malloc is often used to dynamically allocate space for strings.

• malloc is especially useful to allocate space for the result of a string operation:char *result;result = malloc(strlen(s1) + strlen(s2) + 1);strcpy(result, s1);strcat(result, s2);

• Warning: When using malloc to allocate space for a string, don’t forget to include room for the null character.

Dynamically Allocated Arrays• An array can be dynamically allocated by a call of the calloc function.calloc is similar to malloc, but allocates space for an array with nmemb elements, each of which is size bytes long:

void *calloc(size_t nmemb, size_t size);

• The block of memory allocated by calloc is cleared (set to 0 bits).

Dynamically Allocated Arrays• Example:int *a, size, i;printf("Enter array size: ");scanf("%d", &size);a = calloc(size, sizeof(int));printf("Enter array elements: ");for (i = 0; i < size; i++)scanf("%d", &a[i]);

• Warning: A program that uses malloc or calloc must include the following header file:#include <stdlib.h>

If this file is not included, calloc and malloc would be assumed to return int values, causing unpredictable effects.

The free Function• When a block of memory obtained by calling malloc or calloc is no longer referenced by a pointer, it is said to be garbage. In the following example, the memory pointed to by p becomes garbage when p is assigned a new value:

int *p, *q;p = malloc(sizeof(int));q = malloc(sizeof(int));p = q;

Garbage should be avoided; we need to “recycle” memory instead.

The free Function• When a block of memory is no longer needed, it can be released by calling the free function:int *p, *q;p = malloc(sizeof(int));q = malloc(sizeof(int));free(p);p = q;

• Warning: Watch for “dangling pointers” left behind by a call of free:int *p, *q;p = malloc(sizeof(int));q = p;free(p);*q = 0; /* error */

Linked Lists• Dynamic storage allocation is useful for building lists, trees, graphs, and other linked structures.• A linked structure consists of a collection of nodes. Each node contains one or more pointers to other nodes. In C, a node is represented by a structure.• The simplest linked structure is the linked list, which consists of a chain of nodes, with each node pointing to the next node in the chain. A node in a linked list might have the following definition:struct node {int data;struct node *next;};The use of a structure tag is mandatory, since the node structure contains a reference to itself.

Linked Lists• An ordinary pointer variable points to the first node in the list; to indicate that the list is empty, the variable can be assigned NULL:struct node *first = NULL;

The Right Arrow Operator

• Nodes can be created by calling malloc:struct node *temp;temp = malloc(sizeof(struct node));

• The . operator can be used to select the data member in the node that temp points to:(*temp).data = n;

• Because pointers often point to structures, C provides a special notation (the right arrow selection operator) for selecting members of these structures:temp->data = n;

Example: Inserting into a Linked List

• The following statements will create a node containing n, then insert it at the beginning of the list pointed to by first:

struct node *temp;temp = malloc(sizeof(struct node));temp->data = n;temp->next = first;first = temp;

Example: Inserting into a Linked List

• The following example creates a linked list containing numbers entered by the user:struct node *first = NULL, *temp;int n;printf("Enter a series of numbers (enter 0 to stop): ");scanf("%d", &n);while (n != 0) {temp = malloc(sizeof(struct node));temp->data = n;temp->next = first;first = temp;scanf("%d", &n);}The numbers will appear in the list in the reverse of the order in which they were entered.

Example: Searching a Linked List

• The following statement searches a list for an integer n:for (temp = first; temp != NULL; temp = temp->next)if (temp->data == n)… /* found n */

Example: Deleting from a Linked List

• The following statements will delete the first node containing n from the list pointed to by first, assuming that n is present in the list:struct node *p, *q;for (p = first, q = NULL;p != NULL && p->data != n;q = p, p = p->next);if (q == NULL)first = first->next; /* n is at the beginning */elseq->next = p->next; /* n is not at the beginning */free(p);

Functions Passed as Arguments

• C does not allow a function to be passed as an argument to another function. However, a pointer to a function can be passed:int find_zero(int (*f)(int));int poly(int i);int main(void){printf("Answer: %d\n", find_zero(poly));return 0;}int find_zero(int (*f)(int)){int n = 0;while ((*f)(n)) n++; /* or while (f(n)) n++; */return n;}int poly(int i){return i * i + i - 12;}

Functions Passed as Arguments

• Pointers to functions can be used in numerous other ways. For example:A function can return a pointer to a function.A variable can store a pointer to a function.An array may contain pointers to functions.

The qsort Function• Certain functions in the C standard library require a function pointer as a parameter.

One of the most commonly used is qsort, a general-purpose algorithm capable of sorting any array.

• The following declaration for qsort appears in <stdlib.h>:void qsort(void *base, size_t nmemb, size_t size,

int (*compar)(const void *, const void *));base is a pointer to the first element in the array.nmemb is the number of elements in the array.size is the size of each array element.compar is a pointer to a function that compares two array elements.

The qsort Function• When given two pointers p and q to array elements, compar must return a number that is

Negative if *p is “less than” *q.Zero if *p is “equal to” *q.Positive if *p is “greater than” *q.