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);
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 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.
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 ...
Questions are based on the following code :
struct t
{
int * arr;
};
int main()
{
struct t *a = malloc(5*sizeof(struct t));
a[2].arr = malloc(sizeof(int));//line 1
a[2].arr[1] = 3; //line 2
}
In line 2 I'm accessing the array arr using the . (dot) operator and not the -> operator. Why does this work?
When i rewrite line 2 as (a+2)->arr[1] = 3 this works. But if I write it as (a+2)->(*(arr+1)) = 3 I get a message as expected identifier before '(' token. Why is this happening?
For line 1, the dot operator works in this case, because the array access dereferences the pointer for you. *(a+2) == a[2]. These two are equivalent in both value and type.
The "->" operator, expects an identifier after it, specifically the right argument must be a property of the type of the left argument. Read the messages carefully, it really is just complaining about your use of parentheses. (Example using the . operator instead: a[2].(arr) is invalid, a[2].arr is just dandy.)
Also, if we can extrapolate meaning from your code, despite its compilation errors, there is the potential for memory related run time issues as well.
-> dereferences a pointer and accesses its pointee. As you seem to know a[1] is equivalent to *(a + 1), where the dereference already takes place.
The expression (a+2)->arr[1] is equivalent to *((a+2)->arr + 1).
You allocated one single struct t for a[2].arr, then wrote in the second one. Oops.
a[2] is not a pointer. The indexing operator ([]) dereferences the pointer (a[2] is equivalent to *(a+2)).
(*(arr+1)) is an expression. If you want to do it that way, you want to get the pointer (a+2)->(arr+1), then derefrence it: *((a+2)->arr+1). Of course, since you've only malloced enough memory for one int, this will attempt to access unallocated memory. If you malloc(sizeof(int)*2), it should work.
I got surprised when the following program did not crash.
typedef struct _x {
int a;
char b;
int c;
} x;
main() {
x *ptr = 0;
char *d = &ptr->b;
}
As per my understanding the -> operator has higher precedence over & operator. So I expected the program to crash at the below statement when we try to dereference the NULL pointer tr.
char *d = &ptr->b;
But the statement &ptr->b evaluates to a valid address. Could somebody please explain where I'm wrong?
Your expectations were unfounded. C programs don't necessarily "crash" when you dereference null pointers. C programs exhibit so called undefined behavior when you attempt to do something like that. Undefined behavior can manifest itself in many different ways. It can result in a crash. Or it can produce something that even resembles a "working" program. The latter is what apparently happened in your case.
But in any case, your program's behavior is undefined. And no, it does not produce a "valid address" as you seem to mistakingly believe. A numerical address that corresponds to a location in memory where no object exists is not valid (with the exception of null pointer value, of course).
The reason that your code doesn't crash is that you didn't actually dereference the pointer. Notice that the expression
&ptr->b
doesn't actually try loading the contents of ptr or ptr->b. Instead, it just stores the address of where this is located in memory. What you'll end up getting is a pointer to where the b field of the object pointed at by ptr should be. This will be a few bytes past address 0, so dereferencing the pointer you just created will cause a segfault.
&ptr->b == sizeof(int), that means the offset of b within _x after _x.a (which is of type int) relative to the address *((x*)0). The offset of 4 (typical for 32bit architecture) is saved within the d pointer. You have to access to d in order to get an seg-fault.
Computing an address does not require accessing memory. &ptr->b means "give me the address of the b field of the structure pointed to by ptr." Doing so does not require looking at whatever may be stored in that memory location.
It may be helpful to think about indexing an array instead of a structure. C defines ptr[5] as equivalent to *(ptr + 5) , which means that &(ptr[5]) is the same as &(*(ptr + 5)). Now it's easy to see that the & and the * "cancel out" and leave you with (ptr + 5), which involves only a pointer increment, and not a load from memory.
C makes this slightly cloudy because it distinguishes lvalues from rvalues. That is, an expression that refers to memory is treated differently on the left hand side of an expression than it is on the right. Given a statement like x = y;, a C compiler will load a value from the address of y, and store it in the address of x. This is the distinction: y is implicitly dereferenced, but x is not.