Programing

'for'루프 내에서 사후 증가 및 사전 증가는 동일한 출력을 생성합니다

lottogame 2020. 5. 17. 10:27
반응형

'for'루프 내에서 사후 증가 및 사전 증가는 동일한 출력을 생성합니다


이 질문에는 이미 답변이 있습니다.

다음 for 루프는 포스트 증가와 다른 사전 증가를 사용하더라도 동일한 결과를 생성합니다.

코드는 다음과 같습니다.

for(i=0; i<5; i++) {
    printf("%d", i);
}

for(i=0; i<5; ++i) {
    printf("%d", i);
}

두 'for'루프에 대해 동일한 출력을 얻습니다. 뭔가 빠졌습니까?


평가 한 후 i++또는 ++i, 새로운 값은 i두 경우 모두 동일합니다. 증감 전과 후의 차이는 식 자체를 평가 한 결과입니다.

++ii의 새로운 값으로 증가 하고 평가합니다 i.

i++의 이전 값으로 평가 i하고 증가 i합니다.

이것이 for 루프에서 중요하지 않은 이유는 제어 흐름이 대략 다음과 같이 작동하기 때문입니다.

  1. 상태를 테스트
  2. 거짓 인 경우 종료
  3. 사실이라면 본문을 실행하십시오.
  4. 증분 단계를 실행

(1)과 (4)가 분리되어 있기 때문에 사전 또는 사후 증분을 사용할 수 있습니다.


글쎄, 이것은 간단하다. 위의 for루프는 의미 적으로

int i = 0;
while(i < 5) {
    printf("%d", i);
    i++;
}

int i = 0;
while(i < 5) {
    printf("%d", i);
    ++i;
}

이 코드 블록의 관점 에서 행 i++;++i;동일한 의미를 갖습니다. 그것들은 i(하나씩 증가) 값에 동일한 영향을 미치므로 이러한 루프의 동작에 동일한 영향을 미칩니다.

루프를 다음과 같이 다시 작성하면 차이가있을 수 있습니다.

int i = 0;
int j = i;
while(j < 5) {
    printf("%d", i);
    j = ++i;
}

int i = 0;
int j = i;
while(j < 5) {
    printf("%d", i);
    j = i++;
}

This is because in first block of code j sees the value of i after the increment (i is incremented first, or pre-incremented, hence the name) and in the second block of code j sees the value of i before the increment.


The result of your code will be the same. The reason is that the two incrementation operations can be seen as two distinct function calls. Both functions cause an incrementation of the variable, and only their return values are different. In this case, the return value is just thrown away, which means that there's no distinguishable difference in the output.

However, under the hood there's a difference: The post-incrementation i++ needs to create a temporary variable to store the original value of i, then performs the incrementation and returns the temporary variable. The pre-incrementation ++i doesn't create a temporary variable. Sure, any decent optimization setting should be able to optimize this away when the object is something simple like an int, but remember that the ++-operators are overloaded in more complicated classes like iterators. Since the two overloaded methods might have different operations (one might want to output "Hey, I'm pre-incremented!" to stdout for example) the compiler can't tell whether the methods are equivalent when the return value isn't used (basically because such a compiler would solve the unsolvable halting problem), it needs to use the more expensive post-incrementation version if you write myiterator++.

Three reasons why you should pre-increment:

  1. You won't have to think about whether the variable/object might have an overloaded post-incrementation method (for example in a template function) and treat it differently (or forget to treat it differently).
  2. Consistent code looks better.
  3. When someone asks you "Why do you pre-increment?" you'll get the chance to teach them about the halting problem and theoretical limits of compiler optimization. :)

This is one of my favorite interview questions. I'll explain the answer first, and then tell you why I like the question.

Solution:

The answer is that both snippets print the numbers from 0 to 4, inclusive. This is because a for() loop is generally equivalent to a while() loop:

for (INITIALIZER; CONDITION; OPERATION) {
    do_stuff();
}

Can be written:

INITIALIZER;
while(CONDITION) {
    do_stuff();
    OPERATION;
}

You can see that the OPERATION is always done at the bottom of the loop. In this form, it should be clear that i++ and ++i will have the same effect: they'll both increment i and ignore the result. The new value of i is not tested until the next iteration begins, at the top of the loop.


