C: Qual é a diferença entre ++ ie i ++?

888

Em C, qual é a diferença entre using ++ie i++, e qual deve ser usada no bloco de incremento de um forloop?

The.Anti.9
fonte
10
Não sei se o pôster original está interessado, mas em C ++ a diferença no desempenho pode ser substancial, pois a criação do objeto temporário pode ser cara para um tipo definido pelo usuário.
Em Freund

Respostas:

1101
  • ++iaumentará o valor de ie retornará o valor incrementado.

     i = 1;
     j = ++i;
     (i is 2, j is 2)
  • i++aumentará o valor de i, mas retornará o valor original que era imantido antes de ser incrementado.

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

Para um forloop, qualquer um funciona. ++iparece mais comum, talvez porque é isso que é usado em K&R .

De qualquer forma, siga a diretriz "prefira ++isobre i++" e você não errará.

Há alguns comentários sobre a eficiência de ++ie i++. Em qualquer compilador de projeto que não seja aluno, não haverá diferença de desempenho. Você pode verificar isso observando o código gerado, que será idêntico.

A questão da eficiência é interessante ... aqui está minha tentativa de resposta: Existe uma diferença de desempenho entre i ++ e ++ i em C?

Como o @OnFreund observa, é diferente para um objeto C ++, pois operator++()é uma função e o compilador não pode saber como otimizar a criação de um objeto temporário para armazenar o valor intermediário.

Mark Harrison
fonte
6
Esse efeito não resistirá ao loop mais uma vez ao atingir a condição final? Por exemplo, for(int i=0; i<10; i++){ print i; } isso não será diferente do que for(int i=0; i<10; ++i){ print i; } Meu entendimento é que alguns idiomas fornecerão resultados diferentes dependendo de qual você usar.
aVeRTRAC 16/08
27
jonnyflash, ambos funcionarão de forma idêntica, pois o incremento de ie a impressão estão em instruções diferentes. Esse deve ser o caso de qualquer idioma que suporte o estilo C ++. A única diferença entre ++ ie i ++ será ao usar o valor da operação na mesma instrução.
Mark Harrison
16
Como na maioria dos casos eles produzem código idêntico, prefiro i++porque é da forma "operando-operador", como uma atribuição "operando-operador-valor". Em outras palavras, o operando de destino está no lado esquerdo da expressão, assim como em uma declaração de atribuição.
precisa
2
@ MarkHarrison, operará de forma idêntica não porque i++e print iesteja em declarações diferentes, mas porque i++;e i<10está. A observação de @ jonnyflash não é tão estranha assim. Suponha que você tenha for(int i=0; i++<10){ print i; }e for(int i=0; ++i<10){ print i; }. Eles funcionarão de maneira diferente da maneira que @johnnyflash descreveu no primeiro comentário.
Adam
3
@ sam, porque em um loop for típico não há efeito colateral (por exemplo, atribuição) na parte ++ i.
Mark-Harrison #
175

O i ++ é conhecido como pós-incremento, enquanto o ++ i é chamado de pré-incremento.

i++

i++é pós-incremento porque incrementa io valor de 1 após o término da operação.

Vamos ver o seguinte exemplo:

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

Aqui valor de j = 1mas i = 2. Aqui o valor de iserá atribuído jprimeiro e depois iserá incrementado.

++i

++ié pré-incremento porque incrementa io valor de 1 antes da operação. Isso significa que j = i;será executado depois i++.

Vamos ver o seguinte exemplo:

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

Aqui valor de j = 2mas i = 2. Aqui o valor de iserá atribuído japós o i incremento de i. Da mesma forma ++iserá executado antes j=i;.

Para sua pergunta, o que deve ser usado no bloco de incremento de um loop for? a resposta é, você pode usar qualquer um .. não importa. Ele executará seu loop for mesmo não. vezes

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

E

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

Ambos os loops produzirão a mesma saída. ie 0 1 2 3 4.

Só importa onde você está usando.

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

