How to answer this interview test about constant pointers? - c

I had an interview in which they had asked me this question
#include<stdio.h>
int main ()
{
int* const p=NULL;
int const *q=NULL;
p++;
q++;
printf("%d\n",p);
printf("%d\n",q);
}
How will above program behave
a) p will increment 4 bytes;
and q will also increment 4 bytes;
b) p will be zero
q will point to memory 4 bytes ahead;
c) error will come in above program
I am not able to understand what is the difference between the statements
int* const p=NULL;
int const *q=NULL;

int* const p=NULL;
p is a constant-pointer to an integer. The pointer IS constant (the pointer value cannot be changed); the integer pointed to is not constant (the integer value can be modified).
So statement:
p++;
will fail to compile because trying to modify a constant value (the pointer).
and statement:
(*p)++;
will increment the integer value being pointed by pointer p (but because p is assigned NULL, it will be undefined behaviour)
int const *q=NULL;
q is a pointer to a constant-integer.The pointer is not constant (the pointer value can be changed); the integer pointed to IS constant (the integer value cannot be modified).
So statement:
q++;
will modify pointer q to point to memory 4 bytes ahead (assuming sizeof(int) is 4). (because q is assigned NULL, q will be 0x4 -- I assume NULL is zero (which is true in all current implementation), incrementing NULL pointer is actually undefined behaviour )
and statement:
(*q)++;
will fail to compile because trying to modify a constant value (the integer pointed to is a constant)

How will above program behave?
This is rather simple to answer: the program will not compile.
The postfix ++ requires a modifiable lvalue as its argument; p is not modifiable because it is const-qualified.
The const after the * means that the pointer is qualified; if the const appears before the * as it does in the declaration of q, it means that the object referred to by the pointer is qualified. You can decode the C declarator syntax using the clockwise/spiral rule.
If you remove p and all references to it from the program so that only the lines containing q remain, the answer is that the program exhibits undefined behavior: you cannot perform arithmetic on a null pointer (at least not if the result is not the null pointer).

http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html
They specifically say there:
An interesting extra feature pops up
now. What does this mean?
char c; char *const cp = &c;
It's simple really; cp is a pointer to
a char, which is exactly what it would
be if the const weren't there. The
const means that cp is not to be
modified, although whatever it points
to can be—the pointer is constant, not
the thing that it points to. The other
way round is
const char *cp;
which means that now cp is an
ordinary, modifiable pointer, but the
thing that it points to must not be
modified. So, depending on what you
choose to do, both the pointer and the
thing it points to may be modifiable
or not; just choose the appropriate
declaration.

For answering this question and many more questions about const and pointers you have to understand something basic. I will explain it verbally first, and then with an example:
A pointer object can be declared as a const pointer or a pointer to a const object (or both):
A const pointer cannot be reassigned to point to a different object from the one it is initially assigned, but it can be used to modify the object that it points to (called the "pointee"). Reference variables are thus an alternate syntax for constpointers.
A pointer to a const object, on the other hand, can be reassigned to point to another object of the same type or of a convertible type, but it cannot be used to modify any object.
A const pointer to a const object can also be declared and can neither be used to modify the pointee nor be reassigned to point to another object.
Example:
void Foo( int * ptr,
int const * ptrToConst,
int * const constPtr,
int const * const constPtrToConst )
{
*ptr = 0; // OK: modifies the "pointee" data
ptr = 0; // OK: modifies the pointer
*ptrToConst = 0; // Error! Cannot modify the "pointee" data
ptrToConst = 0; // OK: modifies the pointer
*constPtr = 0; // OK: modifies the "pointee" data
constPtr = 0; // Error! Cannot modify the pointer
*constPtrToConst = 0; // Error! Cannot modify the "pointee" data
constPtrToConst = 0; // Error! Cannot modify the pointer
}

I have just put the code provided and ran it,
the
I then compiled it,and an error of read only pointer can not be modified and in our case incremented as below abort compilation
I want just only to give an example of where we can not use const pointers.
Another example from the network simulator ns3 that clarifies constant pointer usage. when we define error model that will examine arriving packets.
a function na
After IsCorrupt return true(in case of error), then the program can then drop or delete the packet from its data buffer.
bool IsCorrupt (Ptr<Packet> pkt);
Note that we do not pass a const pointer, thereby allowing the function to modify the packet if IsCorrupt() returns true.

Related

What is the difference between derefencing and assigning the address of a variable to pointer variable in C?

See the two codes below!
int main() {
int a = 12;
int *p;
*p = a;
}
and the this code,
int main() {
int a = 12;
int *p;
p = &a;
}
In the first piece of code dereferenced the pointer as this *p = a, and in the second piece of code, the address of variabe a is set to the pointer variable.
My question is what is the difference between both pieces of codes?
In your first piece of code:
int main() {
int a = 12;
int *p;
*p = a;
}
you have a serious case of undefined behaviour because, what you are trying to do is assign the value of a to the int variable that p currently points to. However, p has not been assigned an 'address', so it will have an arbitrary - and invalid - value! Some compilers may initialise p to zero (or NULL) but that is still an invalid address (on most systems).
Your second code snippet is 'sound' but, as it stands, doesn't actually achieve anything:
int main() {
int a = 12;
int *p;
p = &a;
}
Here, you are assigning a value (i.e. an address) to your pointer variable, p; in this case, p now points to the a variable (that is, it's value is the address of a).
So, if you appended code like this (to the end of your second snippet):
*p = 42;
and then printed out the value of a, you would see that its value has been changed from the initially-given 12 to 42.
Feel free to ask for further clarification and/or explanation.
Declaring *p and a is reserving some space in memory, for a pointer in first case, for what a is in the 2nd case (an int).
In these both cases, their values are not initialized if you don't put anything in it. That doesn't mean there is nothing in it, as that is not possible. It means their values are undetermined, kind of "random" ; the loader just put the code/data in memory when requested, and the space occupied by p, and the one occupied by a, are both whatever the memory had at the time of loading (could be also at time of compilation, but anyway, undetermined).
So you take a big risk in doing *p = a in the 1st case, since you ask the processeur to take the bytes "inside" a and store them wherever p points at. Could be within the bounds of your data segments, in the stack, somewhere it won't cause an immediate problem/crash, but the chances are, it's very likely that won't be ok!
This is why this issue is said to cause "Undefined Behavior" (UB).
When you initialized a pointer you can use *p to access at the value of pointer of the pointed variable and not the address of the pointed variable but it's not possible to affect value like that (with *p=a). Because you try to affect a value without adress of variable.
The second code is right use p = &a
The first one is bad:
int main() {
int a = 12;
int *p;
*p = a;
}
It means: put the value of variable a into location, pointed by pointer p. But what the p points? probably nothing (NULL) or any random address. In best case, it can make execution error like access violation or segmentation fault. In worst case, it can overwrite any existing value of totally unknown variable, resulting in problems, which are very hard to investigate.
The second one is OK.
int main() {
int a = 12;
int *p;
p = &a;
}
It means: get the pointer to (existing) variable a and assign it to pointer p. So, this will work OK.
What is the difference between dereferencing and assigning the address of a variable to pointer variable in C?
The latter is the premise for the first. They are separate steps to achieve the benefit of pointer dereferencing.
For the the explanation for where the difference between those are, we have to look what these guys are separately:
What is dereferencing the pointer?
First we need to look what a reference is. A reference is f.e. an identifier for an object. We could say "Variable a stands for the value of 12." - thus, a is a reference to the value of 12.
The identifier of an object is a reference for the value stored within.
The same goes for pointers. pointers are just like usual objects, they store a value inside, thus they refer to the stored values in them.
"Dereferencing" is when we "disable" this connection to the usual value within and use the identifier of p to access/refer to a different value than the value stored in p.
"Dereferencing a pointer" means simply, you use the pointer to access the value stored in another object, f.e. 12 in a instead through its own identifier of a.
To dereference the pointer the * dereference operator needs to precede the pointer variable, like *p.
What is assigning the address of a variable to a pointer?
We are achieving the things stated in "What is dereferencing a pointer?", by giving the pointer an address of another object as its value, in analogy like we assign a value to a usual variable.
But as opposed to usual object initializations/assignments, for this we need to use the & ampersand operator, preceding the variable, whose value the pointer shall point to and the * dereference operator, preceding the pointer, has to be omitted, like:
p = &a;
Therafter, The pointer "points" to the address the desired value is stored at.
Steps to dereferencing a pointer properly:
First thing to do is to declare a pointer, like:
int *p;
In this case, we declare a pointer variable of p which points to an object of type int.
Second step is to initialize the pointer with an address value of an object of type int:
int a = 12;
p = &a; //Here we assign the address of `a` to p, not the value of 12.
Note: If you want the address value of an object, like a usual variable, you need to use the unary operator of &, preceding the object.
If you have done these steps, you are finally be able to access the value of the object the pointer points to, by using the *operator, preceding the pointer object:
*p = a;
My question is what is the difference between both pieces of codes?
The difference is simply as that, that the first piece of code:
int main() {
int a = 12;
int *p;
*p = a;
}
is invalid for addressing an object by dereferencing a pointer. You cannot assign a value to the pointer´s dereference, if there isn´t made one reference before to which the pointer do refer to.
Thus, your assumption of:
In the first piece of code I dereferenced the pointer as this *p = a...
is incorrect.
You do not be able to dereference the pointer at all in the proper way with *p = a in this case, because the pointer p doesn´t has any reference, to which you are be able to dereference the pointer correctly to.
In fact, you are assigning the value of a with the statement of *p = a somewhere into the Nirwana of your memory.
Normally, the compiler shall never pass this through without an error.
If he does and you later want to use the value, which you think you´d assigned properly by using the pointer, like printf("%d",*p) you should get a Segmentation fault (core dumped).

Why is it not possible to modify the value at the next addresses after an address that is passed by reference as const in a function?

I have the following code and I am confused why is it now working:
#include<stdio.h>
void modif(const int *p)
{
*(p+1)=5;
}
int main()
{
int a=1;
printf("\n%d",a);
modif(&a);
printf("\n%d",a);
return 0;
}
The error I am getting is this one:
main.c: In function 'modif':
main.c:6:9: error: assignment of read-only location '*(p + 4)'
*(p+1)=5;
^
exit status 1
In my opinion the address next to p should be modifiable. I have tried to modify the values at addresses that were further away and the result was the same.
When using "const" keyword before a parameter passed by reference what is the first address that is actually modifiable?
This statement
*(p+1)=5;
is problematic for a couple of reasons.
p is const-qualified. So that's the reason for the error you get.
You violate the promise you made to the compiler (that you wouldn't modify the object pointed to by p).
If you didn't have the const qualifier, it's still wrong.
Because the object that p points to is a single int, so dereferencing p+1 is undefined behaviour.
Note that evaluating p+1 is fine even if p points to a single int object. It's allowed per C11, 6.5.6/9.
But dereferencing it is not valid.
If there's a valid object at p + 1 (provided that object itself is mutable - otherwise, this will be undefined behaviour), you could cast away the const in modif() and legally modify it. For example, the below is valid (but not something I recommend - if you want modif to be able to modify a's contents, it doesn't make sense to qualify p with const here).
#include<stdio.h>
void modif(const int *p)
{
int *q = (int*)p;
*(q+1)=5;
}
int main()
{
int a[2] = {0};
modif(a);
printf("\n%d, %d",a[0], a[1]);
return 0;
}
'In my opinion the address next to p should be modifiable'
Authors of C language have opposite opinion. And it's their opinion which counts.
The C semantics allows you to perform a so-called pointer arithmetics, which includes adding and subtracting integers to/from typed pointers. The pointer value resulting from such operation points to an element of the same array, respective number of items farther or earlier in the array.
However the const modifier applies to the whole array (despite its size being not specified), so it does not vanish in such operation. If it did, you could just do *((p+1)-1) to access a *p variable without the const restriction!
You're just passing a pointer which in C may point to an arbitrarily sized array of objects -- size 1 for a single object is just one possible case. It's your job as a programmer to find means how the function knows how many objects there are.
If the pointer is a pointer to a const, this means the whole array is immutable.
In your code, your pointer only points to a single object, so accessing the non-existing object at index 1 is just undefined behavior. If this object would exist, would you expect it to be modifyable through a const pointer? Of course not ...

What exactly does "const int *ptr=&i" mean?Why is it accepting addresses of non-constants?

Your answers are very much sought to clear this major lacuna in my understanding about const that I realized today.
In my program I have used the statement const int *ptr=&i; but haven't used any const qualifier for the variable i.Two things are confusing me:
1) When I try to modify the value of i using ptr ,where I have used const int *ptr=&i;,I get the error assignment of read-only location '*ptr'|,even though I haven't declared the variable i with the const qualifier.So what exactly the statement const int *ptr=&i; mean and how does it differ from int * const ptr=&i;?
I had it drilled into my head that const int *ptr=&i; means that the pointer stores the address of a constant,while int * const ptr=&i; means the pointer is itself constant and can't change.But today one user told me in discussion(LINK) that const int *ptr means the memory pointed to must be treated as nonmodifiable _through this pointer_.I find this something new as this kinda means "some select pointer can't alter the value(while others can)".I wasn't aware of such selective declarations!!But a 180k veteran attested to it that that user is correct!!.So can you state this in a clearer,more detailed and more rigorous way?What exactly does ``const int *ptr=&i; mean?
2) I was also told that we can lie to the program in the statement const int *ptr=&i; by assigning the address of a non-constant to the pointer.What does it mean?Why are we allowed to do that?Why don't we get a warning if we assign the address of a non-constant to the pointer ptr which expects address of a constant?And if it is so forgiving about being assigned address of non-constant,why it throws an error when we try to change the value of that non-constant,which is a reasonable thing to do,the pointed variable being a non-constant?
#include <stdio.h>
int main ()
{
int i=8;
const int *ptr=&i;
*ptr=9;
printf("%d",*ptr);
}
error: assignment of read-only location '*ptr'|
The definition const int *ptr = &i; essentially says “I will not modify i through ptr.” It does not say that the int that ptr points to is const, it says that ptr should not be used to modify it.
This conversion is allowed because it makes sense: Since i is not const, I am allowed to modify it, but I can also choose not to modify it. No rule is broken when I choose not to modify i. And, if I create a pointer to i and say “I am not going to use this pointer to modify i”, that is fine too.
The reason you would want to do this is so that you can pass the address of an object to a routine that takes a pointer to a const object. For example, consider the strlen routine. The strlen routine does not modify its input, so its parameter is a pointer to const char. Now, I have a pointer to char, and I want to know its length. So I call strlen. Now I am passing a pointer to char as an argument for a parameter that is pointer to const char. We want that conversion to work. It makes complete sense: I can modify my char if I want, but the strlen routine is not going to, so it treats them as const char.
1) You get an error with *ptr = something; because you declared ptr as a pointer to const int, but then you violated your promise not to use ptr to modify the int. The fact that ptr points to an object that is not const does not negate your promise not to use ptr to modify it.
2) It is not a lie to assign the address of a non-const object to a pointer to const. The assignment does not say that the object is const, it says that the pointer should not be used to modify the object.
Additionally, although you have not asked this, the const attribute in C is not completely binding. If you define an object to be const, you should not modify it. However, there are other situations in which a pointer to const is passed to a routine that converts it to a pointer to non-const. This is effectively a defect in the language, an inability to retain all the information necessary to handle const in the ways we might prefer. An example is the strchr routine. Its declaration is char *strchr(const char *s, int c). The parameter s is const char * because strchr does not change its input. However, the pointer that strchr routines is derived from s (it points to one of the characters in the string). So, internally, strchr has converted a const char * to char *.
This allows you to write code that passes a char * to strchr and uses the returned pointer to modify the string, which is fine. But it means the compiler cannot completely protect you from mistakes such as passing a const char * to strchr and using the returned pointer to try to modify the string, which may be an error. This is a shortcoming in C.
Unravelling this:
const int *ptr means that "*ptr is a const int"; i.e. "ptr is a pointer to a const int". You can't write *ptr = 9 since *ptr is a constant. You can however write int j; ptr = &j; since you can allow the pointer ptr to point at a different int.
int * const ptr means "ptr is a constant pointer to an int". You can write *ptr = 9 since you are not changing the address that ptr is pointing to. You can't assign it to something else though; i.e. int j; ptr = &j; will not compile.
As for the second part (2), it's very useful to have const int* ptr, especially in function prototypes since it tells the caller of the function that the variable to which ptr is pointing will not be modified by the function. As for assignment, if you had int* m = &i, then ptr = m is ok but m = ptr is not ok since the latter will 'cast away the constness'; i.e. you've circumvented the const.

