Right to left associativity with pointers [duplicate] - arrays

This question already has answers here:
Pointer expressions: *ptr++, *++ptr and ++*ptr
(11 answers)
Closed 2 years ago.
I'm currently learning about pointers in C, but I'm a little confused about how right to left associativity works with regards to incrementing a pointer versus incrementing the value being pointed at.
It is understood that ++ and * are both right to left associative in C.
I don't see how *s++ moves the array ahead 1, yet (*s)++ increments the value being pointed at but doesn't move the array ahead.
For example:
#include <stdio.h>
int main(){
char c[20] = "Help";
char *s;
s = c;
printf("init: %s\n",s); // Help
++*s;
printf("++*s: %s\n",s); // "Ielp" ascii increment of first element
++(*s);
printf("++(*s): %s\n",s); // "Jelp" ascii increment of first element
*s++;
printf("*s++: %s\n",s); // "elp" moves to next element in array
(*s)++;
printf("(*s)++: %s\n",s); // "flp" ascii increment of current element
*(++s);
printf("*(++s)\n: %s\n",s); // "lp" moves to next element
*++s;
printf("*++s\n: %s\n",s); // "p" moves to next element
return 0;
}
For the code above, can someone help explain what is going on AND why?
Thanks for taking a look.

As helped by dxiv and John Bode,
When parsing an expression, an operator which is listed on some row will be bound tighter (as if by parentheses) to its arguments than any operator that is listed on a row further below it. For example, the expression *p++ is parsed as *(p++), and not as (*p)++.
In the above expression the point worth noted is ++ is a postfix operator whose precedence(or priority) is greater than *(unary operator)
Operators that are in the same cell (there may be several rows of operators listed in a cell) are evaluated with the same precedence, in the given direction. For example, the expression a=b=c is parsed as a=(b=c), and not as (a=b)=c because of right-to-left associativity.
other example where associativity comes into picture is *++p
here * and ++(prefix operator) are having same precedence, so they will be evaluated as right to left.

Related

Trouble understanding increment operators with arrays in C