Nesse caso, a saída será 1 2 3 4 5.

Parag
fonte
1
A inicialização de variáveis ​​após o prefixo e a pós-correção ajuda a entender. Obrigado.
Abdul Alim Shakir
42

Por favor, não se preocupe com a "eficiência" (velocidade, na verdade) da qual é mais rápida. Atualmente, temos compiladores que cuidam dessas coisas. Use o que fizer sentido, com base no que mostra mais claramente sua intenção.

Andy Lester
fonte
1
o que, eu espero, significa ' usar prefixo (inc | dec), a menos que você realmente precise do valor antigo anterior ao (inc | dec), que poucas pessoas precisam, e que uma proporção desconcertante de supostos materiais de ensino usa, criando um culto de carga de usuários de postfix que nem sabem o que é '..!
underscore_d
Não tenho certeza de que "compiladores hoje em dia ... cuidem dessas coisas" é universalmente verdadeiro. Dentro de um costume operator++(int)(a versão do postfix), o código praticamente precisa criar um temporário que será retornado. Você tem certeza de que os compiladores sempre podem otimizar isso?
Peter - Restabelece Monica
36

++i incrementa o valor e o retorna.

i++ retorna o valor e o incrementa.

É uma diferença sutil.

Para um loop for, use ++i, pois é um pouco mais rápido. i++criará uma cópia extra que será jogada fora.

Ryan Fox
fonte
23
Não conheço nenhum compilador em que ele faça diferença pelo menos para números inteiros.
blabla999 12/01/09
4
Não é mais rápido . Os valores são ignorados (apenas o efeito colateral é efetivo) e o compilador pode / irá gerar exatamente o mesmo código.
wildplasser 01/10/19
31

i++: Neste cenário, primeiro o valor é atribuído e, em seguida, o incremento acontece.

++i: Neste cenário, primeiro o incremento é feito e, em seguida, o valor é atribuído

Abaixo está a visualização da imagem e também aqui está um bom vídeo prático que demonstra o mesmo.

insira a descrição da imagem aqui

Shivprasad Koirala
fonte
Como você pode incrementar um pouco não atribuído?
kouty 19/01
@kouty Você pode incrementar um registro não atribuído a uma variável.
Polluks
20

O motivo ++i pode ser um pouco mais rápido do i++que o i++necessário, pois pode exigir uma cópia local do valor de i antes que ele seja incrementado, embora ++inunca seja necessário. Em alguns casos, alguns compiladores o otimizarão se possível ... mas nem sempre é possível, e nem todos os compiladores fazem isso.

Tento não confiar muito nas otimizações dos compiladores, por isso segui o conselho de Ryan Fox: quando posso usar os dois, uso ++i.

OysterD
fonte
11
-1 para a resposta C ++ à pergunta C. Não há mais "cópia local" do valor do ique o valor 1 quando você escreve uma instrução 1;.
R .. GitHub Pare de ajudar o gelo
14

O resultado efetivo do uso de um loop é idêntico. Em outras palavras, o loop fará a mesma coisa exata nos dois casos.

Em termos de eficiência, pode haver uma penalidade na escolha do i ++ sobre o ++ i. Em termos de especificação de idioma, o uso do operador pós-incremento deve criar uma cópia extra do valor em que o operador está agindo. Isso pode ser uma fonte de operações extras.

No entanto, você deve considerar dois problemas principais com a lógica anterior.

  1. Compiladores modernos são ótimos. Todos os bons compiladores são inteligentes o suficiente para perceber que estão vendo um incremento inteiro em um loop for e otimizarão os dois métodos para o mesmo código eficiente. Se o uso de pós-incremento sobre pré-incremento realmente faz com que seu programa tenha um tempo de execução mais lento, você está usando um compilador terrível .

  2. Em termos de complexidade operacional do tempo, os dois métodos (mesmo que uma cópia esteja realmente sendo executada) são equivalentes. O número de instruções executadas dentro do loop deve dominar significativamente o número de operações na operação de incremento. Portanto, em qualquer loop de tamanho significativo, a penalidade do método de incremento será massivamente ofuscada pela execução do corpo do loop. Em outras palavras, é muito melhor se preocupar em otimizar o código no loop, em vez do incremento.