Pointer and Memory from Stanford

I am reading article from Stanford CS library http://cslibrary.stanford.edu/102/
Bad Pointer Example
Code with the most common sort of pointer bug will look like the above correct code, but without the middle step where the pointers are assigned pointees. The bad code will compile fine, but at run-time, each dereference with a bad pointer will corrupt memory in some way. The program will crash sooner or later. It is up to the programmer to ensure that each pointer is assigned a pointee before it is used. The following example shows a simple example of the bad code and a drawing of how memory is likely to react...
void BadPointer() {
int* p; // allocate the pointer, but not the pointee
*p = 42; // this dereference is a serious runtime error
}
// What happens at runtime when the bad pointer is dereferenced...
But I remember that char* should be defined like this
char *const name_ptr = "Test";
In this way, if everyone think about if this char* is a bad define?
The line
char *const name_ptr = "Test";
is fine; you're initializing the pointer with the address of the string literal "Test", which is an array of char stored in such a way that the memory for it is allocated at program startup and held until the program terminates.
A quick digression on the const qualifier:
In C, declaration of the form
const T foo = expr;
or
T const foo = expr;
means that foo may not be written to; it's assigned the value of expr when it's created, and that value may not be changed for the rest of foo's lifetime1). With pointer variables, it gets a little more complicated:
const T *p = expr;
T const *p = expr;
both declare p as a non-const pointer to const data; IOW, you can change the value of p (p can point to different objects), but not the value of *p (you cannot change the value of what p points to).
T * const p = expr;
declares p as a const pointer to non-const data; you can change the value of what p points to (*p = ...), but you cannot change p to point to a different object.
const T * const p = expr;
T const * const p = expr;
both declare p as a const pointer to const data; you cannot change either the value of p or what p points to.
In C, string literals such as "Test" are stored as arrays of char, but attempting to modify the contents of a string literal is undefined behavior (depending on the platform, you may get an access violation). For safety's sake, it's usually a good idea to declare pointers to string literals as const char * or char const *, rather than char * const as in the example above.
As far as
void BadPointer() {
int* p; // allocate the pointer, but not the pointee
*p = 42; // this dereference is a serious runtime error
}
is concerned, p is an auto variable, which is not initialized to any particular value; it will contain a random bit string that may or may not correspond to a writable address. Because of this, the behavior of the statement *p = 42; is undefined - you may get an access violation, you may wind up overwriting something important and leave the program in a bad state, or it may appear to "work" with no issues (writing to some random memory area that is accessible and not important).
In general, it's impossible to tell whether a given pointer value is valid or invalid from the pointer value alone2). The one exception is the special pointer value NULL, which is a well-defined "nowhere" that's guaranteed to compare unequal to any valid pointer value. Pointer variables declared at file scope (outside of any function) or with the static qualifier are implicitly initialized to NULL. Non-static, block-scope pointer variables should always be explicitly initialized with either NULL or a valid address. This way you can easily check to see if the pointer has been assigned a valid value:
int *p = NULL;
...
if (p != NULL) // or simply if (p)
{
*p = 42;
}
else
{
// p was not assigned a valid memory location
}
1) Note that, in C, foo is not a compile-time constant; it's a regular run-time variable, you just cannot write to it. You cannot use it in a context that requires a compile-time constant.
2) If you're intimately familiar with your platform's memory model you can make some educated guesses, but even then it's not guaranteed.
In the second case:
char *const name_ptr = "Test";
You are creating a string literal that placed in read-only memory. Therefore you can have a legit pointer to it.
In the first case:
void BadPointer() {
int* p; // allocate the pointer, but not the pointee
*p = 42; // this dereference is a serious runtime error
}
you will get an Undefined Behavior (UB).
char *const name_ptr means that name_ptr is a constant pointer to a char (it is the pointer which is constant).
You probably mean const char * name_ptr = "Test"
(name_ptr is a pointer to a character that is constant)
The thing is that "Test" is a string, which is an array of chars, stored somewhere in (probably) constant memory. Since the memory is allocated, then that is fine to initialise the pointer to point at it.
int *p; is an uninitialised pointer. It has some undefined value which might or might not resolve to a sensible memory location - odds are that it won't but you never know. Saying *p = 42; will overwrite that arbitary memory location with 42, then all bets for your program are off.
In a case like this, it helps to remember that a pointer is nothing more than a normal variable that holds a value - the only "magic" part about it is that value represents a location in memory, and you can dereference that location to access what's stored there.
Imagine a bit of code like this:
void BadPrinter() {
int p;
printf("%d\n", p);
}
What would it print? Who knows? Maybe 0, maybe garbage, maybe the lyrics to "Come Sail Away" by Styx encoded as an integer.
Now we go back to your pointer code:
void BadPointer() {
int* p; // allocate the pointer, but not the pointee
*p = 42; // this dereference is a serious runtime error
}
p is uninitialized in the exact same way - it could contain anything. So when you do *p, you're asking the compiler to give you access to whatever memory is represented by the number contained in p.
So if p happens to contain 0, you're now trying to stuff the value 42 into the memory location 0x0: your program will probably crash. If p happens to contain a location in writable memory, your program will probably continue merrily along, since you will be allowed to store 42 at that location.
Now this case is a little different:
char *const name_ptr = "Test";
Here you're asking the compiler to allocate enough memory space to store the string "Test" and store the location of that memory in name_ptr. Going back to our first example, it would be analogous to:
void GoodPrinter() {
int p = 4;
printf("%d\n", p);
}

Strange (for me) behavior of pointers

I'm reading about pointers, but i'm confused about their nature. Here is what I mean.
int x = 4;
//Here I declare p as integer pointer
int *p;
// Here I assign memory address of x to pointer p
p = &x;
// The line below prints result 4 which is expected. If I miss asterisk before p I'll get memory address instead of data which that memory address holds.
printf("%d", *p)
Summarizing when asterisk is mising before pointer it "points" to memory address. If asterisk preceded pointer it "points" to actual data.
So far so good.
But why that segment of code works correctly ?
int someIntVariable = 10;
const int *p = &someIntVariable;
printf("%d", *p);
If I miss asterisk the compiler gives me an warning " warning: initialization makes integer from pointer without a cast"
I expected p (if the compiler allows me to use p without asterisk) to hold memory address of someIntVariable instead of it's "value";
What is happening here ?
In the declaration:
const int *p = &someIntVariable;
The asterisk is not the dereference operator. It simply states p is a pointer. That line has the same effect as
const int *p;
p = &someIntVariable;
Here you are declaring a pointer and assigning a value to the pointer in one step.
It is equivalent to the following code:
const int *p;
p = &someIntVariable;
Here the * is not used as a de-referencing operator. It is used in the context of pointer declaration.
The const int * is a datatype - i.e. pointer to a const int. p is the name of the variable. It is on the LHS.
When asterik is on the RHS it has a different meaning. It means dereference.
I belive you got the warning:initialization makes integer from pointer without a cast,
when you tried these way
int someIntVariable = 10;
const int p = &someIntVariable;
printf("%d", p);
What your trying to do is , Your assigning a address to a normal variable and your expecting it to work but that is not how the normal variables used thats why pointers came into act to do that job and your trying to replace a pointer with normal variable
I still did not find the real answer to it but Just check out these question that I asked I wonder what really the &a returns?

Resources