You are on page 1of 13

UNIT- 3

Pointers

Structure:

3.1 Introduction
3.2 Pointer variable
3.3 Accessing Variables Through Pointers
3.4 Pointer declaration and definition
3.5 Initialization of pointer variables
3.6 Pointers and Functions
3.7 Pointers to Pointers
3.8 Compatibility
3.9 LValue and RValue
3.10 Arrays and Pointers
3.11 Pointer Arithmetic and Arrays
3.12 Passing an array to function
3.12.1 Understanding Complex Declarations
3.13 Memory Allocation Functions
3.13.1 Malloc
3.13.2 Calloc
3.13.3 Realloc
3.13.4 Free
3.1 Introduction

A pointer is a derived data type. This is the one which stores the address of data in
memory, we will be in position to access the data directly and do calculations over it. The
standard concept is, we access the data from memory using variable name it gets the
data and operations are done over them. But the pointer is different that the accessing is
done by address the data is stored so that it will be advantage of decreasing the
instructions and overheads of standard usage. This is very specific because every data
has its own memory space and we are working over it. We are able to store the address
in a variable, which is only done only using & operator. The one thing to remember here
is when we execute the program once we get one type of address and this will be
changed to other when we execute it other time.

3.2 Pointer variable

Having pointer constant and pointer value, we can pointer variable which is the thing that
contains address of variable. Here we see how the representation is done between
pointer variable and data, we represent data a with pointer variable p. So we can access
the data with pointer variable easily and we not need the direct representation of data
whenever it is used.

address of
variable a
a
-123 123450 a -123

&a stored in
variable Pointer
variable
P 123450 p

Physical representation Logical representation


We have the flexibility of storing address of one variable in two different pointers. So the
two pointers represent one data and any changes done to data will be replicated in two
pointers. So the value contained in two different pointers will be the one and same. C
has function that assign NULL pointer constant if not assigned to any variable.

a(&a) p 123450 -123 123450 q(&a)

3.3 Accessing Variables Through Pointers

The actual usage of pointers comes here, that accessing of variables using pointers. We
have the capability of accessing the variables and make the operations over that. The
operator that gets the value from pointer variable is * (indirection operator). This is called
the reference to pointer.
P=&a
So the pointer p has address of a and the value that that cointained in that address can
be accessed by : *p

So the operations done over it can be explained as below:


a++;
a=a+1;
*p=*p+1;
(*p)++:
The all above operations give one output. The indirection operator and the address
operator do the exact opposite operations, which can be stated as address operator
gives the address of data it is stored in and indirection operator gives values that are
stored in address field. So the address operator and indirection operator are exactly
opposite.

Inverse
& *
3.4 Pointer declaration and definition

Pointer declaration is done using the indirection operator; it is then followed by data type
we are using to store in it and name of pointer variable. It can be shown as below

type identifier
*

The pointer type can be of any data type we are in use of storing in it. It can be of int,
char, float etc.

3.5 Initialization of pointer variables

The one thing we clearly know is C do not have the capability of initializing variable, the
thing that is done here is operating system takes care of all uninitialised variables. The
garbage value will be collected in these variables till they are initialized. The same thing
happens in the pointers also, the pointer contain a value the could not be a valid address
location. So the removal of this is mandatory and if the address it has is valid it leads to
a run time error. So initializing a pointer variable is a important thing, it is done as follows
int x;
int *p = &x;
Here the two steps are done at once the two steps are
int *p;
*p=&x;
The combination of these two steps gives us the initialization of pointers. So to avoid the
run time errors we can initialize it with null. It can be as
int *p = NULL;
We have the flexibility of using pointers in different ways, we have the capability of
assigning the one pointer variable to different variable and we can do operations over
them. The other is we can assign different pointers to one variable and do operations
over it.
3.6 Pointers and Functions

