繁体   English   中英

++i 和 i++ 有什么区别?

[英]What is the difference between ++i and i++?

在C中,使用++ii++有什么区别,应该在for循环的增量块中使用哪个?

  • ++i将增加i的值,然后返回增加的值。

     i = 1; j = ++i; (i is 2, j is 2)
  • i++将增加i的值,但返回i在增加之前持有的原始值。

     i = 1; j = i++; (i is 2, j is 1)

对于for循环,两者都可以。 ++i似乎更常见,也许是因为这是在K&R中使用的。

在任何情况下,遵循“首选++i而不是i++ ”的指导方针,你就不会出错。

关于++ii++的效率有一些评论。 在任何非学生项目编译器中,不会有性能差异。 您可以通过查看生成的代码来验证这一点,这将是相同的。

效率问题很有趣......这是我试图回答的问题: C 中 i++ 和 ++i 之间是否存在性能差异?

正如@OnFreund 所指出的,C++ 对象是不同的,因为operator++()是一个函数,编译器不知道优化临时对象的创建以保存中间值。

i++称为后增量,而++i称为前增量。

i++

i++是后增量,因为它在操作结束后将i的值增加 1。

让我们看看下面的例子:

int i = 1, j;
j = i++;

这里j = 1的值,但i = 2 这里i的值将首先分配给j ,然后i将递增。

++i

++i是预增量,因为它在操作之前将i的值增加 1。 这意味着j = i; 将在i++之后执行。

让我们看看下面的例子:

int i = 1, j;
j = ++i;

这里j = 2i = 2的值。 这里i的值将在ii递增后分配给j 同样, ++i会在j=i; .

对于您的问题,应该在 for 循环的增量块中使用哪个? 答案是,你可以使用任何一个……没关系。 它将执行相同次数的for循环。

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

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

两个循环都将产生相同的输出。 0 1 2 3 4

它只在你使用它的地方很重要。

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

在这种情况下,输出将为1 2 3 4 5

i++ :在这种情况下,首先分配值,然后发生增量。

++i :在这种情况下,首先完成增量,然后分配值

下面是图像可视化,也是一个很好的实用视频,演示了相同的内容。

在此处输入图像描述

++i增加值,然后返回它。

i++返回值,然后递增它。

这是一个微妙的区别。

对于 for 循环,请使用++i ,因为它稍微快一些。 i++将创建一个刚刚被丢弃的额外副本。

请不要担心哪个更快的“效率”(实际上是速度)。 这些天我们有编译器来处理这些事情。 使用任何一个有意义的,基于哪个更清楚地表明你的意图。

唯一的区别是变量的增量和运算符返回的值之间的运算顺序。

此代码及其输出解释了差异:

#include<stdio.h>

int main(int argc, char* argv[])
{
  unsigned int i=0, a;
  printf("i initial value: %d; ", i);
  a = i++;
  printf("value returned by i++: %d, i after: %d\n", a, i);
  i=0;
  printf("i initial value: %d; ", i);
  a = ++i;
  printf(" value returned by ++i: %d, i after: %d\n",a, i);
}

输出是:

i initial value: 0; value returned by i++: 0, i after: 1
i initial value: 0;  value returned by ++i: 1, i after: 1

所以基本上++i在递增后返回值,而i++在递增之前返回值。 最后,在这两种情况下, i的值都会增加。

另一个例子:

#include<stdio.h>

int main ()
  int i=0;
  int a = i++*2;
  printf("i=0, i++*2=%d\n", a);
  i=0;
  a = ++i * 2;
  printf("i=0, ++i*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  return 0;
}

输出:

i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2

很多时候没有区别

当返回的值被分配给另一个变量或当与应用操作优先级的其他操作串联执行递增时,差异很明显( i++*2++i*2不同,但(i++)*2(++i)*2返回相同的值) 在许多情况下它们是可以互换的。 一个经典的例子是 for 循环语法:

for(int i=0; i<10; i++)

具有相同的效果

for(int i=0; i<10; ++i)

效率

前增量总是至少与后增量一样有效:实际上后增量通常涉及保留先前值的副本,并且可能会添加一些额外的代码。

要记住的规则

为了不混淆这两个运算符,我采用了这个规则:

将运算符++相对于变量i的位置与++运算相对于赋值的顺序相关联

换句话说:

  • ++ before i表示必须在赋值之前进行递增;
  • ++i之后表示必须在赋值进行递增:

++i可能i++稍快的原因是i++可以在 i 的值递增之前需要其值的本地副本,而++i从不这样做。 在某些情况下,如果可能,一些编译器会对其进行优化……但这并不总是可能的,而且并非所有编译器都这样做。

我尽量不要过分依赖编译器优化,所以我会遵循 Ryan Fox 的建议:当我可以同时使用两者时,我会使用++i

在循环中使用任何一个的有效结果是相同的。 换句话说,循环在两种情况下都会做同样的事情。

就效率而言,选择 i++ 而不是 ++i 可能会受到影响。 就语言规范而言,使用后自增运算符应创建运算符所作用值的额外副本。 这可能是额外操作的来源。

