Вы находитесь на странице: 1из 16

C Pointers Fundamentals Explained with Examples Part I

Anybody who is working on Linux environment (not just developers), should understand the
fundamentals of C programming language and write some basic C program.

This article is part of our ongoing series on C programming language.

The concept of pointers is one of the most powerful fundamentals of C/C++ language.

Through pointers a developer can directly access memory from his/her code which makes memory related
operations very fast. But, as always, with great power comes great responsibility.
A developer has to very carefully make use of pointers in order to avoid some problems that can be
nightmare to debug.

In this article we will study the very basic concept of pointers with examples in C language.

What are Pointers?


Different from other normal variables which can store values, pointers are special variables that can hold
the address of a variable. Since they store memory address of a variable, the pointers are very commonly
said to point to variables. Lets try to understand the concept.

As shown in the above diagram:

A normal variable var has a memory address of 1001 and holds a value 50.
A pointer variable has its own address 2047 but stores 1001, which is the address of the variable
var

How to Declare a Pointer?


A pointer is declared as :
<pointer type> *<pointer-name>

In the above declaration :

1. pointer-type : It specifies the type of pointer. It can be int,char, float etc. This type specifies the type of
variable whose address this pointer can store.
2. pointer-name : It can be any name specified by the user. Professionally, there are some coding styles
which every code follows. The pointer names commonly start with p or end with ptr
An example of a pointer declaration can be :

char *chptr;

In the above declaration, char signifies the pointer type, chptr is the name of the pointer while the
asterisk * signifies that chptr is a pointer variable.

How to initialize a Pointer?


A pointer is initialized in the following way :

<pointer declaration(except semicolon)> = <address of a variable>

OR

<pointer declaration>

<name-of-pointer> = <address of a variable>

Note that the type of variable above should be same as the pointer type.(Though this is not a strict rule but
for beginners this should be kept in mind).

For example :

char ch = 'c';

char *chptr = &ch; //initialize

OR
char ch = 'c';

char *chptr;

chptr = &ch //initialize

In the code above, we declared a character variable ch which stores the value c. Now, we declared a
character pointer chptr and initialized it with the address of variable ch.

Note that the & operator is used to access the address of any type of variable.

How to Use a Pointer?


A pointer can be used in two contexts.

Context 1: For accessing the address of the variable whose memory address the pointer stores.

Again consider the following code :

char ch = 'c';

char *chptr = &ch;

Now, whenever we refer the name chptr in the code after the above two lines, then compiler would try to
fetch the value contained by this pointer variable, which is the address of the variable (ch) to which the
pointer points. i.e. the value given by chptr would be equal to &ch.

For example :

char *ptr = chptr;

The value held by chptr (which in this case is the address of the variable ch) is assigned to the new
pointer ptr.

Context 2: For accessing the value of the variable whose memory address the pointer stores.

Continuing with the piece of code used above :

char ch = 'c';

char t;

char *chptr = &ch;


t = *chptr;

We see that in the last line above, we have used * before the name of the pointer. What does this asterisk
operator do?

Well, this operator when applied to a pointer variable name(like in the last line above) yields the value of
the variable to which this pointer points. Which means, in this case *chptr would yield the value kept at
address held by chptr. Since chptr holds the address of variable ch and value of ch is c, so *chptr
yeilds c.

When used with pointers, the asterisk * operator is also known as value of operator.

An Example of C Pointers
Consider the following code :

CODE :

#include <stdio.h>

int main(void)

char ch = 'c';

char *chptr = &ch;

int i = 20;

int *intptr = &i;

float f = 1.20000;

float *fptr = &f;

char *ptr = "I am a string";


printf("\n [%c], [%d], [%f], [%c], [%s]\n", *chptr, *intptr, *fptr, *ptr, ptr);

return 0;

OUTPUT :

$ ./pointers

[c], [20], [1.200000], [I], [I am a string]

To debug a C program, use gdb. The above code covers all the common pointers. The first three of them
are very trivial now to understand so lets concentrate on the fourth one. In the fourth example, a character
pointer points to a string.
In C, a string is nothing but an array of characters. So we have no staring pointers in C. Its the character
pointers that are used in case of strings too.

Now, coming to the string, when we point a pointer to a string, by default it holds the address of the first
character of the string. Lets try to understand it better.

The string, I am String in memory is placed as :

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010

I a m S t r i n g \0

Since characters occupy one byte each, so they are placed like above in the memory. Note the last
character, its a null character which is placed at the end of every string by default in C. This null character
signifies the end of the string.

Now coming back to the point, any character pointer pointing to a string stores the address of the first
character of the string. In the code above, ptr holds the address of the character I ie 1001. Now, when we
apply the value of operator * to ptr, we intend to fetch the value at address 1001 which is I and hence
when we print *ptr, we get I as the output.

Also, If we specify the format specifier as %s and use ptr (which contains the starting address of the
string), then the complete string is printed using printf. The concept is that %s specifier requires the
address of the beginning byte of string to display the complete string, which we provided using ptr
(which we know holds the beginning byte address of the string). This we can see as the last print in the
output above.
Pointers as Structure Objects
Consider the following code :

CODE:

#include<stdio.h>

struct st{

int a;

char ch;

};

int main(void)

struct st obj;

struct st *stobj = &obj;

stobj->a = 5;

stobj->ch = 'a';

printf("\n [%d] [%c]\n", stobj->a, stobj->ch);

return 0;

OUTPUT:

$ ./pointers
[5] [a]

In the above code, we have declared a pointer stobj of type struct st. Now since the pointer type is a
structure, so the address it points to has to be of a struct st type variable(which in this case is obj). Other
interesting part is how structure elements are accessed using pointer variable stobj. Yes, When dealing
with pointer objects, its a standard to use arrow operator -> instead of . operator(which would have been
used, had we used obj to access the structure elements).

C Pointer to Pointer, Pointer to Functions, Array of Pointers


Explained with Examples

In this article, we will try to develop understanding of some of the relatively complex concepts. The
following are explained in this article with examples:

1. Constant pointer and pointer to constant.


2. Pointer to pointer with an example
3. Array of pointers with an example
4. Pointer to functions with an example

1. C Constant Pointer and Pointer to Constant


As a developer, you should understand the difference between constant pointer and pointer to constant.

C Constant pointer
A pointer is said to be constant pointer when the address its pointing to cannot be changed.

Lets take an example :

char ch, c;

char *ptr = &ch

ptr = &c

In the above example we defined two characters (ch and c) and a character pointer ptr. First, the
pointer ptr contained the address of ch and in the next line it contained the address of c. In other
words, we can say that Initially ptr pointed to ch and then it pointed to c.
But in case of a constant pointer, once a pointer holds an address, it cannot change it. This means a
constant pointer, if already pointing to an address, cannot point to a new address.

If we see the example above, then if ptr would have been a constant pointer, then the third line would
have not been valid.

A constant pointer is declared as :

<type-of-pointer> *const <name-of-pointer>

For example :

#include<stdio.h>

int main(void)

char ch = 'c';

char c = 'a';

char *const ptr = &ch; // A constant pointer

ptr = &c; // Trying to assign new address to a constant pointer. WRONG!!!!

return 0;

When the code above is compiled, compiler gives the following error :

$ gcc -Wall constptr.c -o constptr

constptr.c: In function main:

constptr.c:9: error: assignment of read-only variable ptr


So we see that, as expected, compiler throws an error since we tried to change the address held by
constant pointer.

Now, we should be clear with this concept. Lets move on.

C Pointer to Constant
This concept is easy to understand as the name simplifies the concept. Yes, as the name itself suggests,
this type of pointer cannot change the value at the address pointed by it.

Lets understand this through an example :

char ch = 'c';

char *ptr = &ch

*ptr = 'a';

In the above example, we used a character pointer ptr that points to character ch. In the last line, we
change the value at address pointer by ptr. But if this would have been a pointer to a constant, then the
last line would have been invalid because a pointer to a constant cannot change the value at the address its
pointing to.

A pointer to a constant is declared as :

const <type-of-pointer> *<name-of-pointer>;

For example :

#include<stdio.h>

int main(void)

char ch = 'c';

const char *ptr = &ch; // A constant pointer 'ptr' pointing to 'ch'

