In this article, we will learn the nature and use cases of the 'const' type qualifier in C programming. We will see the difference between default variables, pointers and those that have a 'const' added to them.
I hate taking interviews! I feel it is very difficult to judge someone's potential and intellect based on a few mundane and routine questions. While working with Qualcomm, I remember my conversation with a candidate:
Me : "So you are not as good as your resume speaks - you could not correctly answer any of the 6 questions I asked you."
Candidate : "Well, I might just know the 7th one!"
Jokes apart, a very elusive question that I tend to ask folks during interviews is about the "const" type qualifier in C/C++. So a routine question that I ask any candidate is "What is const?", and if I get the answer as:
"const means constant"
I know that I am dealing with an amateur! :-P
What I actually expect is more of a reply like:
"read only"
Although this kind of a "read only" reply doesn't do justice to the type qualifier and would hurt C, yet I would take it as an answer on most occassions. The very next question would be a more detailed one. What do the following declarations mean?
/* 1. */ const int a; /* 2. */ int const a; /* 3. */ const int * a; /* 4. */ int const * a; /* 5. */ int * const a; /* 6. */ int const * a const;
Puzzled? :-) Well, let me open up the Pandora's Box for you!
- There is no difference between the declaration 1 and 2. They both mean the same thing and would declare a "read only" integer. So whatever value you initiailize 'a' with, would be the value of 'a' till its life time. Do notice that it doesnt really matter on the sequence of the keywords const and int. But, they cannot be reinitialized or assigned a different value. A codepiece like the following would generate an error:
const int a = 10; int const b = 20; a = 11; /* ERROR ! */ b = 31; /* ERROR ! */
- Again, there is no difference between the declaration 3 and 4. They both essentially declare a pointer 'a' which would point to a constant integer. This means, the integer it points to is not modifiable - but the pointer is. Let's understand this from some error cases:
const int a = 10; int b = 20; const int * a1 = &a; int const * b1 = &b; b = 31 /* "NO" ERROR */ * a1 = 11; /* ERROR ! */ * b1 = 31; /* ERROR ! */ * a1 = &b; /* "NO" ERROR */
An important thing to note here is that the pointers a1 and b1 need not essentially point to a contant integer. For example in the above case 'b1' points to 'b', but 'b' is not a contant integer. Hence we can change the value of 'b' directly, but we cannot change its value by deferencing the pointer 'b1' as the memory location pointer by 'b1' is read only! -
The declaration 5 is interesting! It declares a contant 'read only' pointer to a integer. This means that the integer pointed by the pointer is modifiable but the pointer is not. Let's write some error cases for this one too:
const int a = 10; int b = 20; int c = 30; int * const a1 = &a; /* ERROR */ int * const b1 = &b; b1 = &c; /* ERROR */ * b1 = 50; /* NO ERROR */
I guess the only statement to explain here is :
int * const a1 = &a;
This is an error because this type of declaration declares a pointer which should point to a non constant memory location but 'a' is read-only!
-
The 6th and the final declaration declares a constant pointer 'a' pointing to a contant integer. This means both the pointer as well as the memory location it is pointing to are 'read-only'. Now this one is on you. Play around with it and generate your own error cases! :-)
Now the million dollar question!
Why do we care about the type qualifier 'const' while programming? One can always write the correct functionality without ever using it , right? Or can we?
This is generally my final question to any candidate who manages to cross the first two hurdles!
- Code using the type qualifier 'const' liberally and adequately would have fewer number of bugs. This is because the compiler would itself take care of protecting parameters from being changed that should not be changed otherwise!
- Code would be tighter giving the optimizer some additional information
- Last and most importantly - your code becomes more and more readable!
There is a nice cheat-sheet on what kind of variables go where (Text Segment, Code Segment, Stack, Heap) for quick reference here.