I coded something like the following code,and I was able to assign a value to the new address after increasing it but was not able to print this value run time error, Also after assigning a value to the location this pointer pointing to, pointer value changed to be 14. Anyone has an idea of what's going on ?
Why the pointer value itself changed to 14 after assigning value to the location itself ?
I did not get any error after increasing the pointer value too !
#include <stdio.h>
int main()
{
int x = 10;
int *ptr = &x;
printf("%x\n",ptr); // ptr value
ptr++; //No ERROR !!
printf("%x\n",ptr); //ptr value +4 bytes no error!!!
*ptr = 20;
printf("%x\n",ptr); //ptr=14
printf("%x\n",*ptr); // run time error happens here only
return 0;
}
This is undefined behavior. When you incremented the pointer variable then it was pointing to one past the variable x (4 Bytes past in your system). But then you dereference it. First of all the memory you made change to is not allocated by you. And also it is not a location that is already allocated (like part of an array etc). It is Undefined behavior to access it.
And again you can assign it to any possible address. But dereferencing it would be undefined behavior in case the memory address it points to is invalid.
From standard 6.3.2.3
The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator; if it points to an
object, the result is an lvalue designating the object. If the operand
has type ''pointer to type'', the result has type type. If an
invalid value has been assigned to the pointer, the behavior of the
unary * operator is undefined
When you do ptr++, it points "one element" past x. This is allowed, because x in this case is treated as an array of size 1, and a pointer is allowed to point one element past the end of an array. You can also subsequently print the value of that pointer with no problem.
What you can't do however is dereference a pointer to one element past the end. That invokes undefined behavior. In this case that behavior manifested as the pointer having an unexpected value and a subsequent crash.
That being said, here's what probably happened.
ptr was most likely placed right after x in memory, so after doing ptr++, ptr was pointing to itself. So *ptr = 20; had the effect of of setting ptr to 20. The value 14 that was printed is in hex, which is the same as 20 decimal. This explains the value that was printed.
Then you tried to print *ptr, which in this case says "print the int value at address 0x14". That is most likely not a valid address, so attempting to read it caused a crash.
You can't however depend on this behavior. You could add an extra printf or compile with different optimization settings and the observed behavior would change.
Related
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).
I was playing around with pointers, and I tried to initialize a pointer variable with a value and not a memory location.
If I am initializing a pointer with a non-zero value, and it is clearly giving me a compile time error.
int *p = 1;
main.c:14:14: error: initialization makes pointer from integer without a cast [-Werror=int-conversion]
int *p = 1;
^
However, if I initialize it as value 0, it doesn't give me a compile time error.
int *p = 0; //no compile time error but segmentation fault
Why is this so? Is there a valid memory address like 0? Normally, an address location is shown as 0xffffff or similar way. How is 0 interpreted into a memory location?
Thanks
From the C11 Standard (draft):
6.3.2.3 Pointers
[...]
3 An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant. If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
Usualy 0 represent a "no address" asNULL. When you use it that way you can check:
if (p) {
doSomthingWith(*p)
}
You are allowed to assign 0 to a pointer because NULL is typically defined as 0 cast to a void *. Any other integer value is a type mismatch.
While you can cast some other integer value to a pointer to assign it a value, it rarely makes sense to do so unless you're dealing with an embedded environment where specific memory locations have known uses.
You're getting a segfault not because you're printing the pointer but because you dereference the pointer and attempt to print what it points to. Because the pointer has a NULL value, dereferencing it causes undefined behavior. In this case, it results in a segfault.
To print the pointer, do the following:
printf("%p\n", (void *)p);
Why is this so? Is there a valid memory address like 0? Normally, an
address location is shown as 0xffffff or similar way. How is 0
interpreted into a memory location?
Generally, the address 0 is not accessible for most of the operating systems, because they reserve it for other tasks.
In C, the address 0 is interpreted as a NULL pointer and a NULL pointer is a pointer that is interpreted as a pointer that is not referencing a valid memory location accessible by the program.
So, if you are defining int* p = 0 or int* p = NULL the program written in C is assuming that the pointer is pointing to nothing (not a 0xffffff address).
A literal 0 in a pointer context represents a null pointer constant. A 1 is always just a 1 and therefore an int.
In the Following example, I expect that foo((&i)++) will evaluate to foo(4 + address of (i)) assuming that the int size is 4 Byte however it gives a compilation error at this line
anyone has an explanation ?
void foo(int*);
int main()
{
int i = 10;
foo((&i)++);
}
void foo(int *p)
{
printf("%d\n", *p);
}
The error message is "lvalue required for increment operator". The problem is that ++ needs to operate on a variable - you increment, AND STORE THE RESULT.
You cannot store the result of the increment operation in (&i).
To get foo to operate on an integer that is stored at the address you appear to want, you can do one of the following (I'm sure you can think of others):
foo(&i);
int *p = &i; foo(p++);
The second option will correctly call foo with a pointer to i, but will increment that pointer for the next time (which seems to be what you were trying to do with your code - except you had nowhere to put that value. By declaring a separate pointer p, I created that storage space. But realize that p is now pointing "nowhere" - if you access it again, you will get undefined behavior).
If you wanted to point to the next location after the address of i you would have to do
foo(++p);
but that would be undefined behavior (since there is no way of knowing what is stored in the next location after i; most likely it will be p but that is not guaranteed.)
Pointers. Powerful, dangerous, and slightly mysterious.
The operand of ++ must be an lvalue -- a variable or other location in memory that can be modified -- since it adds 1 to it and replaces it with the result. &i is not an lvalue, it's just an expression that yields the address of i.
Also,
foo(4 + address of (i))
is wrong since you're using postfix ++ rather than prefix ++. The value of EXPR++ is EXPR (with the side effect of changing the variable that expr refers to).
To get the value you want, just use
foo(&i + 1)
Note, however, that this is likely to result in undefined behavior ... depending on just what foo does with its argument.
You're incrementing and trying to store back the address of i. How and where does the result get stored back? It can't, because &i doesn't exist in memory.
I think you want to do this instead:
foo((&i)+1);
{
int *p=12;
printf("%p",p);
printf("\n%d",p);
}
OUTPUT:
0000000C
12
Question: So is p assigned the address 0x0000000C?
{
int *p=12;
*p=22;
}
But this one doesn't run. So what's actually happening?
int *p=12;
This declares a pointer and sets the address to which it points to 12.
*p=22;
This de-references the pointer and writes 22 to the int at that memory address 12. Since you did not allocate any memory and just set the pointer to point at a random address, it results in a runtime error.
What is confusing you is that both pieces of code contain *p=.... However, the first assignment is to the pointer, and the second assignment is to the pointee. This is just one of those notational overloadings that you have to get used to when programming in C.
Both cases have undefined behavior.
The behavior of the first example is undefined, as you use an invalid pointer.
The second example is worst, as you derefernce a pointer with invalid address.
int *p=12; // set the address 12 to the int pointer called p
*p=22; // set the value 22 to the address 12 (invalid address)
There have been other question/answers on negative array in C in the forum, but i would request the answer to these for a 32-bit compiler :
If we have an array defined int test_array[5] = {1,2,3,4,5};
then what should following statements return
test_array[20], test_array[-2], test_array[-32764], test_array[4294967700](value greater than what 32 bit can accommodate), *(a-32764) etc
Does the compiler force any fixed value to be returned in case index go beyond its declared range ?
It is indefined behaviour as you write it since you are accessing the array out-of-bounds.
However, negative indices do not necessarily mean undefined behaviour. The following code is well defined:
int test_array[5] = {1,2,3,4,5};
int *p = test_array + 1;
int i = p[-1];//i now has the value 1
This is equivalent to:
int i = *(p-1);
Accessing an array beyond its bounds results in Undefined Behavior(UB).
An -ve index is not an valid index and results in Undefined Behavior.
An Undefined Bheavior means anything can happen literally, If you are lucky your program will crash and the problem gets detected, If you are unlucky the code works fine all along and all hell breaks loose some day.
So, always avoid writing any code which causes an Undefined Behaivor.
Does the compiler force any fixed value to be returned in case index go beyond its declared range ?
NO
The programmer has to take care of this. The Standard does not need the compiler to give you any indication/warning for this.The standard just defines it as an UB.
Furthermore the standard identifies all of the following scenarios to cause Undefined Behavior:
Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that does not point into, or just beyond, the same array object.
Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond the array object and is used as the operand of a unary * operator that is evaluated.
An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]).
Accessing elements outside the array is Undefined Behaviour.
Furthermore, making a pointer point to an element outside of the array, except for the (inexistant) one-past-the-last, is also Undefined Behaviour. Accessing the one-past-the-last is Undefined Behaviour (the pointer existence is ok)
int arr[42] = {0};
int *ptr = arr;
ptr += 41; /* ok, ptr points to the last element of arr */
*ptr; /* ok */
ptr += 1; /* ok, ptr points to one-past-the-last */
*ptr; /* UB */
ptr += 1; /* UB */
ptr = arr;
ptr -= 1; /* UB */