0% found this document useful (0 votes)
26 views9 pages

Unit 5 Pointers

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views9 pages

Unit 5 Pointers

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

Unit 4 – POINTERS

Definition and initialization of pointer variables:


A pointer is a variable that is used to store a memory address. Most commonly the address is the
location of another variable in memory.
If one variable holds the address of another then it is said to point to the second variable.
Addres Value Variable
s
1000
1004 1012 ivar_ptr
1008
1012 23 ivar
1016
In the above illustration ivar is a variable of type int with a value 23 and stored at memory
location 1012. ivar_ptr is a variable of type pointer to int which has a value of 1012 and is stored
at memory location 1004. Thus ivar_ptr is said to point to the variable ivar and allows us to refer
indirectly to it in memory.
Syntax : type *ptr ;
which indicates that ptr is a pointer to a variable of type type. For example
int *ptr ;
declares a pointer ptr to variables of type int.

Pointer Operators * and &:


& is a unary operator that returns the address of its operand which must be a variable.
For Example :-

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.

int *ptr ; Address Value


int array[3] = { 100, 101, 102 } ; ptr 1000 2008
ptr = &array ;
array[0] 2008 100
array[1] 2012 101
array[2] 2016 102

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 ;

ptr = str ;/* causes ptr to point to start of string str */


ptr = &str[0] ; /* this performs the same as above */

It is illegal however to do the following

str = ptr ; /* illegal */

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.

char str[80], *ptr , ch;

ptr = str ; // position the pointer appropriately

*ptr = 'a' ; // access first element i.e. str[0]


ch = *( ptr + 1 ) ; // access second element i.e. str[1]

Thus *( array + index ) is equivalent to array[index].

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

int x[10], *ptr ;

ptr = x ;
ptr[4] = 10 ; /* accesses element 5 of array by indexing a pointer */

Strings and pointers


C's standard library string handling functions use pointers to manipulate the strings. For example
the prototype for the strcmp() function found in <string.h> is

int strcmp( const char *string1, const char *string2 ) ;

where const is a C keyword which locks the variable it is associated with and prevents any
inadvertent changes to it within the function.

Strings can be initialized using pointer or array notation as follows

char *str = "Hello\n" ;

char string[] = "Hello\n" ;

in both cases the compiler allocates just sufficient storage for both strings.

Multiple Indirection -- Pointers to Pointers:


It is possible in C to have a pointer point to another pointer that points to a target value.
This is termed multiple indirection in this case double indirection. Multiple indirection can be
carried out to whatever extent is desired but can get convoluted if carried to extremes.In the
normal situation, single indirection, a pointer variable would hold the address in memory of an
appropriate variable, which could then be accessed indirectly by de-referencing the pointer using
the * operator.

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.

int x = 10, *p, **q ;

p = &x ;
q = &p ;

**q = 20 ; // de-reference twice to access value


p = *q ; // de-reference q once to get a pointer to int

int array1[] = { 1,2,3,4,5,6 ,7 ,8,9,10} ;
int array2[] = {10,20,30,40,50} ;
int *pointers[2] ; // an array of pointers to type int
int **ptr ; // a doubly indirected pointer

ptr = pointers ; // initialise pointer to array of pointers


*ptr++ = array1 ; // now we simply de-reference the pointer to a pointer
*ptr = array2 ; // once and move it on like any pointer

**ptr = 100 ; // ptr is pointing at pointers[1] which in turn is pointing


// at array2 so array2[0] is assigned 100
Command Line Arguments:
Command line arguments allow us to pass information into the program as it is run. For example
the simple operating system command type uses command line arguments as follows

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.

void main( int argc, char *argv[ ] )


{
...
}

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] ) ;
}

To run the program one might type c:\>name tom


For Example :- Program to count down from a given value, the countdown being displayed if the
argument "display" is given.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

void main( int argc, char *argv[ ] )


{
int disp, count ;

if ( argc < 2 )
{
puts("Missing Arguments Usage : progname count [display]" );
exit(1) ;
}

if ( argc > 2 && !strcmp( argv[2], "display" ) )


disp = 1 ;
else
disp = 0 ;

for ( count = atoi( argv[1] ) ; count ; count-- )


if ( disp )
printf( "%d\n", count ) ;
printf( “done\n” ) ;
}
Dynamic memory management functions:
Dynamic memory management functions are used to allocate memory to the variables
dynamically. There are four memory management functions

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);
}

You might also like