The most important feature of C is the ability of handling pointers. They contain the address of a variable and they guarantee a huge control on the memory.




A pointer is a variable that doesn’t contain a value, but the memory address of another variable.

As you know, each variable occupies some space in the computer memory ( RAM ) and each unit of it is identified with an address.

Imagine a district: the whole area is the computer memory, each house is a unit of space and each resident is a variable.

Each house can be identified in two ways: the name of its owner and its address.

However, no one will ever look for your house just by your name, because it’s far more convenient and fast to do it using your address.

Imagine a pointer as a postman in a district of a city

In the same way, each unit of memory has its own unique address ( you can’t move a house to a new place ) to which each variable is assigned ( people can move to a new house ).

Although the machine controls all variables by their addresses, high-level languages allow you to call them by name.

The major strength of C is being able to use both addresses and names.

What is a pointer?


We saw what an address is, so now let’s talk about pointers.

As I said, a pointer is a variable that stores an address, which corresponds to a part of memory where another variable is stored.

What do pointers contain?

So, instead of containing values, such as 1, ‘A’, 3.4, it contains something like 100A – addresses in modern computers might be longer, but you got the point.

Recalling the previous example, a pointer is like a postman: he knows the address of a house but not who lives there.

Furthermore, if I have two variables, A and B, and a pointer, P, I can change the address pointed by P, without changing the contents of the variables.

Getting the address from a variable and the value from a pointer: & and *


Before going any further, it’s better to explain two new symbols: & and *.

The first one, &, extracts the address from a variable.

The second one, *, gets the variable pointed by a pointer, and therefore its value.

The table below shows the different values given by these symbols with a variable a = 4 and a pointer p, which points to a:

formula value
p the address of a
a 4
&a the address of a
*p 4

When to use the ampersand and the asterisk?

Moreover, the asterisk is also used to specify the data-type of a variable pointed by a pointer during declaration/definition.

Defining a pointer


In order to define a pointer, use the following syntax:

Where:

  • type is the data-type of the variable pointed by the pointer, or the one you would like to point.
    For example: if you type int, the pointer will be able to point only int variables; if you type char, the pointer will be able to point only char variables; however the address itself doesn’t change type.
  • the asterisk is a fixed character and it tells the computer that you’re creating a pointer and not a normal variable.
  • name is the name of the pointer

You can read it like this: define the pointer name, which points to type variables.

Initialising and assigning a new address to a pointer


By default, a pointer is initialised to the address 0, that correspond to the null pointer, the only one that is considered false and always not valid.

Pointers initialisation and assignment work the same way.

They’re like assigning a value to a normal variable, but, instead of pure values, it’s about addresses.

So, in order to initialise a pointer, do the following:

Where & gets the address of the variable var.

To assign a new address to a pointer, use this:

Notice that we use the asterisk only during definition.

If you change the address assigned to a pointer:

The values of var1 and var2 don’t change, but the value returned by *name does – because the pointer is pointing a different variable, and do a different value.

Operations with pointers


You can do 2 operations with pointers:

  1. Algebraic sum between a pointer and an integer
  2. Difference between two pointers

Algebraic sum between a pointer and an integer

Since an address is just a number, you can add or subtract an integer to it to point a different unit of memory.

However there’s an important feature that is worth mentioning: scaling.

Scaling depends on the dimension of the pointer data-type and it means bringing the integer to the same order of magnitude of the pointer.

Do you want to know more about scaling? Read this explanation by Codingfox.

The scaled value of an integer i is equal to i times the dimension of the pointer type.

Consider the pointer p equals to the address 1000 (hexadecimal) and compare the following situations:

  • if the type of p is int ( 4 bytes )

    p is equal to 1000 + (4 * 4) = 1010
  • if the type of p is char ( 1 byte )

    p is equal to 1000 + (4 * 1) = 1004

This is why is important to specify the type of a pointer.

Difference between two pointers

Although it isn’t possible to add two pointers together, you can subtract them to get the number of elements between two addresses.

Also in this case, the result will be scaled according on the type of the pointer.

So, if I have two pointers, p1 = 1000 and p2 = 1010,…

  • … and they are of type int

    the result r will be equal to (1010 – 1000) / 4 = 4 ( remember that these are hexadecimal numbers )
  • … and they are of type char

    the result r will be equal to (1010 – 1000) / 1 = 10 (dec=16) ( remember that these are hexadecimal numbers )