但是,您应该考虑上述逻辑的两个主要问题。

  1. 现代编译器很棒。 所有优秀的编译器都足够聪明,可以意识到它在 for 循环中看到了一个整数增量,并且它将两种方法优化为相同的高效代码。 如果使用后增量而不是前增量实际上会导致您的程序运行时间变慢,那么您使用的是糟糕的编译器。

  2. 就操作时间复杂度而言,这两种方法(即使实际上正在执行复制)是等效的。 在循环内部执行的指令数量应显着支配增量操作中的操作数量。 因此,在任何显着大小的循环中,增量方法的惩罚将被循环体的执行所掩盖。 换句话说,你最好不要担心优化循环中的代码而不是增量。

在我看来,整个问题归结为一种风格偏好。 如果您认为预增量更具可读性,请使用它。 就个人而言,我更喜欢后增量,但这可能是因为这是我在对优化一无所知之前就被教过的。

这是过早优化的典型例子,像这样的问题有可能分散我们对设计中严重问题的注意力。 然而,这仍然是一个很好的问题,因为在“最佳实践”中没有统一的用法或共识。

他们都增加了数字。 ++i等价于i = i + 1

i++++i非常相似但不完全相同。 两者都增加数字,但++i在评估当前表达式之前增加数字,而i++在评估表达式之后增加数字。

例子:

int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3

++i (前缀操作):递增然后赋值
(例如): int i = 5 , int b = ++i在这种情况下,首先将 6 分配给 b,然后递增到 7,依此类推。

i++ (后缀操作):赋值然后递增值
(例如): int i = 5 , int b = i++在这种情况下,首先将 5 分配给 b,然后递增到 6,依此类推。

for 循环的情况: i++最常用,因为通常我们在 for 循环中递增之前使用i的起始值。 但根据您的程序逻辑,它可能会有所不同。

++i :是前增量,另一个是后增量。

i++ :获取元素然后递增它。
++i :增加 i 然后返回元素。

例子:

int i = 0;
printf("i: %d\n", i);
printf("i++: %d\n", i++);
printf("++i: %d\n", ++i);

输出:

i: 0
i++: 0
++i: 2

i++ 和 ++i

这个小代码可能有助于从与已经发布的答案不同的角度可视化差异:

int i = 10, j = 10;
  
printf ("i is %i \n", i);
printf ("i++ is %i \n", i++);
printf ("i is %i \n\n", i);
  
printf ("j is %i \n", j);
printf ("++j is %i \n", ++j);
printf ("j is %i \n", j);

结果是:

//Remember that the values are i = 10, and j = 10

i is 10 
i++ is 10     //Assigns (print out), then increments
i is 11 

j is 10 
++j is 11    //Increments, then assigns (print out)
j is 11 

注意之前和之后的情况。

for 循环

至于应该在 for 循环的增量块中使用哪一个,我认为我们能做的最好的决定就是使用一个很好的例子:

int i, j;

for (i = 0; i <= 3; i++)
    printf (" > iteration #%i", i);

printf ("\n");

for (j = 0; j <= 3; ++j)
    printf (" > iteration #%i", j);

结果是:

> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3 

我不了解你,但我看不出它的用法有什么不同,至少在 for 循环中是这样。

以下 C 代码片段说明了前后递增和递减运算符之间的区别:

int  i;
int  j;

增量运算符:

i = 1;
j = ++i;    // i is now 2, j is also 2
j = i++;    // i is now 3, j is 2

不久:

如果您不在函数中编写++ii++ ,它们的工作方式相同。 如果你使用类似function(i++)function(++i)的东西,你可以看到区别。

function(++i)表示首先将 i 增加 1,然后将此i放入具有新值的函数中。

function(i++)表示先将i放入函数中,然后将i增加 1。

int i=4;
printf("%d\n",pow(++i,2));//it prints 25 and i is 5 now
i=4;
printf("%d",pow(i++,2));//it prints 16 i is 5 now