We get a clear usage of pointers in the working with functions. We have a clear idea of
usage of functions, the thing done here is the values of variables are directly changed
and replicated in calling function, which is said as call by value. The new concept comes
into picture using pointers that are call by reference, the thing done here is passing a
pointer to a variable. The pass by value concept is as follows:
void exchange (int x, int y);
int main (void) {
int a =5;
int b = 7;
exchange (a,b);
printf (“%d %d\n”, a,b);
return 0;
}

void exchange (int x, int y){


int temp;
temp=x;
x=y;
y=temp;
return;
}

Here the exchange function does not work when we go for call by reference it is done as
follows;
void exchange (int *, int *); void exchange (int *x, int *y) {
int main (void) { int temp;
int a=5; temp=*x;
int b=7; *x=*y;
exchange(&a,&b); *y=temp;
printf(“%d %d”,a,b); return;
return 0; }
}
Here the exchange gets worked because we used a pointer for referencing variable in a
function.
exchange (int *, int *)

So that pointers are directly dealt with data address and so it is easy to represent
variable and operations over it.
If we need of sending back more than one value from a function, we can use pointers.
By passing the address of variables defined in main, or any other function that calls, we
can store data directly in the calling function rather than using return. Now we shall see
the functions that returning pointer:
int *smaller (int *p1, int *p2);
int main (void) a b
….
int a;
int b;
int *p; p
… &a or &b
scanf(%d %d”, &a,&b);
p=smaller(&a,&b);
px py

Here we write function as:

int *smaller(int *px, int *py)


return(*px<*py ?px :py);
}
3.7 Pointers to Pointers

The concept of pointer to pointer too has a lot of functionalities and many usages over
this concept. This concept says that we can point a pointer to pointer that is pointer
concerned to variable will have address of that variable and that pointer is pointed again
to that pointer. So that pointer with address of variable is stored in other pointer. We can
use in different operations. The indirection does not have limit but it is considerable only
up to two levels. If we take a variable a, this is pointed by pointer P and this p is pointed
by Q, we have the capability that
int a;
int *p;
int **q;
These are taken in program and if we give this
printf(“%d”, a);
printf(“%d”, *p);
printf(“%d”, **q);
All these give the same value that is the value of a. This can be represented as:

q p a

3.8 Compatibility

As we know that though the pointers are derived data types, they have specific data type
as the general variables and we cannot assign one type of variable to different data type
variable.

Casting:
We say the thing is we do not have the capability of assigning one data type to other.
The flexibility of this can be got by defining it as void or by casting which is done as
below
int a;
char *p;
p=(char *)a this is what the casting is.
Here the int a is changed to char type and it is assigned to p. By using void we can do it
as follows
void *pVoid;
char *pChar;
int *pInt;
pVoid=pChar;
pInt=pVoid;
pInt=(int *)pChar;
This is the thing we can do casting.

3.9 LValue and RValue

In every expression we have lvalue and rvalue. Lvalue is the one that gets the value
and rvalue is the one that operations done on some variables
1. An lvalue expression must be used whenever the object is receiving a value; that
is, it is being modified.
2. An rvalue expression can be used to supply a value for further use; that is, to
examine or copy its value.

Sl.No Expression Type Comments


1 Identifier Variable identifier
2 Expression[..] Array indexing
3 (expression) Expression will always be lvalue
4 *expression Dereferenced expression
5 Expression.name Structure selection
6 Expression->name Structure indirect selection
7 Function call Uses return in lvalue

So we have come across what the variables to be on left and which to be on right. Any
expression we build will fall into any type of above.
3.10 Arrays and Pointers

Arrays and pointers have a close relationship, we say it by the fact that the name of
array is the pointer constant to the first element. When the array name is dereferenced, it
refers to the only first element, not the whole array. We can say it by:

int a[5];
printf (“%d %d”, &a[0],a);

Here the output is same for two variables. Any how we can say this by making pointer
assigned to array, we can store this pointer in a pointer variable. We can make it as
below:

#include<stdio.h>
int main(void) {
int a[5]={2,4,6,7,8}
int *p=a;
int i=0;
…..
printf(“%d %d”, a[i],*p);
…….
return 0;
}

So this two outputs are one and same. We have print them by first using index notation
and then pointer notation. We can do it by intialising pointer to any of member of array.
So if we initialize as that we can access in two different ways using the pointers onto the
same array.
3.11 Pointer Arithmetic and Arrays

We get a facilitation of arithmetic operations using pointers. This as we generally know


that we got a capability of going to other tht is by arithmetic operations. The thing that
done in above example can be taking for this reasoning. Here we have pointed it for the
second element so p+1 is pointed for third element and so on. This is possible because
we have data types that occupy the same space at any time. So it can calculate itself
based on data type, to go to which position we assigned to it. We can show this as
below:

A 2 p-1

A+1 p
4
A+2 p+1
6
A+3 p+2
8
A+4 p+3
10

The actual funda behind this is

Address=pointer+(offset * size of element)


Size of element is the data type we are using. Offset is number of elements in array.
The operations done over array using pointers are of different types. For the addition we
can use one pointer and one is integer the possibility is they both can be of any side of
operator. For subtraction we can do using only two pointers and the subtraction gives
the no of elements in array if we operate over first and last element. As usually unary
operations can be done. They can be shown as below:

P+5 5+p p-5 p1 -p2 p++ --p


3.12 Passing an array to function

As we know that the name of array is the pointer constant, so when we pass the array,
we do not pass the address operator. So the typical will be as:

doIt (aryName);

We do have the other way of initiasing it as

int doIt(int ary[]);

If we use function header as a pointer we have the functionality as below:

int doIt (int *arySalary)

If we want to initialize the multi-dimensional array we do it as:

int doIt (int bigAry[ ] [ ] [ ] );

3.12.1 Understanding Complex Declarations

We have the usage of complicated declarations and their interpretation has become
difficult for usage. So for interpretation we have the formula as
Right-Left rule: Here we first go for things that are right to the identifier and then for left
of identifier. We represent it as below

identifier

6 4 1 3 5
2 Start here
3.13 Memory Allocation Functions

Modern languages have the flexibility of allocating memory at run time. This concept
gives us idea of two concepts, they are static memory allocation and dynamic memory
allocation. Static memory allocation requires that the declaration and definition of
memory be fully specified in source program. This works till we have the capability of
what our requirements are known to us.

Dynamic memory allocation uses predefined functions to allocate and release memory
for data while the program is running. To use this, the programmer must use either
standard data types or already must have declared any derived types. For implementing
dynamic memory we have four management functions. They are malloc,calloc,realloc
and free. We find all these in <stdlib.h> library.

Memory
management

malloc calloc realloc free

3.13.1 Malloc

The malloc function allocates a block of memory that contains the number of bytes
specified in its parameter. It returns a void ponter to first byte of allocated memory. The
allocated memory is not initialized. You should therefore assume that it will contain
garbage and initialize is required.The prototype is as:

void *malloc (size_t size);

In general it itself calculated for known datatypes. It is as for integer.

pInt = (int *)malloc(sizeof (int));

malloc returns address of first byte in memory space, NULL for not successful
3.13.2 Calloc

It allocates a conyiguous block of memory large enough to contain an array of elements


of specified size. So it requires two parameters as number of elements to be allocated
and for size of each element. It returns pointer to first element of allocated array. Its
prototype is:
void *calloc (size_t element_count,size_t element_size);

3.13.3 Realloc

This is inefficient and shouid be used advisebly. Ealloc changes the size of block by
deleting or extending the memory at end of block. If memory is not available it gives
complete new block.The prototype is:

void *realloc (void *ptr, size_t newSize);

3.13.4 Free

The name itself indicates that it clears the memory given. The prototype is

Void free (void *ptr);