Scanf and pointers


Have you noticed that so far we’ve always used the & symbol in every scanf with no apparent reason?

Well, a reason exists and it’s related to pointers.

As you know, most functions require one or more arguments to work: printf requires a string and other variables and scanf seems quite similar to it.

However, in order to assign values to variables, you have to pass to scanf the addresses of those variables and not the variables themselves.

Here the & symbol comes into play.

Do you remember what does it mean? If not, scroll up.

The & symbol before the name of a variable gets the address of that variable and a memory address is basically a pointer.

To sum up: scanf requires a pointer to work and you can get it using the & symbol before the name of a variable.

For further information on why scanf requires & while printf doesn’t, have a look at this article by GeeksforGeeks.

The %p specifier


In order to print the value of a pointer, you have to use the %p format specifier.

It can be used for any types and it will print an address in hexadecimal format.

(My) Output:

You can also print it using other format specifiers and it will be converted to that data type.

Here’s an example using %u – that is used for unsigned integers:

(My) Output:

Let’s analyse today’s program


Today’s program sums up some of the main feature of pointers that we examined in this post.

It gets two values from the user, it assigns the address of the first to a pointer and then it prints them.

Then it changes the address pointed by the pointer and it prints all the values again, proving that even if the value of a pointer changes, the one of the pointed variable doesn’t.

Apart from the usual stuff, such as including a library ( read on of the first posts for that ), here’s a detailed explanation of the code.

int var1, var2

This line defines two variables of type int: var1 and var2.

They hasn’t been initialised, so their values are unpredictable until we will change them.

int *p

It creates a pointer p to a not specified variable of type int.

The asterisk tells the computer that p is a pointer and not an ordinary variable.

p = &var1

This line assigns the address of var1 to p.

As you’ve learnt, & gets a variable address, so that we can assign it to the pointer.

scanf(“%d%d”, &var1, &var2)

This scanf reads two integers ( there’re two %ds ) from the command line and it stores them at the addresses of var1 and var2.

printf(“\nValue of p when it’s pointing to var1: %p\n”, p)

This line prints the values of p using the %p format specifier, which is used for addresses.

Translation of today’s program in human language


Computer, include the standard C library for inputs and outputs, stdio.h
Here’s the main body of the program
Define two variables, var1 and var2, of type int
Define a pointer p of type int
Assign the address of var1 to p
Print “Enter the values of var1 and var2:”
Read two integers from the command line and store them at the addresses of var1 and var2
Go to a new line, print “Value of p when it’s pointing to var1:” followed by the value of p and then go to another new line
Move to the next tab space, print “var1=” followed by the value of var1, go to a new line and move to the next tab space, print “var2=” and the value of var2 and finally go to another new line
New line, next tab space, print “…Changing the address pointed by p…”, new line again
Assign the address of var2 to p
Go to a new line, print “Value of p when it’s pointing to var2:” followed by the value of p and then go to another new line
Move to the next tab space, print “var1=” followed by the value of var1, go to a new line and move to the next tab space, print “var2=” and the value of var2 and finally go to another new line
New line, next tab space, print “Even if the value of the pointer changes, the values pointed by it don’t”, new line again

C and C++ comparison


c++ vs c

The main difference between the C and the C++ versions of today’s program is related to printf/cout and scanf/cin.

As you can notice, cout and cin are more easy to use: in fact you don’t have to specify which type of value you want to print and the address of each variable you want to set.

So:

  • cout and cin don’t require any format specifiers
  • cin doesn’t require the & symbol

Conclusion


Today you’ve learnt some of the main features of pointers.

Next time we will see how to use them with arrays, unlocking their real potential.

Now you know how to use and store addresses as values and how to create and manipulate pointers.

I hope this post has been helpful, but if you still have any doubts, feel free to ask me anything you want through a comment below.

If you think this article might help a friend of yours, share it with him/her 😀

Remember that you can always subscribe to the newsletter to receive further guides on C programming and explanations on useful algorithms.

Anyway, the post is finished, have a good day and we will see next week!

From Zephyro it’s all, Bye!

Categories: Learn C

Learn C programming: Pointers to Arrays and Strings - Zephyro · 9 November 2018 at 5:24 PM

[…] Learn C programming: Pointers | Step-by-Step explanation […]

Leave a Reply

%d bloggers like this: