Transcript Lecture 17

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:
Arrays
Strings
Structures
• Dynamically allocated structures can be linked together to
form lists, trees, and
other 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 0
To 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 =
*p, *q;
malloc(sizeof(int));
malloc(sizeof(int));
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 */
else
q->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 generalpurpose 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.