Na minha opinião, toda a questão simplesmente se resume a uma preferência de estilo. Se você acha que o pré-incremento é mais legível, use-o. Pessoalmente, prefiro o pós-incremento, mas é provavelmente porque foi o que me ensinaram antes de saber algo sobre otimização.

Este é um exemplo por excelência de otimização prematura, e problemas como esse têm o potencial de nos distrair de problemas sérios no design. Ainda é uma boa pergunta, no entanto, porque não há uniformidade no uso ou consenso nas "melhores práticas".

crepúsculo
fonte
13

Ambos incrementam o número. ++ié equivalente a i = i + 1.

i++e ++isão muito parecidos, mas não exatamente iguais. Ambos incrementam o número, mas ++iincrementam o número antes que a expressão atual seja avaliada, enquantoi++ incrementam o número após a expressão ser avaliada.

Exemplo:

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

++i(Operação Prefixo): Incrementos e, em seguida, atribui o valor
(por exemplo,): int i = 5, int b = ++i Neste caso, 6 é atribuído a B em primeiro lugar e, em seguida, a incrementos de 7 e assim por diante.

i++(Operação sufixo): Atribui e, em seguida, incrementa o valor
(por exemplo,): int i = 5,int b = i++ Neste caso, é atribuído a 5 B em primeiro lugar e, em seguida, a incrementos de 6 e assim por diante.

Caso do loop i++for : é usado principalmente porque, normalmente, usamos o valor inicial de iantes de incrementar o loop for. Mas, dependendo da lógica do seu programa, isso pode variar.

Anands23
fonte
7

++i: é pré-incremento, o outro é pós-incremento.

i++: obtém o elemento e depois o incrementa.
++i: incrementa ie retorna o elemento.

Exemplo:

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

Resultado:

i: 0
i++: 0
++i: 2
Scitech
fonte
5

Suponho que você entenda a diferença na semântica agora (embora, honestamente, eu me pergunte por que as pessoas perguntam 'o que o operador X significa' perguntas sobre o estouro de pilha, em vez de ler, você sabe, um livro ou tutorial da Web ou algo assim.

De qualquer maneira, quanto a qual usar, ignore as questões de desempenho, que são improváveis ​​importantes mesmo em C ++. Este é o princípio que você deve usar ao decidir qual usar:

Diga o que você quer dizer com código.

Se você não precisar do valor antes do incremento em sua declaração, não use esse formato do operador. É um problema menor, mas, a menos que você esteja trabalhando com um guia de estilo que proíbe uma versão totalmente a favor da outra (também conhecido como guia de estilo com cabeça de osso), use o formulário que expressa exatamente o que você está tentando fazer.

QED, use a versão pré-incremento:

for (int i = 0; i != X; ++i) ...
Scott Urban
fonte
5

A diferença pode ser entendida por este código C ++ simples abaixo:

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;
IOstream
fonte
5

A principal diferença é

  • Postagem do i ++ ( após incremento ) e
  • ++ i Pré ( Antes do Incremento )

    • postar se i =1 o loop aumentar como1,2,3,4,n
    • pré se i =1 o loop aumentar como2,3,4,5,n
Gopinath Kaliappan
fonte
5

i ++ e ++ i

Este pequeno código pode ajudar a visualizar a diferença de um ângulo diferente das respostas já postadas:

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);

O resultado é:

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

Preste atenção às situações antes e depois.

para laço

Quanto a qual deles deve ser usado em um bloco de incremento de um loop for, acho que o melhor que podemos fazer para tomar uma decisão é usar um bom exemplo:

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);

O resultado é:

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

