Unit 5 Pointers
Unit 5 Pointers
int *m ;
int count=125, i ;/* m is a pointer to int, count, i are integers */
m = &count ;
The address of the variable count is placed in the pointer variable m.
The * operator is the complement of the address operator & and is normally termed the
indirection operator. Like the & operator it is a unary operator and it returns the value of the
variable located at the address its operand stores.
For Example :-
i = *m ;
assigns the value which is located at the memory location whose address is stored in m, to the
integer i. So essentially in this case we have assigned the value of the variable count to the
variable i. The final situation is illustrated below.
One of the most frequent causes of error when dealing with pointers is using an uninitialized
pointer. Pointers should be initialized when they are declared or in an assignment statement. Like
any variable if you do not specifically assign a value to a pointer variable it may contain any
value. This is extremely dangerous when dealing with pointers because the pointer may point to
any arbitrary location in memory, possibly to an unused location but also possibly to a memory
location that is used by the operating system. If your program tries to change the value at this
address it may cause the whole system to crash. Therefore it is important to initialize all pointers
before use either explicitly in your program or when defining the pointer.
A pointer may also be initialized to 0 ( zero ) or NULL which means it is pointing at nothing.
This will cause a run-time error if the pointer is inadvertently used in this state. It is useful to be
able to test if a pointer has a null value or not as a means of determining if it is pointing at
something useful in a program.
pointers and function arguments:
Pointers and function arguments are nothing but pointers concept is implemented with functions.
This can be done in two ways
i. Call by reference
Call by reference:
Call by reference means passing addresses from calling function to called function
instead of passing direct values to called function. The solution to the problem is to use call by
reference which is implemented in C by using pointers as is illustrated in the following example.
#include <stdio.h>
void swap( int *, int * ) ;
void main( )
{
int a, b ;
printf( "Enter two numbers" ) ;
scanf( " %d %d ", &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
swap( &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
}
void swap ( int *ptr1, int *ptr2 )
{
int temp ;
temp = *ptr2 ;
*ptr2 = *ptr1 ;
*ptr1 = temp ;
}
Pointer Arithmetic:
Pointer variables can be manipulated in certain limited ways. Many of the manipulations are
most useful when dealing with arrays which are stored in contiguous memory locations.
Knowing the layout of memory enables us to traverse it using a pointer and not get completely
lost.
Assignment
int count, *p1, *p2 ;
p1 = &count ; // assign the address of a variable directly
p2 = p1 ; // assign the value of another pointer variable, an address
Addition / Subtraction
The value a pointer holds is just the address of a variable in memory, which is normally a four
byte entity. It is possible to modify this address by integer addition and subtraction if necessary.
Consider the following we assume a 32-bit system and hence 32-bit integers.
We now have the pointer variable ptr pointing at the start of array which is stored at memory
location 2008 in our illustration. Since we know that element array[1] is stored at address 2012
directly after element array[0] we could perform the following to access its value using the
pointer.
ptr += 1 ;
This surprisingly will cause ptr to hold the value 1012 which is the address of array[1], so we can
access the value of element array[1]. The reason for this is that ptr is defined to be a pointer to
type int, which are four bytes in size on a 32-bit system. When we add 1 to ptr what we want to
happen is to point to the next integer in memory. Since an integer requires four bytes of storage
the compiler increments ptr by 4. Likewise a pointer to type char would be incremented by 1, a
pointer to float by 4, etc.
Similarly we can carry out integer subtraction to move the pointer backwards in memory.
ptr = ptr - 1 ;
ptr -= 10 ;
The shorthand operators ++ and -- can also be used with pointers. In our continuing example
with integers the statement ptr++ ; will cause the address in ptr to be incremented by 4 and so
point to the next integer in memory and similarly ptr-- ; will cause the address in ptr to be
decremented by 4 and point to the previous integer in memory.
Pointers and Arrays:
There is a very close relationship between pointer and array notation in C. As we have seen
already the name of an array ( or string ) is actually the address in memory of the array and so it
is essentially a constant pointer.
For Example :-
char str[80], *ptr ;
as str is a constant pointer and so its value i.e. the address it holds cannot be changed.
Instead of using the normal method of accessing array elements using an index we can
use pointers in much the same way to access them as follows.
Note that the parentheses are necessary above as the precedence of * is higher than that of +. The
expression
ch = *ptr + 1 ;
for example says to access the character pointed to by ptr ( str[0] in above example with value
‘a’) and to add the value 1 to it. This causes the ASCII value of ‘a’ to be incremented by 1 so that
the value assigned to the variable ch is ‘b’.
In fact so close is the relationship between the two forms that we can do the following
ptr = x ;
ptr[4] = 10 ; /* accesses element 5 of array by indexing a pointer */
where const is a C keyword which locks the variable it is associated with and prevents any
inadvertent changes to it within the function.
in both cases the compiler allocates just sufficient storage for both strings.
In the case of double indirection, we have the situation where a variable may be pointed to by a
pointer as with single indirection, but that this pointer may also be pointed to by another pointer.
So we have the situation where we must de-reference this latter pointer twice to actually access
the variable we are interested in. De-referencing the pointer to a pointer once gives us a normal
singly indirected pointer, de-referencing the pointer to a pointer secondly allows us to access the
actual data variable. The situation is depicted in the diagram below.
To declare a pointer to a pointer we include another indirection operator
float * * ptr ;
which in this case defines a pointer to a pointer to type float.
The following illustrates some valid operations using double indirection.
p = &x ;
q = &p ;
c:>type text.dat
where the name of the file to be printed is taken into the type program and the contents of the file
then printed out.
In C there are two in-built arguments to the main() function commonly called argc and argv
which are used to process command line arguments.
argc is used to hold the total number of arguments used on the command line which is always at
least one because the program name is considered the first command line argument.
argv is a pointer to an array of pointers to strings where each element in argv points to a
command line argument. For example argv[0] points to the first string, the program name.
For Example :- Program to print a name ( saved in name.c ) using command line arguments.
#include <stdio.h>
void main( int argc, char *argv[ ] )
{
if ( argc != 2 )
{
puts( "Missing parameter. Usage : name yourname" ) ;
exit( 1 );
}
printf( "Hello %s", argv[1] ) ;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
if ( argc < 2 )
{
puts("Missing Arguments Usage : progname count [display]" );
exit(1) ;
}
i. malloc()
ii. free()
iii. calloc()
iv. realloc()
The malloc function The malloc function allocates a memory block of size n bytes (size_t is
equivalent to an unsigned integer) The malloc function returns a pointer (void*) to the block of
memory. That void* pointer can be used for any pointer type. malloc allocates a contiguous
block of memory. If enough contiguous memory is not available, then malloc returns NULL.
Therefore always check to make sure memory allocation was successful by using
void* p;
if ((p=malloc(n)) == NULL)
return 1;
else { /* memory is allocated */}
Example: if we need an array of n ints, then we can do
int* A = malloc(n*sizeof(int));
A holds the address of the first element of this block of 4n bytes, and A can be used as an array.
For example, if (A != NULL)
free():
A dynamically allocated memory can be freed using free function. For example
free(A);
will cause the program to give back the block to the heap (or free memory). The argument to free
is any address that was returned by a prior call to malloc. If free is applied to a location that has
been freed before, a double free memory error may occur.
calloc and realloc():
calloc and realloc are two functions that can be useful in dynamic memory management
void *calloc(size_t nmemb, size_t size);
allocates memory for an array of nmemb elements each of size and returns a pointer to the
allocated memory. Unlike malloc the memory is automatically set to zero.
calloc(n, sizeof(int)) is equivalent to malloc(n*sizeof(int))
except for the fact that calloc block is already initialized. Calloc is appropriate when allocating a
dynamic array of ints. Another useful function is realloc. Typically in order to resize an existing
memory block, one must reallocate a new block, copy the old values to the new block and then
free the old memory block.
void *realloc(void *ptr, size_t size);
realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will
be unchanged to the minimum of the old and new sizes; newly allocated memory will be
uninitialized. If ptr is NULL, the call is equivalent to malloc(size); if size is equal to zero, the
call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to
malloc(), calloc() or realloc().
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str;
str = (char *) malloc(15); /* Initial memory allocation */
strcpy(str, "tutorialspoint");
printf("String = %s, Address = %u\n", str, str);
str = (char *) realloc(str, 25); /* Reallocating memory */
strcat(str, ".com");
printf("String = %s, Address = %u\n", str, str);
free(str);
return(0);
}