Consider a variable v of particular data type. During the execution, v is allocated memory cells to store the data values. The number of memory locations required to store a variable will depend on the type of the variable. Thus a single character may be stored in one(1) byte, whereas a floating point number may take 4 contiguous bytes. The address of vs memory location is denoted by an expression &v. This is sometimes called left value of v (l_value v). The actual value of v is called the right value of v (r_value v).
A variable p is called a pointer to v, if it points to the location where v is stored.
The syntax for declaring a pointer variable is,
*
Example 9.1 :
int v;
int *p; /* pointer to an integer*/
The following statement, assigns the address location of the variable v to p, and p is a pointer to v.
p=&v;
Since a pointer variable points to a location, the content of that location is obtained by prefixing the pointer variable by the unary operator * (also called the indirection or dereferencing operator) like, *
Example 9.2 :
int u,v=9;
int *pi;
pi=&v; /* pi points to the location of v */
u=*pi; /*assigns the value 9 to u, the content of the location pointed to by pi i.e. the r_value of v */
A pointer may be assigned (or initialised) a ‘null’ value, when it does not point to any other data item.
The unary operators & and * have same precedence as the other unary operators -, --, +, ++, !, sizeof and
REMARK :
The address operator & can be applied to an operand which has unique address e.g. to variables or single array elements. It cannot be applied to arithmetic expressions.
The indirection operator * can be applied to operands that are pointers e.g. pointer variables. However, if pi points to v, that is, pi=&v, then in an expression *pi and v can be used interchangeably.
Example 9.3 :
/* to show indirection operator usage */
int v=3;
int *pi;
pi=&v;
*pv=0; /* resets v indirectly */
9.1 OPERATIONS ON POINTERS
A pointer can be made to point different locations in the memory by performing operations such as adding or subtracting integer quantity to or from a pointer variable. The pointer shifts (due to such operation) to a new location. The new location is determined by adding or subtracting (depending on the operator used in the operation) the product of the offset (integer quantity indicating the extent of shift) and the scaling factor associated with the datatype of that pointer. Consider the following example :
Example 9.4 :
#include
main()
{
static int j[5]={1,3,5,7,9};
int *k; /* defines a pointer to an integer*/
k=j; /* now k points to same location address stored in j i.e the address of the first element in the array (&j[0] which holds the value 1)*/
k=k + 3;
:
}
The statement k=k+3; will increment the pointer k so that the pointer k would point to a new location which can be computed using the following calculation.
new position of k =(old position of k) + (offset * scaling factor)
Since k is a pointer to an integer (which typically occupies 4 bytes in memory), the scaling factor becomes 4. The offset or the integer quantity is added to k in the operation is 3. So by substituting the values in places we finally get,
k=k + (3 * 4);
means k is incremented by 12 bytes or pointing to the new location address &j[3] which stores the value 7.
The following operations on pointers are not allowed.
1. Addition of two pointers.
2. Multiplying a pointer with a number
3. Dividing a pointer with a number.
9.2 MORE ABOUT POINTER ARITHMETIC
Here, we illustrate the usage of increment/decrement (++/--) and dereferencing operator (*) in implementing pointer arithmetic. The ++, -- and * operators fall in the same precedence group and their associativity is right to left. Consider the following array declaration for evaluating the results of the expressions that involve pointer arithmetic,
int arr[4]={1,2,3,4};
int *ip;
ip=arr; /*ip points to the first element in the array */
All the expressions listed below are assumed to be the statement immediately following the previous statement (i.e. ip=arr;).
Expression | Evaluation |
++ip | ip points to the second element in the array |
--ip | ip points back to the element 1 again |
++*ip | since operators are associated right to left, the * ip operation is considered first and then ++ operator is applied, so the value of the element that ip is pointing to will be accessed first (*) and then the value is incremented by 1. Since ip was pointing the first element[arr[0]), its new value becomes 2 (1 +1). |
(*ip)++ | same as previous |
*++ip | in this case the ++ will be evaluated first followed by the indirection operator *. Thus it accesses the content of the second element (i.e. arr[1]) from the array i.e. 2. |
*(ip++) | same as previous |
*ip++ | same as previous. |
9.3 DYNAMIC MEMORY ALLOCATION AND DEALLOCATION- malloc & free functions
A pointer can point to data objects of any type, not merely integer or float. Thus one can have a pointer to arrays, structures or even to functions. At this point, it is necessary to emphasise that, when a pointer variable is declared such as in
data *p;
where data is previously defined data type, space will not be automatically allocated for an object of type data. C supports a facility to allocate such space whenever it is required. Such dynamic allocation of memory space helps in reducing overall memory requirement for the program. Also as we will see later, such a facility enables us to create dynamic data structures such as lists, trees, etc., efficiently.
In order to allocate space for the data object pointed to by p, C provides a library function malloc(). The space thus created can be freed using the function free(). The procedure for using malloc function is illustrated below,
p=(data *) malloc(sizeof(data));
If data is int, then sizeof(int) will determine space required to store an integer data e.g. 4 bytes. Similarly if data is double then malloc will reserve a space of 8 bytes and will assign the address of this space to p. The sizeof function helps the program to become machine independent. This function returns a pointer to char type. Hence we need to use the type casting operator (data *) to match the type of p.
9.4 POINTERS AND ARRAYS
It can be recalled that a one dimensional array name essentially indicates (points) to the location where the array is stored.
Thus consider the array declaration,
int x[20];
Here x is treated as an address to the array. Incidentally, it stores the address of the first element (i.e. &x[0]) of the array. The location of any element say ith element of the array x can be determined in either of the two ways, &x[i] or (x + i). In (x + i), the integer quantity i (position of a specific (ith) element in the array) is added to the address of the first element to extract the address of the ith element. This is possible because all the elements of the array x, occupies a contiguous memory block.
The following example illustrates the usage of pointers in one dimensional array manipulations.
Example 9.5 :
#include
main()
{
static int x[5]={1,2,3,4,5};
int *p;
int i=2;
p=&x[i]; /* assigns p to the address of the third element */
p=(x + i); /* this statement is equivalent in all respect with the previous statement */
x[3]=*p; /*will put the value of the element 3 to the 4th element in the array*/
/* an alternate way to write the previous statement will be
*(x + 3)=*p;
*/
}
9.5 CREATION OF AN ARRAY USING POINTERS
We have already observed that an array name is actually a pointer to the first element in the array. However a conventional array definition results in a fixed block of memory being reserved at the beginning of the program which may lead to wastage of memory space during program execution. This problem can be avoided if an array is implemented using a pointer variable. The use of a pointer variable to represent an array requires some sort of initial memory allocation before the array elements are processed. This is done by using the malloc library function. Compare the following two blocks of statements to understand the difference between conventional array declaration and array implementation using pointers by dynamic memory allocation.
block 1 :
# include
# define size 10
int arr[size]; /* Conventional static memory allocation */
block 2:
# include
# define size 10
int *arr; /* defined as a pointer to an integer variable */
main()
{
:
arr=(int *)malloc(size * sizeof(int));
}
Example 9.6 :
This example illustrates the usage of a pointer in creating a one dimensional array of integers and sorting them.
#include
#include
main()
{
int i,n, *vector;
void bubble ();
printf (“Size of array ?”);
scanf (“%d”, &n);
printf (“%d”,n);
/* Dynamic memory allocation*/
/* sizeof function gives the size of any datatype in bytes*/
vector = (int*) malloc(n*sizeof (int));
printf (“
Enter elements separated by blanks
”);
for (i = 0; i
scanf(“%d”, vector+i); /* reading elements */
for (i = 0; i
printf (“%5d”, *(vector+i)); /* displaying elements*/
printf(“
”);
/* invoking function*/
bubble (vector,n);
printf(“
Sorted array
”);
for (i = 0; i
printf(“%d ”,vector[i]);
printf (“
”);
} /*end of main() */
/*Bubble sort function*/
void bubble (x,m)
int *x,m;
{
int pass,i,temp;
for (pass = 0; pass
{
for (i = 0; i <>
{
if (*(x+i)>*(x+i+1))
{
temp = *(x+i);
*(x+i) = *(x+i+1);
*(x+i+1) = temp;
}
}
}
}
One dimensional character string
Similar to a one dimensional integer array, the character array or string name holds the address of the starting element. However, unlike the integer array, a character array is always terminated by a null (
0 comments:
Post a Comment