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


887

在C语言中,使用++i和之间有什么区别i++,在for循环的增量块中应该使用哪个?


10
不确定原始发布者是否感兴趣,但是在C ++中,性能差异可能很大,因为对于用户定义的类型而言,创建临时对象可能会很昂贵。
弗洛伊德

Answers:


1098
  • ++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中使用的

无论如何,请遵循“优先++ii++” 准则,您不会出错。

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

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

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


6
这种效果会不会在达到最终条件时再次运行循环?例如, for(int i=0; i<10; i++){ print i; } 这与for(int i=0; i<10; ++i){ print i; } 我的理解没什么不同,有些语言会根据您使用的语言为您提供不同的结果。
aVeRTRAC'8

27
jonnyflash,两者将以相同的方式运行,因为i的增量和打印内容位于不同的语句中。对于任何支持C样式++的语言,都是这种情况。++ i和i ++之间的唯一区别是在同一条语句中使用运算的值。
马克·哈里森

16
因为在大多数情况下它们会产生相同的代码,所以我更喜欢,i++因为它的形式为“ operand-operator”,即赋值为“ operand-operator-value”。换句话说,目标操作数在表达式的左侧,就像在赋值语句中一样。
David R Tribble

2
@MarkHarrison,它将相同地运行,不是因为i++print i在不同的语句中,而是因为i++;i<10。@jonnyflash的话不是那么离谱。假设您有for(int i=0; i++<10){ print i; }for(int i=0; ++i<10){ print i; }。它们的操作方式与@johnnyflash在第一条评论中描述的方式不同。
亚当

3
@sam,因为在典型的for循环中,++ i部分没有副作用(例如,赋值)。
马克·哈里森

175

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

i++

i++是post增量,因为它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 = 2不过i = 2。的值iji 递增后分配给i。同样,++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


1
在前缀和后缀之后初始化变量有助于理解。谢谢。
阿卜杜勒·阿林·沙基尔

42

请不要担心其中一个更快的“效率”(速度)。这些天,我们有负责这些事情的编译器。使用任何一种有意义的方法,在此基础上可以更清楚地表明您的意图。


1
我希望这意味着“ 使用前缀(inc | dec)语句,除非您实际上需要在(inc | dec)之前的旧值,很少有人这样做,但是假定的教材使用的比例令人困惑,创建一个甚至不知道它是什么的后缀用户的货物崇拜 '..!
underscore_d

我不确定“如今的编译器……照顾这些事情”是否普遍存在。在自定义operator++(int)(后缀版本)中,代码几乎必须创建一个临时文件,然后将其返回。您确定编译器总是可以优化它吗?
彼得-恢复莫妮卡

35

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

i++ 返回值,然后将其递增。

这是一个微妙的区别。

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


23
我不知道任何编译器至少对整数有影响。
blabla999

4
并不快。忽略这些值(仅副作用有效),并且编译器可以/将生成完全相同的代码。
wildplasser

31

i++:在这种情况下,首先分配值,然后进行递增。

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

下面是图像的可视化效果,这也是一个演示相同内容的实用视频

在此处输入图片说明


如何增加未分配的数量?
kouty

@kouty您可以增加未分配给变量的寄存器。
Polluks

20

究其原因++i 可以是略快于i++是,i++可以要求i的值的本地副本,它得到递增之前,而++i从来不会。在某些情况下,某些编译器会在可能的情况下对其进行优化……但是,并非总是如此,并非所有编译器都这样做。

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


11
-1为C ++回答C问题。i编写语句时,值的“本地副本”不多于值1的“本地副本” 1;
R .. GitHub停止帮助ICE,2010年

14

在循环中使用其中一个的有效结果是相同的。换句话说,循环将在两种情况下执行相同的操作。

在效率方面,选择i ++而不是++ i可能会涉及罚款。根据语言规范,使用后递增运算符应创建该运算符所作用的值的额外副本。这可能是额外操作的来源。

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

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

  2. 就操作时间复杂度而言,这两种方法(即使实际上正在执行复制)是等效的。在循环内部执行的指令数应主要控制增量操作中的操作数。因此,在任何大小很大的循环中,执行循环体都会大大增加增量方法的代价。换句话说,您最好不用担心在循环中优化代码,而不必担心增量。

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

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


13

它们都增加数字。++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

8

++i(前缀操作):增量,然后将值
(例如): int i = 5int b = ++i 在这种情况下,6被分配给b的第一和然后递增到7等。

i++(后缀操作):分配,然后递增值
(例如): int i = 5int b = i++ 在这种情况下,5分配给b的第一和然后递增到6等等。

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


7

++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

5

我假设您现在已经理解了语义上的区别(尽管说实话,我想知道为什么人们在堆栈溢出时问“运算符X的含义是什么”问题,而不是阅读书籍或网络教程之类的东西。

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

说出您在代码中的意思。

如果您在语句中不需要先增值,请不要使用该形式的运算符。这是一个小问题,但是除非您使用的样式指南完全禁止一个版本支持另一个版本(又称骨头样式指南),否则您应该使用最能表达您想要做什么的形式。

QED,使用预递增版本:

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

5

可以通过下面的简单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;


5

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循环中,我看不出它的用法有什么不同。


5

以下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

4

预递增意味着在同一行上递增。后增量是指行执行后的增量。

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 OR condition if first line is already true then compiler doesn't check the rest. It is 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 address of x
    std::cout<<"address = "<<p<<"\n"; //prints (address of x) + sizeof(int)
    std::cout<<"address = "<<&x<<"\n"; //prints address of x

    std::cout<<"address = "<<++&x<<"\n"; //error. reference can't re-assign because it is fixed (immutable)
}

4

不久:

++ii++如果你不是在一个函数写他们的工作原理相同。如果您使用类似function(i++)或的产品function(++i),则可以看到区别。

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

function(i++)表示将第一个i放入函数中,然后再递增i1。

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

2
区别并不是真正地与函数调用相关(并且您可以在不进行函数调用的情况下发现差异)。有之间的差异int j = ++i;以及int k = i++;即使有不涉及函数调用。
Jonathan Leffler

3

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

此代码及其输出说明了不同之处:

#include<stdio.h>

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

输出为:

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

因此,基本上++i在增加值之后返回值,而++i在增加值之前返回值。最后,在两种情况下,iwill的值都会增加。

另一个例子:

#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的顺序相关联++

换句话说:

  • ++ 分配之前i必须先进行递增;
  • ++ after i表示必须分配进行递增:


-3

a = i ++表示一个包含当前i值a = ++ i表示一个包含递增i值


10
这个答案不正确。 a = i++;表示存储在其中的值a将是i递增之前的值,但是“不递增”表示i未递增,这是完全错误的— i递增,但是表达式的值是递增之前的值。
Jonathan Leffler

-6

这是了解差异的示例

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

输出:(10 12/11 11取决于printf函数自变量的求值顺序,在编译器和体系结构中会有所不同)

说明: i++-> i打印,然后递增。(打印10,但i将变为11) ++i-> ivalue递增并打印该值。(打印12,值i也12)


11
导致不确定的行为,因为i++和之间没有序列点++i
MM 2014年

@Lundin是正确的,尽管LHS和RHS之间有序列点,但是2个表达式彼此之间仍未排序
Antti Haapala
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.