EmbLogic's Blog
Pointers
Pointers are just variables like any other variables we declare, the only difference is that, the so called normal variables store some sort of data like an integer,a character,a floating point number, on the other hand a pointer stores a logical address belonging to the data or stack segment (at which some data is stored or is to be stored).
A pointer provides us the ability to access and modify data from anywhere. Pointers allow faster access to memory.
Pointer declaration:
The ‘*’ operator is used to declare a pointer for e.g. int *ptr or char *ptr. In the former case ptr is a pointer which would hold the memory location of an integer similarly in the latter ptr is a pointer which would store the memory location of a character. Its important to note that the datatype preceding the identifier is not the datatype of the identifier its the datatype of the value that would be stored or is already present at the location ptr is pointing to.
Pointer Initialization:
Its important to remember that a pointer when declared does not store a valid logical address, rather it holds a garbage value and such pointers are called wild pointers and are very dangerous as they may be pointing to a location where some data is already stored and you might end up overwriting it. So its essential to give a valid address to the pointer (You shouldn’t worry too much about this as the compiler would give you a segmentation fault at run time if you try to access a wild pointer, but its a good habit to initialize the pointer as soon as you declare it).
There are many ways to initialize a pointer:
-
Suppose you declare a pointer which points to an integer value, like int *ptr, now this pointer doesn’t have a valid address. We can use the address of another variable and assign this address to our pointer like
int variable1;
ptr = &variable1;
‘&’ ampersand is used to get memory location of the integer variable.
-
Another way is dynamic memory allocation. In this technique pointer is assigned a valid address at run time from the heap segment. This is the best way to assign addresses to pointers as it gives us the flexibility of deciding the amount of memory we want our pointer to access and the type of data we will store in the block of memory. Dynamic allocation of memory is done using malloc(), calloc(),and realloc() system calls.
For e.g. lets assign an address to ptr
ptr = (int*)malloc(sizeof(int) * 10);
Here, we type cast malloc to tell the compiler that we want a memory block that stores integers and we use the sizeof() function to find the size of ‘int’ our system and multiply it by the no. of integers we want to store in this block. ptr would store the starting address of this block of memory.
-
This last method is specific to character arrays
for e.g. char *ptr = “Hello world”
‘ptr’ is a pointer which would store the address at which a character is to be stored. In our e.g. ptr would hold the address at which ‘H’ is stored using this address we access the entire string.
Note that the string will be automatically terminated by NULL character. Another point to remember is that this is a declaration for a const char* that means the string pointed to by ptr cannot be changed. An attempt to modify this string will not result in a compile time error, rather at run time a segmentation fault will occur. A better option is to initialise ptr as :
const char *ptr = “Hello World”;
Modifying ptr now would give compile time error, which is better because both statements give the same result, a const char array, so a compile time error saves us time and reduces the confusion.
Reading Complicated Pointer Declarations:
Reading complex pointer declarations can become a nightmare especially for people who are new to C. So, I’ve added an e.g. w.r.t this topic just to complete my share social service for this week.
We’ll use the following e.g. to understand how we should interpret complicated pointer declarations.
int*(*(*ptr[]) () )[]
We should start from the identifier(and the innermost brace) and move right then left until we reach an end brace. So here we start from ptr:
-
ptr is the identifier we can straight away conclude that ptr is an array (on moving right) of (on moving left) pointers, after square brackets the innermost braces close. So we’re at *ptr[]
-
Next on moving right ptr is an array of pointers to a (on moving right) function (then moving left) that returns a pointer. At this point we’re at (int*(*ptr[])() )
-
Finally the outermost braces give us : ptr is an array of pointers to a function returning pointer to (on moving right) an array of integer pointers(on moving left).
I’ll take another e.g. and explain it in more detail to make things clear:
char (*(*ptr())[])()
-
Using our convention we start from ptr, now moving right we see that ptr is a function , then we reach the end of the innermost brace but we still don’t know what this function returns to find out we move to the left of ptr and find ‘*’ operator so we conclude that ptr is a function that returns a pointer. At the end of this we’re at: *ptr() (ptr is a function returning a pointer), but we don’t know what the returning pointer points to.
-
Going out of the inner most braces on the right we see square brackets so that means the pointer returned by ptr would point to an array, now on moving left we find what this array stores. It stores pointers. So at this stage we have : *(*ptr())[] (ptr is a function returning a pointer to an array of pointers). Remember we don’t know the pointers in the array point to.
-
Now to the outermost braces on moving right its clear that the pointers in the array each point to a function and on moving left we find the return type of these functions is a char type variable.
So we can conclude that ptr is a function returning a pointer to an array of pointers which point to functions that return char type variables.
I’ll leave a few exercises and there answers so that you can become accustomed to this method.
-
*(*(*arr[3]))[3]
-
*(*arr[5])( ))
-
char(*ptr)( )
Answers:
-
‘arr’ is an array ( of size 3 ) of pointers each of which points to a pointer that points to an array ( of size 3 ) of pointers.( Remember if you encounter nothing on the right simply move to the left)
-
‘arr’ is an array ( of size 5 ) of pointers each of which points to a function that returns a pointer.
-
‘ptr’ is pointer to a function that returns a char type variable.