Edit: Thanks to Jason for pointing out that this for() to while() equivalence does not hold if the loop contains control statements (such as continue) that would prevent OPERATION from being executed in a while() loop. OPERATION is always executed just before the next iteration of a for() loop.


Why it's a Good Interview Question

First of all, it takes only a minute or two if a candidate tells the the correct answer immediately, so we can move right on to the next question.

But surprisingly (to me), many candidates tell me the loop with the post-increment will print the numbers from 0 to 4, and the pre-increment loop will print 0 to 5, or 1 to 5. They usually explain the difference between pre- and post-incrementing correctly, but they misunderstand the mechanics of the for() loop.

In that case, I ask them to rewrite the loop using while(), and this really gives me a good idea of their thought processes. And that's why I ask the question in the first place: I want to know how they approach a problem, and how they proceed when I cast doubt on the way their world works.

At this point, most candidates realize their error and find the correct answer. But I had one who insisted his original answer was right, then changed the way he translated the for() to the while(). It made for a fascinating interview, but we didn't make an offer!

Hope that helps!


Because in either case the increment is done after the body of the loop and thus doesn't affect any of the calculations of the loop. If the compiler is stupid, it might be slightly less efficient to use post-increment (because normally it needs to keep a copy of the pre value for later use), but I would expect any differences to be optimized away in this case.

It might be handy to think of how the for loop is implemented, essentially translated into a set of assignments, tests, and branch instructions. In pseudo-code the pre-increment would look like:

      set i = 0
test: if i >= 5 goto done
      call printf,"%d",i
      set i = i + 1
      goto test
done: nop

Post-increment would have at least another step, but it would be trivial to optimize away

      set i = 0
test: if i >= 5 goto done
      call printf,"%d",i
      set j = i   // store value of i for later increment
      set i = j + 1  // oops, we're incrementing right-away
      goto test
done: nop

If you wrote it like this then it would matter :

for(i=0; i<5; i=j++) {
    printf("%d",i);
}

Would iterate once more than if written like this :

for(i=0; i<5; i=++j) {
    printf("%d",i);
}

You could read Google answer for it here: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preincrement_and_Predecrement

So, main point is, what no difference for simple object, but for iterators and other template objects you should use preincrement.

EDITED:

There are no difference because you use simple type, so no side effects, and post- or preincrements executed after loop body, so no impact on value in loop body.

You could check it with such a loop:

for (int i = 0; i < 5; cout << "we still not incremented here: " << i << endl, i++)
{
    cout << "inside loop body: " << i << endl;
}

Both i++ and ++i is executed after printf("%d", i) is executed at each time, so there's no difference.


Yes, you'll get exactly same outputs for both. why do you think they should give you different outputs?

Post-increment or pre-increment matters in situations like this:

int j = ++i;
int k = i++;
f(i++);
g(++i);

where you provide some value, either by assigning or by passing an argument. You do neither in your for loops. It gets incremented only. Post- and pre- don't make sense there!


The third statement in the for construct is only executed, but its evaluated value is discarded and not taken care of.
When the evaluated value is discarded, pre and post increment are equal.
They only differ if their value is taken.


There is a difference if:

int main()
{
  for(int i(0); i<2; printf("i = post increment in loop %d\n", i++))
  {
    cout << "inside post incement = " << i << endl;
  }


  for(int i(0); i<2; printf("i = pre increment in loop %d\n",++i))
  {
    cout << "inside pre incement = " << i << endl;
  }

  return 0;
}

The result:

inside post incement = 0

i = post increment in loop 0

inside post incement = 1

i = post increment in loop 1

The second for loop:

inside pre incement = 0

i = pre increment in loop 1

inside pre incement = 1

i = pre increment in loop 2


Compilers translate

for (a; b; c)
{
    ...
}

to

a;
while(b)
{
    ...
 end:
    c;
}

So in your case (post/pre- increment) it doesn't matter.

EDIT: continues are simply replaced by goto end;

참고URL : https://stackoverflow.com/questions/4706199/post-increment-and-pre-increment-within-a-for-loop-produce-same-output

반응형