A concept in C programming that is absolutely essential and fundamental to all software design but often misunderstood is pointers. A pointer is used in C to point to the address of a variable or a function.
While simple in nature, pointers offer a very powerful and flexible tool that if not properly yielded or understood can cause an engineer to shoot themselves in the foot. This is primarily due to the fact that you can set a pointer to any address and then just start overwriting what is there. It is therefore very important that when using pointers the engineer understand exactly how they work.
Initially, the language constructs used to create and manipulate pointers are straight forward; however, as pointers are declared for more complex language features such as structures, arrays or arrays of structures, it can become very confusing as to whether you are manipulating data or addresses. In order to make sure that anyone can follow along we will start with the simplest declarations and work towards complex ones which will later be used in mapping to peripherals.
A pointer is declared like any other variable except that the * symbol is placed after the type. For example,
This statement declares IntPtr as a pointer to an integer. In this case, we have declared a null pointer which is a pointer looking at address location zero.
We can assign the pointer to another variable by using the & symbol. This symbol is used to get the “address of” a variable. For example, we can assign our pointer to the address location of a variable named Var1 of type int as follows
Let’s say that Var1 was initialized with a value of 14. The pointer stores the address of Var1 so for the programmer to get access to the data stored at the memory location the pointer needs to be dereferenced. This is done by using the * symbol as shown below:
In this example we not only dereference the pointer using *, if the value found at the address is greater than or equal to 14 then it is set to 1. To get a better understanding of what is happening in memory the following memory space can be examined
This memory block shows the address of variables Var1, Var2, and the pointer PtrInt. Notice that the PtrInt value is the address of Var1.
There are a number of instances where the real power of pointers comes into play. The most obvious of these is when data needs to be passed and shared throughout an application. For example, if there is a large data set stored as an array that needs manipulation, instead of passing the dataset to a function by value, the function could be declared to take a pointer to the array instead.
This has the advantage of directly manipulating the dataset rather than creating a memory copy of the data. Not only does this save memory but it also increases the speed at which the function runs since it does not need to create a local copy of the data.
In the next article in this series we will examine more complex cases for the use of pointers in detail such as pointer arrays, pointer array structures and if there is time briefly introduce function pointers. Understanding these different uses and behaviors of pointers will be essential when we look at mapping peripherals and creating reusable drivers.
This article has previously been published on Embedded.com’s sister publication, EDN Magazine.