++*P--;
That is a question from an exam, if P a pointer to any element in an array, explain what this statement really does.
I even wrote a simple code to evaluate it:
int i;
int* array = calloc(10, sizeof(int));
for (i = 0; i < 10; i++) {
array[i] = i;
printf("%d,", array[i]);
}
int* P = array + 5;
printf("\n %p", P);
printf("\n %d", *P);
++*P--;
printf("\n %p", P);
printf("\n %d \n", *P);
for (i = 0; i < 10; i++) {
printf("%d,", array[i]);
}
But the output confuses me even more:
0,1,2,3,4,5,6,7,8,9,
0x100105534
5
0x100105530
4
0,1,2,3,4,6,6,7,8,9,
It looks like it first dereferences P, then increases its value and then decreases value of pointer P, but why?
According to K&R table 2-1 from p53 (see the picture below)
++, --, and * (dereference) has the same precedence and associativity from right to left.
So first step should be decreasing value of P, then dereference and then increasing dereferenced value, am I wrong?
You are correct that the precedence is
++(*(P--))
But note that the decrement is a postfix operation: even though the change to P happens first, the rest of the expression uses the old value of P. So in your example, first P is decremented to array+4, but the value of P-- is array+5, so array[5] gets incremented.
You can imagine this expression
++*P--
the following way
int *tmp = p;
--p;
int value = *tmp;
++value;
Here is a demonstrative program
#include <stdio.h>
int main( void )
{
char s[] = "Hello World";
char *p = s + 6;
std::printf( "%c\n", ++*p-- );
std::printf( "%s\n", s );
p = s + 6;
char *tmp = p--;
char value = *tmp;
++value;
std::printf( "%c\n", value );
std::printf( "%s\n", s );
}
The program output is
X
Hello Xorld
Y
Hello Xorld
The difference in the outputting the string is that expression ++*p-- changes the string itself but expression ++value; changes a separate object. But the logic is similar.
Postfix expression p-- has the highest priority but its value is the value of p before decreasing.
Unary operators ++ and * in expression ++*p-- group right to left. So at first operator * is applied to the expression and after that operator ++ is applied.
Related
I did a recursion exercise and I could not understand what is the difference between doing *p++ or *p+=1.
Both of them should add 1 to the value pointed at but for some reason *p+=1 works and *p++ doesn't.
void rec(char a[], int *p ,int i)
{
if(a[i+1]== '\0')
return;
if(a[i]==a[i+1])
*p+=1;
rec(a, p, i+1);
}
void rec(char a[], int *p ,int i)
{
if(a[i+1]== '\0')
return;
if(a[i]==a[i+1])
*p++;
rec(a, p, i+1);
}
*p += 1; means, dereference the pointer p and then increment the dereferenced value by 1. While *p++; means
*p;
p += 1; // Increment the pointer itself
This is because ++ has higher precedence than * operator so compiler will parse it as *(p++);.
(*p)++ is equivalent to *p += 1;.
Precedence wise
++ > * > +=
Here *p+=1 is increasing the value that is pointed by p. Here the value at the memory location pointed by p is incremented. You can see the change in your code.
In the second case, *p++ it is just increasing the pointer p and then it de-references the value but you don't assign that r-value anywhere. This is not changing the actual content that there is in the memory pointed by p.
That is why in second case you don't see any change in the working variables and concluded that it doesn't work which is certainly not the case.
I am trying to wrap my head around "pointer to a pointer". And I tried some experiments and I got stuck here for a while:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
}
And I got this as output:
printing
Source: 4
Output by pointer: 4, 4
Output by pointer to a pointer: 4, 4
printing
Source: 5
Output by pointer: 5, 5
I don't understand why after 1 loop, the program stop at the 2nd loop- line 9. Did I misunderstand anything basic knowledge or something else.
Thank you for reading.
Change the last printf to:
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
You're basically using *pp in place of p, but the * operator doesn't group as tightly as [] so you need to use parentheses in the first form. In the second form, you need to dereference pp before adding i, after which the result is dereferenced.
For starters it is unclear why there is used the magic number 4 in the loop instead of the number 5 that is the number of elements in the array
for ( int i = 0; i < 4; i ++)
^^^^^
The pointer pp does not point to first element of an array. It points to a single object
int **pp = &p;
So these expressions
*pp[i] (that is equivalent to *(pp[i] )
and
**(pp + i)
does not make sense.
An expression using the pointer p can be written using the pointer pp like *pp.
So these correct expressions
p[i]
and
*(p + i)
can be written using the pointer pp the following way (just substitute p for *pp taking into account operation precedences)
( *pp )[i]
and
*( *pp + i )
You acesses to pointer thru pointer-to-pointers are wrong:
you must access the pointee as the array:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
}
This line is wrong
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
You need to change it to
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
so that you dereference the double pointer before using it as a normal pointer.
You can think of it like this:
p is the same as (*pp)
In other words - in a valid expression that uses p you are allowed to substitute p with (*pp). That is
p[i] --> (*p)[i]
*(p + i) --> *((*pp) + i) --> *(*pp + i)
Notice that the parenthesis is important. The parenthesis can be removed in the second example but not in the first as [] has higher precedence than *.
Doing pp + i generates a pointer that doesn't point to any valid object. So when you dereference it using **(pp + i) you do an illegal access an your program crashes.
As per my understanding, in the line marked as 'line 2' of the below code, the expression (*ptr)++ should generate "lvalue required" error because *ptr evaluates to a constant value of i=1, which is not lvalue?
So why is the program working successfully? Or am I somewhere wrong in my concepts? If yes, please enlighten me on this.
int main(void)
{
int i;
int *ptr = (int *) malloc(5 * sizeof(int));
for (i=0; i<5; i++)
*(ptr + i) = i;
printf("%d ", *ptr++); //line 1
printf("%d ", (*ptr)++); //line 2
printf("%d ", *ptr); //line 3
printf("%d ", *++ptr); //line 4
printf("%d ", ++*ptr); //line 5
}
You're having a misconception. result of (*ptr) is lvalue, upon which the post increment operator can be applied.
So, in your case,
printf("%d ", (*ptr)++); //line 2
is fine.
To quote C11 standard, chapter ยง6.5.3.2, Address and indirection operators, (emphasis mine)
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.
FWIW, if *ptr would not be a lvalue, you would have got error for writing something like *ptr = 5 also, wouldn't it?
What about int i = 0; i++;. If i is 0, then is 0++ valid? The answer is of course no, 0++ (and 1++) are not valid. ++ is not applied to the value, it's applied to the object (in this case i, or in your case, the object pointed to by *ptr).
An lvalue is something that refers to someplace in memory that can/does hold a value.So if *ptr=10; then *ptr is lvalue.
#include <stdio.h>
int main(void) {
int i = 42;
int *ptr = &i; /* ptr points to i */
(*ptr)++; /* you increment the pointed value */
printf("%d", i); /* and there is a proof: 43 is displayed */
return 0;
}
This question already has answers here:
pointer increment and dereference (lvalue required error)
(4 answers)
Closed 8 years ago.
I'm having getting an error related to lvalue in this code:
#include <stdio.h>
#include<string.h>
main()
{
int a[]={10,20,30,40,50};
int j;
for(j=0;j<5;j++)
{
printf("%d\n",a);
a++;
}
return 0;
}
The error is displayed is:
lvalue is required as an increment operator.
Why is this problem occuring?
Any help will be appreciated.
You are trying to increment a int[] variable but that kind of variable doesn't support the increment operator.
If you were trying to iterate over the array you just need to use the variable used as the loop condition with the subscript operator:
for (int j = 0; j < 5; ++j)
printf("%d\n",a[j]);
The main problem is that the ++x operator is semantically equivalent to x = x + 1, x. This requires x to be assignable (lvalue) (since you assign a new value to it) but an array is not assignable.
In this expression
a++;
a temporary object of type int * is created that points to the first element of array a. You may not increment temporary objects. It is the same if you would write for example
int x = 10;
( x + 0 )++;
You could write the program the following way
#include <stdio.h>
int main()
{
int a[] = { 10, 20, 30, 40, 50 };
int *p;
for ( p = a; p != a + sizeof( a ) / sizeof( *a ); ++p )
{
printf( "%d\n", *p );
// or printf( "%p\n", p ); depending on what you want to output
}
return 0;
}
While it's true that arrays decays to pointers, an array is not a pointer, and you can't e.g. increment it.
Instead you can let it decay to a pointer by doing e.g.
printf("%d\n", *(a + j));
as in the title, what's the difference because these two seem to get me the same results?
No they are not the same. Assume that d is a pointer to int:
int n = 0;
int* d = &n;
*d++; // d++ then *d, but d++ is applied after the statement.
(*d)++; // == n++, just add one to the place where d points to.
I think there is an example in K&R where we need to copy a c-string to another:
char* first = "hello world!";
char* second = malloc(strlen(first)+1);
....
while(*second++ = *first++)
{
// nothing goes here :)
}
The code is simple, put the character pointed by first into the character pointed by second, then increment both pointers after the expression. Of course when the last character is copied which is '\0', the expression results to false and it stops!
The increment ++ has higher operator precedence than the dereference *, so *d++ increments the pointer d to point to the next location within the array, but the result of ++ is the original pointer d, so *d returns the original element being pointed to. Conversely, (*d)++ just increments the value being pointed to.
Example:
// Case 1
int array[2] = {1, 2};
int *d = &array[0];
int x = *d++;
assert(x == 1 && d == &array[1]); // x gets the first element, d points to the second
// Case 2
int array[2] = {1, 2};
int *d = &array[0];
int x = (*d)++;
assert(x == 1 && d == &array[0] && array[0] == 2);
// array[0] gets incremented, d still points there, but x receives old value
In the official C terminology, these expressions do give you the same results, as they should. In the proper terminology, the "result" of a non-void expression is what that expression evaluates to. Both of your expressions evaluate to the initial value of *d, so not surprisingly, the results are the same.
However, an addition to a "result" every expression in C has zero or more so called "side effects". And side effects of these two expressions are completely different. The first expression increments the value of pointer 'd'. The second expression increments the value of '*d' (the pointed value).
The first increments the pointer, the second increments the value pointed to.
As an experiment, try this:
int main() {
int x = 20;
int *d = &x;
printf("d = %p\n", d);
int z = (*d)++;
printf("z = %d\n", z);
printf("d = %p\n", d);
int y = *d++;
printf("y = %d\n", y);
printf("d = %p\n", d);
}
They do return the same result, but the state change in your program is completely different.
This is easiest to understand if we just expand out the operations.
x = *d++;
// same as
x = *d;
d += 1; // remember that pointers increment by the size of the thing they point to
x = (*d)++;
// same as
x = *d;
*d += 1; // unless *d is also a pointer, this will likely really just add 1
I don't have a compiler handy.
a = (*d)++;
b = (*d);
is a==b? i don't think it is.