Dúvida sobre operadores de Pós/Pré-Incremento/Decremento

Pessoal, ontem fazendo o simulado Whizlabs me deparei uma questão que envolvia pós/pré-incremento/decremento.
Bati o olho e me parecia muito simples, pois sabendo que o operador pós-incremento/decremento altera o valor após o uso e que o operador de pré-incremento/decremento altera o valor antes de seu uso. Entretanto, errei esta questão pois nela havia o uso da mesma variável duas vezes em uma expressão e o resultado neste caso foi completamente diferente do que eu esperava, e ainda não consegui entender.
Fiz alguns testes, e gostaria que se alguém souber o motivo e a lógica aplicada nestas situações me explique por favor.

Segue o código de exemplo:

public class PosPreIncremento {
    
  public static void main(String [] args){
	int a;
	int b;
	
	//comportamento anormal/não trivial
	
	a = 0; b = 0;
	b = a++ + ++a; 
	System.out.println("Val i: " + b); //imprime b = 2 (a = 2) //não deveria ser (b = 1)?
	
	a = 0; b = 0;
	b = a++ + a++; 
	System.out.println("Val ii: " + b); //imprime b = 1 (a = 2) //não deveria ser (b = 0)?
	
	a = 0; b = 0; 
	b = ++a + a++; 
	System.out.println("Val iii: " + b); //imprime b = 2 (a = 2) //não deveria ser (b = 1)?
	
	a = 0; b = 0;
	b = ++a + ++a; 
	System.out.println("Val iv: " + b); //imprime b = 3 (a = 2) //ok, (b = 3)
	
	//comportamento normal/trivial
	
	a= 0; b = 0;
	b= ++a + b; 
	System.out.println("Val v: " + b); //imprime b = 1  (a = 1)
	
	a = 0; b = 0;
	b = a++ + b; 
	System.out.println("Val vi: " + b); //imprime b = 0 (a = 1)
	
	a = 0; b = 0;
	b = b + ++a; 
	System.out.println("Val vii: " + b); //imprime b = 1 (a = 1)
	
	a = 0; b = 0;
	b = b + a++; 
	System.out.println("Val viii: " + b); //imprime b = 0 (a = 1)
  }
}

talvez ajude a entender
http://www.guj.com.br/posts/list/2853.java#13818

[quote=billcaio]talvez ajude a entender
http://www.guj.com.br/posts/list/2853.java#13818[/quote]

Nossa, dei uma passada rápida… parece uma questão bem polêmica.
Obrigado.

Vamos supor que você tenha o seguinte:

a = 0;
a = a++;

Enquanto você nao usar o “a” novamente ele continuará valendo 0. Assim, quando temos uma situação do tipo
b = a++ + a; você pode tentar fazer assim, leia da esquerda para a direita para ficar mais facil. Começando com a++. Por enquanto o “a” vale 0 já que ele ainda não apareceu de novo. Continue lendo. Aparece um outro “a”. Este “a” vai ser igual a 1, pois recebeu +1 do pos incremento anterior. Depois que você sabe todos os valores da expressão temos: b = 0 + 1, portanto b = 1.

Quando você tem expressoes do tipo

a = 0;
b = 0;

b = ++a + a;

Leia da esquerda para a direita também, procurando o valor dos fatores da expressão. Primeiro fator: ++a, portanto aí o “a” é igual a 1 pois temos um pré-incremento. O segundo fator é um outro “a” que vale 1 pelo pré-incremento da primeira expressão. Portanto temos b = 1 + 1 = 2.

Vendo caso por caso fica assim:

Primeiro caso

a = 0; b = 0; b = a++ + ++a;//a++: "a" vale 0 por enquanto. Temos b = 0 + ++a. //++a: O "a" aparece de novo. Portanto recebe o pós-incremento do primeiro fator, ficando a = 1 e mais o pré-incremento, ficando a = 2. A expressão final fica b = 0 + 2 = 2 a = 2, b = 2.

Segundo caso:

a = 0; b = 0; b = a++ + a++; //Esquerda para a direita: a++, a = 0, por enquanto temos b = 0 + a++. //Aparece outro a++, portanto ele recebe +1 do primeiro pós-incremento, sendo entao a = 1. Como aqui nesta segunda expressão ele recebe outro pós-incremento, este valor só seria acrescentado se o "a" aparecesse novamente. A expressão final fica b = 0 + 1, portanto b = 1.