*ptr = 'a';// WRONG!!! Cannot change the value at address pointed by 'ptr'.

return 0;
}

When the above code was compiled, compiler gave the following error :

$ gcc -Wall ptr2const.c -o ptr2const

ptr2const.c: In function main:

ptr2const.c:7: error: assignment of read-only location *ptr

So now we know the reason behind the error above ie we cannot change the value pointed to by a constant
pointer.

2. C Pointer to Pointer
Till now we have used or learned pointer to a data type like character, integer etc. But in this section we
will learn about pointers pointing to pointers.

As the definition of pointer says that its a special variable that can store the address of an other variable.
Then the other variable can very well be a pointer. This means that its perfectly legal for a pointer to be
pointing to another pointer.

Lets suppose we have a pointer p1 that points to yet another pointer p2 that points to a character ch. In
memory, the three variables can be visualized as :

So we can see that in memory, pointer p1 holds the address of pointer p2. Pointer p2 holds the address of
character ch.

So p2 is pointer to character ch, while p1 is pointer to p2 or we can also say that p2 is a pointer to
pointer to character ch.
Now, in code p2 can be declared as :

char *p2 = &ch;

But p1 is declared as :

char **p1 = &p2;

So we see that p1 is a double pointer (ie pointer to a pointer to a character) and hence the two *s in
declaration.

Now,

p1 is the address of p2 ie 5000


*p1 is the value held by p2 ie 8000
**p1 is the value at 8000 ie c
I think that should pretty much clear the concept, lets take a small example :

#include<stdio.h>

int main(void)

char **ptr = NULL;

char *p = NULL;

char c = 'd';

p = &c;

ptr = &p;

printf("\n c = [%c]\n",c);

printf("\n *p = [%c]\n",*p);
printf("\n **ptr = [%c]\n",**ptr);

return 0;

Here is the output :

$ ./doubleptr

c = [d]

*p = [d]

**ptr = [d]

3. C Array of Pointers
Just like array of integers or characters, there can be array of pointers too.

An array of pointers can be declared as :

<type> *<name>[<number-of-elements];

For example :

char *ptr[3];

The above line declares an array of three character pointers.

Lets take a working example :

#include<stdio.h>
int main(void)

char *p1 = "Himanshu";

char *p2 = "Arora";

char *p3 = "India";

char *arr[3];

arr[0] = p1;

arr[1] = p2;

arr[2] = p3;

printf("\n p1 = [%s] \n",p1);

printf("\n p2 = [%s] \n",p2);

printf("\n p3 = [%s] \n",p3);

printf("\n arr[0] = [%s] \n",arr[0]);

printf("\n arr[1] = [%s] \n",arr[1]);

printf("\n arr[2] = [%s] \n",arr[2]);

return 0;

In the above code, we took three pointers pointing to three strings. Then we declared an array that can
contain three pointers. We assigned the pointers p1, p2 and p3 to the 0,1 and 2 index of array. Lets see
the output :
$ ./arrayofptr

p1 = [Himanshu]

p2 = [Arora]

p3 = [India]

arr[0] = [Himanshu]

arr[1] = [Arora]

arr[2] = [India]

So we see that array now holds the address of strings.

4. C Function Pointers
Just like pointer to characters, integers etc, we can have pointers to functions.

A function pointer can be declared as :

<return type of function> (*<name of pointer>) (type of function arguments)

For example :

int (*fptr)(int, int)

The above line declares a function pointer fptr that can point to a function whose return type is int and
takes two integers as arguments.

Lets take a working example :


#include<stdio.h>

int func (int a, int b)

printf("\n a = %d\n",a);

printf("\n b = %d\n",b);

return 0;

int main(void)

int(*fptr)(int,int); // Function pointer

fptr = func; // Assign address to function pointer

func(2,3);

fptr(2,3);

return 0;

In the above example, we defined a function func that takes two integers as inputs and returns an
integer. In the main() function, we declare a function pointer fptr and then assign value to it. Note that,
name of the function can be treated as starting address of the function so we can assign the address of
function to function pointer using functions name. Lets see the output :

$ ./fptr
a = 2

b = 3

a = 2

b = 3

So from the output we see that calling the function through function pointer produces the same output as
calling the function from its name.