I'm having trouble wrapping my head around a concept in C regarding the use of the operator ++ and arrays. I know enough that ++ will increment a value, but I'm running into a code snippet that does not make any sense to me:
while((c = getchar()) != EOF)
{
if(c < NUM_CHARS)
{
thisval = ++freqarr[c];
if(thisval > maxval)
{
maxval = thisval;
}
}
the line thisval = ++freqarr[c]; does not make a lot of sense to me.
Does it mean that thisval adds an additional index or value to the array?
I'm still new to C, so I'm not sure if this is common in C or not, if it's not or looked down upon, please let me know.
Prefix ++ has lower precendence than [], see https://en.cppreference.com/w/c/language/operator_precedence. So this is equivalent to thisval = ++(freqarr[c]);. It takes the cth element of the array, and increments that element, then assigns the new value to thisval. Just like:
freqarray[c] = freqarray[c] + 1;
thisval = freqarray[c];
I presume that c is defined as an int and freqarr is defined as an array. (It's generally best to include a Minimal, Reproducible Example in your question).
The prefix ++ operator increments an object and yields the incremented value. freqarr[c] is an object. The fact that it happens to be an element of an array is not relevant here. It works the same way as it would if it were applied to a simple named variable.
Note that the indexing operator [] binds more tightly than ++, so the expression ++freqarr[c] is equivalent to ++(freqarr[c]).
The prefix ++ operator increments its operand, and the resulting expression has the incremented value.
So this line does two things:
It increments the value of freqarr[c] which is a member of an array
It assigned the incremented value of freqarr[c] to thisval

What does a while statement that only sets 2 pointers equal, do?

we are currently learning how Pointers work in C.
I have this very short code of a copymethod of Strings in C, that was given to us from a tutor. I tried to explain its function in my own words but I am unsure if I have understood it correctly and would appreciate if somebody could correct my mistakes and answer my questions about it.
void copy ( char ∗ source , char ∗ dest) {
while (∗dest++ = ∗source++);
}
"Copy is a function with 2 Paramaters source and dest, which are both pointers of type char. The function calls a while statement which sets the dereferenced dest, incremented by 1 * sizeof(char), equal to the dereferenced and incremented (by 1*sizeof(char)) source."
What exactly does the while statement do? From my understanding *dest means that I am getting the char which dest points to, is that correct? But why would a while statement only set 2 pointers equal to each other, I don't really get it.
I appreciate any help, thank you!
This is the terse way to write an implementation of strcpy.
It is equivalent to the longer, but easier to follow
while (*dest = *source) {
dest++;
source++;
}
*dest = *source copies one char from the source to the destination. The result is zero if a zero byte was copied, at which time the loop ends.
Adding the increment to the condition is possible because the pointer dereferenced is the pointer value before the increment.
First, you need to start evaluating the expressions from the inner to the outer side. An important thing is to take into consideration that the body of the loop is empty (the ; at the right parenthesis indicates that the loop is executing the null statement --do nothing--, so everything must happen in the test expression).
The expression in the while test is not a test for equity, but an assignment. The equals operator is written doubling the =, as in ==, while = is used to assign the value of the right subexpression to the variable on the left side.
The variable on the left side is *dest++. A bit complicated expression that includes a dereference operator * and an autoincrement operator ++. The ++ takes higher preference, so it is acted first: the pointer is incremented, and the value returned by this subexpression is the value of the pointer before it was incremented. This means that the value of the pointer being used is the one it had before the expression dest++ was evaluated, and the * operator states the char variable pointed to by dest. So the place where the value will be stored in the assignment is the value pointed to by dest, and the pointer will be incremented before the end of the whole expression ends --but after the value is used--. The right side of the assignment show what is going to be assigned. As the expression is the same, I will pass quickly over it. The value assigned is the one pointed to by the source variable. It is incremented once the value is taken, and the value stored in the place of dest is filled with the character of the variable pointed by src. After that, both pointers are incremented, so the next time the test expression is evaluated, the characters involved will be the next source assigned to the next destination character. So, in this point, when the loop will be finished? Well, the value of an assignment expression is precisely the value assigned to the destination target, so in this case is the character copied from source to destination. And the test will fail, when the character copied happens to be zero (or false in C terms). As you see, there's nothing left to be put in the body of the loop.
This sample is famous for being an example of how cryptic C can get to. It appears in the two editions of "The C programming language" of Kernighan & Ritchie, the inventors of the language, and is accompanied by a comment that says something more or less like this: This is a bit obscure but every programmer that is proud of being proficient at C coding must be capable of interpreting this with a bit of care. (indeed the loop variables in the source are one letter s and d, i think)

precedence of ++ (post,prefix) nd dereference operator

Shouldn't the output of the following code be f
I get an output e
#include<stdio.h>
void main(){
char arr[]="Geeks";
char *ptr = arr;
++*ptr++;
printf("%c\n",*ptr);
}
No, it shouldn't. Your code increments the first character and then moves the pointer one forward. The pointer will point to the first e, and depending on your locale/character encoding, the first letter is most probably H. The expression is parsed according to precedence and associativity rules as:
++(*(p++))
Yes expression is parsed as ++*((ptr++)), first ptr++ is calculated but because it is postfix increment the new calculated value doesn't update the old value of ptr until the statement ends (;) . Next ++**( ptr++ ) is calculated on old value of ptr that result , G change to H. Now all work is done, the statement ends and ptr value is updated, that points to next element that is e.

Comma operator in condition of loop in C

#include <stdio.h>
main()
{
int i;
for(i=0; i<0, 5; i++)
printf("%d\n", i);
}
I am unable to understand the i<0, 5 part in the condition of the for loop.
Even if I make it i>0, 5, there's no change in output.
How does this work?
On topic
The comma operator will always yield the last value in the comma separated list.
Basically it's a binary operator that evaluates the left hand value but discards it, then evaluates the right hand value and returns it.
If you chain multiple of these they will eventually yield the last value in the chain.
As per anatolyg's comment, this is useful if you want to evaluate the left hand value before the right hand value (if the left hand evaluation has a desirable side effect).
For example i < (x++, x/2) would be a sane way to use that operator because you're affecting the right hand value with the repercussions of the left hand value evaluation.
http://en.wikipedia.org/wiki/Comma_operator
Sidenote: did you ever hear of this curious operator?
int x = 100;
while(x --> 0) {
// do stuff with x
}
It's just another way of writing x-- > 0.
Comma operator evaluates i<0 Or i>0 and ignores. Hence, it's always the 5 that's present in the condition.
So it's equivalent to:
for(i=0;5;i++)
The coma operator is done to the initialization and to the increment part, to do something like for(i=0,j=20;i<j;i++,j--), if you do it in the comparation part it will evaluate the last one (as it was already answered before)
i<0,5 will always evaluate to 5, as always the right expression will be returned for ex1,ex2 .
The comma operator is intended for cases where the first operand has some side effects. It's just an idiom, meant to make your code more readable. It has no effect on the evaluation of the conditional.
For example,
for (i = 0; i<(i++, 5); i++) {
// something
}
will increment i, and then check if i<5.

Copying a string in C

I am confused about this code: (http://www.joelonsoftware.com/articles/CollegeAdvice.html)
while (*s++ = *t++);
What is the order of execution? Is *s = *t first done, and then are they each incremented? Or other way around?
Thanks.
EDIT: And what if it was:
while(*(s++) = *(t++));
and
while(++*s = ++*t);
while (*s++ = *t++);
From the precedence table you can clearly see ++ is having higher precedence than *. But ++ is used here as post increment operator, so the incrementation happens after the assignment expression. So *s = *t happens first, then s and t are incremented.
EDIT:
while(*(s++) = *(t++));
Is same as above. You are making it more explicit with the use of parenthesis. But remember ++ is still a post increment.
while(++*s = ++*t);
There is just one operator next to s. So * is applied first and on that result ++ is applied which results in the lvalue required error.
while(*++s = *++t);
Again just operator next to s,t. So the incrementation happens first followed by copy. So we are effectively skipping the copy of the first char from t to s.
You are right. *s = *t is done first, and then they are incremented.
The increment is a post-increment. Post not just because it comes after the variable being incremented, but also because it comes after the expression is evaluated. So the order of execution is
*s = *t
then s++ and t++
EDIT::
#chrisgoyal
Order of execution is an ambiguous term. There are two different things here. The syntactical order, and the semantics of the expression.
Syntactically, the operator ++ is applied first. If the *s is applied first, then the following is equivalent to what #Hogan said:
(*s)++ = (*t)++
Which is very different from Joel's sample.
The semantics of the operator ++ is that it is executed after the expression.
Hope that clarifies what I meat.
Actually, s++ and t++ are applied first. Don't forget that the post-fix operator is executed after the expression is done. Basically the operator ++ is applied for both, then *s = *t is executed.
In Post increment operation variable is used first and then after its gets modified.
So there are two forms of increment
++s // increment before using value
s++ // increment after using value
And the result of these can be dereferenced:
*++s // or...
*s++
This worked out really well on one of the very first machines for C to run on, the PDP-11, which had a register-indirect addressing mode that increment the register after. The following ops were available in hardware:
*--s // or
*s++
You could do either
*x++ = *y++; // or
*--x = *--y; // or some combination
And if you did, the whole line happened in a single instruction. Since // comments were introduced by C99, however, you couldn't actually get away with my comment syntax.
The code: (while *s++ = *t++); is roughly equivalent to:
while (*s = *t) {
++s;
++t;
}
The second is exactly the same -- the extra parens don't change anything (in this case). For the parens to do anything, they'd have to be like: while ((*s)++ = (*t)++);. This would do roughly the same as your third example (covered in the paragraph below).
The last example: while(++*s = ++*t); is completely different. Since the dereference (*) is closer to the operand, this dereferences the operand, and increments the result of the dereference, which means it increments what the pointer points AT, instead of incrementing the pointer itself. As a result, this would copy the first character, then increment that character, then check whether that character was non-zero and continue the same until it was zero. The result would be both the source and the destination becoming empty strings (since the first character of both would now be a zero, which is used to terminate strings).

Resources