Terceiro caso:

a = 0; b = 0; b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2 //Resposta: b = 2.

Quarto caso

a = 0; b = 0; b = ++a + ++a;//Lendo da esqueda para a direita: ++a, portanto a = 1. Depois vem outro ++a. Assim a = 2. Portanto a expressão fica : b = 1 + 2. //Resposta b = 3.

Os outros casos acho que são mais fáceis de enxergar.

Eu penei pra chegar na resposta também, mas depois que passei a ver da forma como te mostrei acima, consegui a resposta bem mais fácil. Espero ter ajudado

Abraços

explicação muito boa, valeu

douglas_vidotto, cara vc mandou benzaço na sua resposta.
Agora eu entendi perfeitamente, era isto mesmo que eu queria, encontrar alguma lógica nesse código que não me parecia racional.
Vou dar uma praticada, mas tenho certeza que não vou mais me atrapalhar.

Muito obrigado mesmo!!!

E esse caso, alguém pode explicar?

public class Incremento {
public static void main(String[] args){
int j = 0;
for (int i = 0; i < 100; i++) {
j = j++;
System.out.println(j);
}
System.out.println(j);
}
}

A cada iteração o j seria referenciado novamente, então deveria haver o incremento, não?

Alguem ai tem uma explicação sobre a questao á cima?

Eu uso a mesma lógica do que acontecia em C. Se não me engano, compilador troca ++i por i=i+1, e i++ por i=i, i=i+1. Aí é só utilizar essa lógica que fica explicado o print(j) dentro do laço. Por isso meu professor até brincava que era boa prática colocar sempre pré-incremento.
[]s

Como isso é uma atribuição, vai ser efectuada a parte direita do igual (j++), então o que é feito é guardar o valor de j para usar na expressão (0), e incrementado j (1). Como essa parte fica tratada, vai ser atribuído a j o valor da expressão (lembra-te que tinha sido guardado o 0 para usar na expressão, daí j ficar com 0. E isto se repete em todo o ciclo, incrementa mas depois sobrepõe o valor com 0.

Desde que se saiba como funciona o que estás a usar, tanto podes utilizar pré como pós-incremento.

Pessoal desculpe entrar de intrometido aqui , mais é que essa questão me gerou uma duvida

Douglas não intendi o 3 caso

[code]a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2.
a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2.

[/code]

pensa comigo b= ++a + a++ ‘a’ recebe preincremento de ‘a’ que vale 1 + o posincremente de ‘a’ que no momento vale 0 pois não incremento nada ainda, ele só ira incremente quando usar o ‘a’ novamente , nesse caso nos não estamos usando o ‘a’ novamente. Então era para fica b = 1 + 0 resposta 1

alguem tem alguma outra logica para isso?

O teu erro está aqui. Neste caso estás a usar o a novamente. Está na mesma linha mas é uma utilização diferente.

++a --> fica 1 em a e usa 1 na expressão
a++ --> usa 1 na expressão (que tinha sido incrementado na anterior) e fica 2 em a.

[quote]O teu erro está aqui. Neste caso estás a usar o a novamente. Está na mesma linha mas é uma utilização diferente.

++a --> fica 1 em a e usa 1 na expressão
a++ --> usa 1 na expressão (que tinha sido incrementado na anterior) e fica 2 em a.
[/quote]

mais aqui a++ nos estamos apenas acionando o pós incrmento, estamos usando apenas para acionar o pos incremento, ai na proxima vez que nós fomos usar que teria que incrementar não é? pois usando o raciocionio de que ele faz o pos encremeto e so incrementa quando fomos usar novamente, não intendo essa logica

Se o problema está em b = ++a + a++; porque não partir a expressão em partes mais pequenas, para melhor compreender?

 
    c = ++a; // A primeira parte da expressão, ficando c=1 e a=1 (logo apos o ++a, a passa a ser 1)

    d = a++;  // A primeira parte da expressão, ficando d=1 (nesta altura, a já é 1 pela instrução anterior) 

    b = c + d: //A atribuição final, 1+1 = 2

[quote=erickfm8]Pessoal desculpe entrar de intrometido aqui , mais é que essa questão me gerou uma duvida

Douglas não intendi o 3 caso

[code]a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2.
a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2.

[/code]

pensa comigo b= ++a + a++ ‘a’ recebe preincremento de ‘a’ que vale 1 + o posincremente de ‘a’ que no momento vale 0 pois não incremento nada ainda, ele só ira incremente quando usar o ‘a’ novamente , nesse caso nos não estamos usando o ‘a’ novamente. Então era para fica b = 1 + 0 resposta 1

alguem tem alguma outra logica para isso?[/quote]

Já coloquei outra lógica no meu post anterior.

na 3: b= (a=a+1) + (a=a), a=a+1;

[quote=erickfm8]Pessoal desculpe entrar de intrometido aqui , mais é que essa questão me gerou uma duvida

Douglas não intendi o 3 caso

[code]a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2.
a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2.

[/code]

pensa comigo b= ++a + a++ ‘a’ recebe preincremento de ‘a’ que vale 1 + o posincremente de ‘a’ que no momento vale 0 pois não incremento nada ainda, ele só ira incremente quando usar o ‘a’ novamente , nesse caso nos não estamos usando o ‘a’ novamente. Então era para fica b = 1 + 0 resposta 1

alguem tem alguma outra logica para isso?[/quote]

b = 0; b = ++a + a++;

++a é pré-incremento, então a vale 1, não precisa “esperar” outro a aparecer.

a++ aqui o valor de a vale 1, só que o pós-incremento não ocorre na expressão.

Por isso o valor é b = 1 + 1 = 2;

Quem altera é ++a.
O ++a só usa o valor de a.

Espero ter ajudado.

rmalati

Obrigado rmalati conseguir intender alias intender não conseguir perceber, eu estava viajando, bom

obrigado

essa parte faz confusão mesmo. rrsrsrs

Abraço.

Boa Tarde Pessoal! :oops:

Desculpa ai o incomodo…mas fiquei com a tal da pulga atrás da orelha.

view plaincopy to clipboardprint?
a = 0;
b = 0;
b = ++a + ++a;//Lendo da esqueda para a direita: ++a, portanto a = 1. Depois vem outro ++a. Assim a = 2. Portanto a expressão fica : b = 1 + 2.
//Resposta b = 3. -[color=red] PQ DEU 3?[/color]

view plaincopy to clipboardprint?
a = 0;
b = 0;
b = ++a + a++;//Da esquerda para a direita: ++a, portanto a = 1. Depois vem a++ que não é incrementado até aparecer outro a. Portanto temos b = 1 + 1 = 2
//Resposta: b = 2. -[color=green]PQ DEU 2 SE NÃO TEM OUTRO + DEPOIS DO a++?[/color]

view plaincopy to clipboardprint?
a = 0;
b = 0;
b = a++ + a++; //Esquerda para a direita: a++, a = 0, por enquanto temos b = 0 + a++.
//Aparece outro a++, portanto ele recebe +1 do primeiro pós-incremento, sendo entao a = 1. Como aqui nesta segunda expressão ele recebe outro pós-incremento, este valor só seria acrescentado se o “a” aparecesse novamente. A expressão final fica b = 0 + 1, portanto b = 1. -[color=red] PQ FICOU 0+1 ?O a++ fica 0 depois que é incrementado?[/color]

VALEU PESSOAL! :lol:

++a // nesse primeiro ++a, a EXPRESSÃO utiliza o valor 1, e "a" passa a valer 1
++a // nesse segundo ++a, a EXPRESSÃO utiliza  o valor 2 pra somar (visto que era 1, agora já vale 2)
// logo o valor da soma é 1 + 2 = 3
++a // No primeiro ++a, o valor a ser somado na instrução é 1, e o valor de "a" passa a ser 1
a++ // Agora o valor a ser somado é 1, pois é o valor de a antes de ser incrementado. "a" passa a valer 2 DEPOIS da soma
// logo, a soma é feita de 1 + 1 = 2

lembre-se de uma coisa:
quando você tem

a = 0;
while (a++ <= 0) {}

na EXPRESSÃO que o “a” está submetido, ele vale 0. DEPOIS da expressão avaliada ele valerá 1. Então vai entrar no loop!

Logo, no caso abaixo e retomando sua pergunta

a = 0;  
b = 0;  
b = a++ + a++;

a primeira expressão a++ vale 0. Depois de sair dela, e for avaliar o próximo a++ o “a” até vale 1, porém naquele momento a EXPRESSÃO avaliou a++ como 0.
Se ainda ficar dúvida, vai enviando.

Abraços