Não sei você, mas não vejo diferença em seu uso, pelo menos em um loop for.

carloswm85
fonte
5

O seguinte fragmento de código C ilustra a diferença entre os operadores de pré e pós incremento e decremento:

int  i;
int  j;

Operadores de incremento:

i = 1;
j = ++i;    // i is now 2, j is also 2
j = i++;    // i is now 3, j is 2
Nihal Reddy
fonte
4

Pré-incremento significa incremento na mesma linha. Pós-incremento significa incremento após a execução da linha.

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

Quando se trata de operadores OR, AND, torna-se mais interessante.

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
}

Na matriz

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
}

Em C ++ pós / pré-incremento da variável ponteiro

#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)
}
Uddhav Gautam
fonte
4

Em breve:

++ie i++funciona da mesma maneira se você não estiver gravando em uma função. Se você usar algo como function(i++)oufunction(++i) pode ver a diferença.

function(++i)diz o primeiro incremento i em 1, depois disso, coloque isso ina função com novo valor.

function(i++)diz colocar primeiro ina função após esse incremento iem 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
GokhanAvci
fonte
2
A diferença não está realmente ligada às chamadas de função (e você pode identificar a diferença sem fazer chamadas de função). Há uma diferença entre int j = ++i;e int k = i++;mesmo quando não há chamada de função envolvida.
Jonathan Leffler
3

A única diferença é a ordem das operações entre o incremento da variável e o valor que o operador retorna.

Este código e sua saída explicam a diferença:

#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);
}

A saída é:

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

Então, basicamente, ++iretorna o valor após ser incrementado, enquanto ++iretorna o valor antes de ser incrementado. No final, em ambos os casos, o ivalor será incrementado.

Outro exemplo:

#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;
}

Resultado:

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

Muitas vezes não há diferença

As diferenças são claras quando o valor devolvido é atribuído a uma outra variável ou quando o incremento é realizada em concatenação com outras operações em que as operações de precedência é aplicada ( i++*2é diferente de ++i*2, mas (i++)*2e (++i)*2devolve o mesmo valor), em muitos casos, eles são intercambiáveis. Um exemplo clássico é a sintaxe do loop for:

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

tem o mesmo efeito de

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

Regra para lembrar

Para não confundir os dois operadores, adotei esta regra:

Associe a posição do operador ++em relação à variável ià ordem da ++operação em relação à atribuição

Disse em outras palavras:

  • ++ antes dos i meios, o incremento deve ser realizado antes da atribuição;
  • ++ após o i incremento dos meios deve ser realizado após a atribuição:
Francesco Boi
fonte
3

Você pode pensar na conversão interna disso como várias instruções ;

  • caso 1
i++;

você pode pensar assim,

i;
i = i+1;
  • caso 2
++i;

você pode pensar assim,

i = i+i;
i;
Jeet Parikh
fonte
-3

a = i ++ significa a contém valor atual de i a = ++ i significa a contém valor incrementado de i

munna
fonte
10
Esta resposta não é precisa. a = i++;significa que o valor armazenado aserá o valor iantes do incremento, mas 'sem incrementar' implica que inão é incrementado, o que está completamente errado - ié incrementado, mas o valor da expressão é o valor antes do incremento.
Jonathan Leffler
-6

Aqui está o exemplo para entender a diferença

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

saída: 10 12/11 11(dependendo da ordem de avaliação dos argumentos para oprintf função, que varia entre compiladores e arquiteturas)

Explicação: i++-> ié impresso e, em seguida, é incrementado. (Imprime 10, mas ipassa a 11) ++i-> o ivalor aumenta e imprime o valor. (Imprime 12 e o valor itambém 12)

srinath
fonte
11
Isso causa comportamento indefinido, pois não há ponto de sequência entre i++e++i
MM
@Lundin é que, embora correta, os LHS, RHS de vírgula tem ponto de seqüência entre eles, mas os 2 expressões ainda estão wrt unsequenced uns aos outros
Antti Haapala