Assigning a variable using a unary operator

In summary, the code above assigns the values 1, 2, 3, 4, 5 to a[0], a[1], a[2], a[3], and a[4] respectively.
  • #1
167
7
Homework Statement
I am using unary operator inside while loop to assign values, but it isn't doing doing anything
Relevant Equations
None
C:
int a[]={12,34,55,76,89,23};
int n=5;
while(n>1){
   a[n]=a[--n];}
for(int i=0;i<6;i++){
   printf("%d\t",a[i]);
}
Mentor note: Please use code tags in future posts. I've added them to this code.
The above code should shift the element values to the right of each array cell, but after running the code it doesn't seem to be doing anything.
Screenshot (147).png
Screenshot (147).png
 
Last edited by a moderator:
Physics news on Phys.org
  • #2
You need to decrement n after using it on the right-hand side of the assignment, not before.
Try replacing a[--n] by a[n--]
 
  • Informative
Likes berkeman
  • #3
In line 15, when it assigns the value to the left side a[n] has the value of n already been decremented? If so, then it is the same as the right side a[n].
(I am not expert enough to know the answer, but I suspect this might be the problem.)
 
  • #4
andrewkirk said:
You need to decrement n after using it on the right-hand side of the assignment, not before.
Try replacing a[--n] by a[n--]
That wouldn't change anything right. The original values would be assigned back.
 
  • #5
FactChecker said:
In line 15, when it assigns the value to the left side a[n] has the value of n already been decremented? If so, then it is the same as the right side a[n].
(I am not expert enough to know the answer, but I suspect this might be the problem.)
Nope I'm doing pre-increment using --n. What you r saying is post increment, that would be n--.
 
  • #6
Crystal037 said:
Nope I'm doing pre-increment using --n. What you r saying is post increment, that would be n--.
I'm not convinced about that. If it is 'pre', then it has already been decreased on both sides of the equality before anything is done. If that is even done before the lvalue left-hand side is determined, then it is just putting the same value in the same spot.
Try assigning nOld = n before line 15 and changing line 15 to "a[nOld]=a[--n];". See if that makes a difference.
(PS. Those pre-increments and post-increments can be treacherous and some programming standards forbid their use. I would not use them unless there was a serious reason.)
(PPS. If you want to, you can examine the resulting assembler code of line 15 to see exactly what is happening and when.)
 
  • #7
It is stated here that
1) If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
2) If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.
The following examples are given:
Code:
// For (1):
i = ++i + i++;

// For (2):
a[i] = i++;
f(i, i++);
These examples between them suggest that
Code:
a[i] = a[--i];
also produces undefined behaviour.

The fact that there is scope for debate about what that line of code does is reason enough to rewrite it; perhaps as
Code:
for(n = 5; n > 1; n--) 
   a[n] = a[n-1];
 
  • Like
Likes Grelbr42, hmmm27 and FactChecker
  • #8
pasmith said:
It is stated here that

The following examples are given:
Code:
// For (1):
i = ++i + i++;

// For (2):
a[i] = i++;
f(i, i++);
These examples between them suggest that
Code:
a[i] = a[--i];
also produces undefined behaviour.
I think that another example in the reference makes an even better case. If something like this is undefined:
C:
i = i++ + 1; // undefined behavior
Then surely something like this is also undefined:
C:
a[n]=a[--n];
This being undefined may mean that it will give different results with different compilers -- a very bad thing.
pasmith said:
The fact that there is scope for debate about what that line of code does is reason enough to rewrite it; perhaps as
Code:
for(n = 5; n > 1; n--)
   a[n] = a[n-1];
Amen. The headaches of pre-increment and post-increment are just not worth it except for the very simplest cases where it is virtually the only thing being done.
 
  • #9
Crystal037 said:
The above code should shift the element values to the right of each array cell
Your statement above is not clear in that it seems to imply that you are shifting the array values to the right. From your code, it appears that your goal is actually to shift each array value one position to the left.

As already noted in this thread, using increment or decrement operators can lead to undefined behavior in some cases, especially in assignment statements where the same variable appears on both sides of the assignment operator,

The following code moves each element one position to the left, with the old a[0] going into the bit bucket. Since each element has moved left by one position, when you print them out, the loop should run one less time.
C:
    int a[] = { 12, 34, 55, 76, 89, 23 };
    int size = sizeof(a) / sizeof(int);   
    int temp;
   
    for (int i = 0; i < size; i++) {
        temp = a[i+1];
        a[i] = temp;
    }
 
  • #10
@Crystal037, I've noticed in several of your threads that, after some advice, you don't return. It would be nice, as well as good manners, if you acknowledged that advice, to say whether it helped or didn't.

Nobody gets paid here, so saying "thanks" goes a long way.
 
  • #11
Mark44 said:
@Crystal037, I've noticed in several of your threads that, after some advice, you don't return. It would be nice, as well as good manners, if you acknowledged that advice, to say whether it helped or didn't.

Nobody gets paid here, so saying "thanks" goes a long way.
Oh I'm so sorry! Thank you all for answering my query. Now, I got to know about undefined behaviour of the code.
 
  • Like
Likes FactChecker and Mark44
  • #12
Late to the game, but per the standard post (in/de)crement operators return the altered value. Pre (in/de)crement operators may return the original value, but I don't think they have to return anything (thus undefined behavior in the standard). The optimizer can elect to use the pre increment operator when the altered value is not used.
 
  • #13
valenumr said:
Late to the game, but per the standard post (in/de)crement operators return the altered value.
No you have this the wrong way round: prefix operators return (a reference to) the altered value, postifx operators return (a reference to a copy of) the value before alteration.

https://en.cppreference.com/w/cpp/language/operator_incdec

valenumr said:
Pre (in/de)crement operators may return the original value, but I don't think they have to return anything
No, see above.

valenumr said:
The optimizer can elect to use the pre increment operator when the altered value is not used.
The key point to remember is that with the right settings the optimizer is clever enough to produce exactly the same code for
C++:
accumulator += x[i];
i++; // Or ++i.
as
C++:
accumulator += x[i++];
so there is no point in doing the latter, follow the simple rule to never use the return value of an increment/decrement operator.

Some style guides go as far as to say don't use the increment/decrement operators at all - instead use
C++:
accumulator += x[i];
i += 1;
(and of course with the right optimizer settings for production code this will again compile to exactly the same object code).
 
  • Like
Likes DrClaude, valenumr and Grelbr42
  • #14
pbuk said:
No you have this the wrong way round: prefix operators return (a reference to) the altered value, postifx operators return (a reference to a copy of) the value before alteration.

https://en.cppreference.com/w/cpp/language/operator_incdecNo, see above.The key point to remember is that with the right settings the optimizer is clever enough to produce exactly the same code for
C++:
accumulator += x[i];
i++; // Or ++i.
as
C++:
accumulator += x[i++];
so there is no point in doing the latter, follow the simple rule to never use the return value of an increment/decrement operator.

Some style guides go as far as to say don't use the increment/decrement operators at all - instead use
C++:
accumulator += x[i];
i += 1;
(and of course with the right optimizer settings for production code this will again compile to exactly the same object code).
You are correct.
 
  • #15
There are other problems that I don't think have been mentioned with using the postfix operator this way: a = 2 + x[i++];
1) Suppose you want to modify the code so that there is something between the assignment to a and the index increment. This code makes it harder to make that change without unnecessarily changing this line.
2) It is also harder to spot that the index has been incremented on this line and is easy to overlook.
3) It makes the documentation of that line messy.
4) Some coding standards forbid side effects. I consider the index increment to be a side effect.
 
  • Like
Likes valenumr
  • #16
FactChecker said:
2) It is also harder to spot that the index has been incremented on this line and is easy to overlook.
I agree that it is easy to overlook, but experienced C/C++ programmers will know that in the example you showed, the index doesn't get incremented until the next line; i.e., after the sequence point signified by the terminating semicolon (;) has been passed. A sequence point is a place in a program at which it is guaranteed that all side effects of previous operations have been performed. See https://en.wikipedia.org/wiki/Sequence_point.

In this example code, a = 2 + x[i++];, if the value of i is 2, array element x[2] is evaluated and then added to 2. This sum is then assigned to a. In the next line i's new value will be 3.

FactChecker said:
4) Some coding standards forbid side effects. I consider the index increment to be a side effect.
The increment and decrement operators cause side effects but aren't themselves side effects. The side effect in this case is that the index variable gets changed.
 
  • #17
Mark44 said:
I agree that it is easy to overlook, but experienced C/C++ programmers will know that in the example you showed, the index doesn't get incremented until the next line; i.e., after the sequence point signified by the terminating semicolon (;) has been passed. A sequence point is a place in a program at which it is guaranteed that all side effects of previous operations have been performed. See https://en.wikipedia.org/wiki/Sequence_point.
Yes, good point. I wrestled with whether to use a simple example or a complicated example. Of course, this and other examples are so simple that I have used such simple code many times. I have made hundreds of lines in a row that increment the index, especially when packing or unpacking a structure. Those are easy to understand and have very little likelihood of causing a problem.
So I would recommend anyone reading my post to imagine a more complicated example, where the likelihood of a problem can be much more significant.
Mark44 said:
In this example code, a = 2 + x[i++];, if the value of i is 2, array element x[2] is evaluated and then added to 2. This sum is then assigned to a. In the next line i's new value will be 3.
Yes. I understand and I hope that others do too.
Mark44 said:
The increment and decrement operators cause side effects but aren't themselves side effects. The side effect in this case is that the index variable gets changed.
Yes, it is code that causes a side effect. I fail to see a significant problem with how I used the phrase and I think that the wording can be forgiven.
 
  • #18
FactChecker said:
Yes, it is code that causes a side effect. I fail to see a significant problem with how I used the phrase and I think that the wording can be forgiven.
I was just trying to be more precise in the wording.
 
  • Like
Likes FactChecker

Suggested for: Assigning a variable using a unary operator

Replies
1
Views
1K
Replies
2
Views
1K
Replies
2
Views
777
Replies
2
Views
874
Replies
13
Views
2K
Replies
7
Views
2K
Replies
1
Views
742
Back
Top