主要区别是

  • i++ Post(增量后)和
  • ++i Pre(增量之前

    • post if i =1循环增量为1,2,3,4,n
    • pre if i =1循环增量为2,3,4,5,n

可以通过下面这个简单的 C++ 代码来理解不同之处:

int i, j, k, l;
i = 1; //initialize int i with 1
j = i+1; //add 1 with i and set that as the value of j. i is still 1
k = i++; //k gets the current value of i, after that i is incremented. So here i is 2, but k is 1
l = ++i; // i is incremented first and then returned. So the value of i is 3 and so does l.
cout << i << ' ' << j << ' ' << k << ' '<< l << endl;
return 0;

Pre-crement 表示在同一行上递增。 后增量是指在行执行后增量。

int j = 0;
System.out.println(j); // 0
System.out.println(j++); // 0. post-increment. It means after this line executes j increments.

int k = 0;
System.out.println(k); // 0
System.out.println(++k); // 1. pre increment. It means it increments first and then the line executes

当它带有 OR、AND 运算符时,它变得更加有趣。

int m = 0;
if((m == 0 || m++ == 0) && (m++ == 1)) { // False
    // In the OR condition, if the first line is already true
    // then the compiler doesn't check the rest. It is a
    // technique of compiler optimization
    System.out.println("post-increment " + m);
}

int n = 0;
if((n == 0 || n++ == 0) && (++n == 1)) { // True
    System.out.println("pre-increment " + n); // 1
}

在数组中

System.out.println("In Array");
int[] a = { 55, 11, 15, 20, 25 };
int ii, jj, kk = 1, mm;
ii = ++a[1]; // ii = 12. a[1] = a[1] + 1
System.out.println(a[1]); // 12

jj = a[1]++; // 12
System.out.println(a[1]); // a[1] = 13

mm = a[1]; // 13
System.out.printf("\n%d %d %d\n", ii, jj, mm); // 12, 12, 13

for (int val: a) {
     System.out.print(" " + val); // 55, 13, 15, 20, 25
}

在 C++ 中指针变量的后/前增量

#include <iostream>
using namespace std;

int main() {

    int x = 10;
    int* p = &x;

    std::cout << "address = " << p <<"\n"; // Prints the address of x
    std::cout << "address = " << p <<"\n"; // Prints (the address of x) + sizeof(int)
    std::cout << "address = " << &x <<"\n"; // Prints the address of x

    std::cout << "address = " << ++&x << "\n"; // Error. The reference can't reassign, because it is fixed (immutable).
}

我假设您现在了解语义上的差异(尽管老实说,我想知道为什么人们会问关于堆栈溢出的“运算符 X 是什么意思”的问题,而不是阅读书籍或网络教程之类的东西。

但无论如何,就使用哪一个而言,忽略性能问题,即使在 C++ 中也不太重要。 这是您在决定使用哪个时应遵循的原则:

说出你在代码中的意思。

如果您的语句中不需要 value-before-increment,请不要使用这种形式的运算符。 这是一个小问题,但除非您使用的样式指南禁止一个版本而完全支持另一个版本(又名愚蠢的样式指南),否则您应该使用最准确地表达您想要做的事情的形式。

QED,使用预增量版本:

for (int i = 0; i != X; ++i) ...

简而言之,两者之间的区别在于步骤看下图。

在此处输入图像描述

例子:

int i = 1;
int j = i++;

j结果为1

int i = 1;
int j = ++i;

j结果为2

注意:在这两种情况下i值都是2

您可以将其内部转换视为多个语句

// case 1

i++;

/* you can think as,
 * i;
 * i= i+1;
 */



// case 2

++i;

/* you can think as,
 * i = i+i;
 * i;
 */

前缀和后缀递增运算符

在C++中,“++”运算符是前后自增运算符。 后缀版本 (i++) 在变量递增之前返回变量的值,而前缀版本 (++i) 在变量返回值之前递增变量。

for循环的情况

在 for 循环的情况下,使用前缀版本还是后缀版本都没有关系。 因此,“for (int i = 0; i < 4; i++)”和“for (int i = 0; i < 4; ++i)”在功能上是等价的。

C++中的for循环分为三部分:初始化、条件、自增。 初始化通常用于初始化变量,通常是计数器变量,用于控制循环。 条件是一个 boolean 表达式,它在循环的每次迭代之前被评估。 如果条件为真,则执行循环体,否则退出循环。 增量用于更新控制循环的变量,通常是通过递增或递减它。

例如下面的for循环:

for (int i = 0; i < 4; i++) { // Postfix increment
   // code here
}

用值 0 初始化变量 i,在每次循环迭代之前评估条件 i < 4,并在每次循环迭代之后将 i 递增 1。

下面的for循环:

for (int i = 0; i < 4; ++i) { // Prefix increment
   // code here
}

与第一个循环相同,它用值 0 初始化变量 i,在每次循环迭代前评估条件 i < 4,并在每次循环迭代后将 i 递增 1。

for 循环的主要区别

关键区别在于 i 值的递增方式。 在第一个循环中使用了后缀运算符 (i++),这意味着 i 的值在第 3 部分的循环中使用后递增。 在第二个循环中使用前缀运算符 (++i),这意味着 i 的值在第三部分的循环中使用之前递增。 但是,在这两种情况下,i 的值都会增加 1,并且结果相同,因为两个循环都将运行 4 次迭代。

风格和可读性问题

这是风格和可读性的问题,但一般来说,当变量的值在递增之后使用时使用前缀运算符,当变量的值在递增之前使用时使用后缀运算符,但是 for for 循环,两者可以互换。

a=i++表示a包含当前i值。

a=++i表示a包含递增的i值。

这是理解差异的示例

int i=10;
printf("%d %d",i++,++i);

输出: 10 12/11 11 (取决于printf函数的参数评估顺序,因编译器和架构而异)

解释: i++ -> i被打印,然后递增。 (打印 10,但i将变为 11) ++i -> i值递增并打印该值。 (打印 12,并且i的值也是 12)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM