Publi

Preincremento y postincremento (x++ != ++x)

Hace unos días un alumno de clases particulares me preguntó la diferencia entre estos dos; me pareció una pregunta interesante ya que los únicos usos que había visto eran como única sentencia:

a++;
++a;

En este uso no hay diferencia, puesto que hagamos las cosas en el orden que las hagamos el resultado será igual; aunque en este ejemplo tampoco se tiene clara la idea del orden de las operaciones. Pero veamos otro ejemplo:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(int argc, char *argv[])
{
  int a=10;
  int b;

  b=a++;
  printf("a=%d\nb=%d\n", a, b);
}

Vemos que estamos realizando un postincremento de a, o lo que es lo mismo, incrementamos la variable a después de las demás operaciones (asignar a b el valor de a).

Por lo tanto, si a vale 10, b tomará el valor 10 y tras eso a incrementará 1 pasando a valer 11.
Al ver la salida podemos observar:

$ ./prepost
a=11
b=10

En cambio podemos crear este programa también (igual que el anterior cambiando a++ por ++a),

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(int argc, char *argv[])
{
  int a=10;
  int b;

  b=++a;
  printf("a=%d\nb=%d\n", a, b);
}

Cuya salida es:

$ ./prepost2
a=11
b=11

En este caso, preincrementamos a. Antes de cualquier operación incrementamos la variable. Por tanto, si a vale 10, incrementamos esa variable pasando a valer 11 y luego asignamos ese valor a b.

La gran ventaja de esto es que con la experiencia suficiente nos ayuda a reducir el código que escribimos y optimizar la velocidad de nuestros programas. Además, a la hora de crear nuestros programas podremos ahorrar mucho código, sobre todo a la hora de lidiar con punteros de cadenas o imágenes donde, en ocasiones, podemos realizar tareas de forma más fácil.

Dejo algunos ejemplos más, aunque sencillos del uso de estos operadores:

Mareando un poco la perdiz

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(int argc, char *argv[])
{
  int a=10;
  int b=5;

  b=a++ + ++b;
  printf("a=%d\nb=%d\n", a, b);
}

Que da como salida:

$ ./prepost3
a=11
b=16

En este caso… cogemos a (que vale 10), luego incrementamos b (que valía 5 y pasa a valer 6), sumamos los dos valores (que da en total 16) y luego incrementamos a (que pasa a valer 11).

En un do-while

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(int argc, char *argv[])
{
  int a;

  a=0;
  do
    printf("Bucle a=%d\n", a);
  while (++a<5);
}

Cuya salida es:

$ ./preposw
Bucle a=0
Bucle a=1
Bucle a=2
Bucle a=3
Bucle a=4

En este caso, al finalizar cada iteración, incrementamos a y luego miramos si es menor que 5; por lo que, en la última vuelta del bucle, si a vale 4, incrementaremos su valor (pasando a ser 5) y luego veremos que ya no es menor que 5 por lo que saldremos del bucle.

En contraposición podemos hacer:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(int argc, char *argv[])
{
  int a;

  a=0;
  do
    printf("Bucle a=%d\n", a);
  while (a++<5);
}

Cuya salida es:

$ ./preposw
Bucle a=0
Bucle a=1
Bucle a=2
Bucle a=3
Bucle a=4
Bucle a=5

En este caso, al verificar que a 5 antes de incrementar a. Cuando a vale 4, haremos la comparación, cuando todavía es menor que 5 e incrementaremos. Daremos otra vuelta más con a valiendo 5, donde, en la siguiente comparación (a ahora sí que saldrá del bucle, aunque si verificáramos el valor de a tras salir del bucle sería 6.

Contar caracteres a mano

Un ejemplo tonto más, para contar las letras de una cadena:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main(int argc, char *argv[])
{
  int i=0;
  char *str="HOLA";

  // Con esto vale
  while (str[++i]!='\0');

  printf("Longitud: %d\n", i);
  }

Salida:

$ ./prepos
Longitud: 4

En este caso, dentro del while, primero incrementamos i, luego comparamos str[i] con ‘\0’ y si efectivamente tiene ese valor saldremos del bucle. No se crea un bucle infinito porque el incremento se produce (aunque sea en la misma sentencia de la comparación).
Hay que tener cuidado con este ejemplo, ya que si la cadena está vacía (es decir, que el primer carácter que encontremos sea \0) tal vez este método produzca resultados inesperados, ya que nunca llegamos a comparar el carácter 0 (incrementamos antes de comparar ese carácter). Una posible solución es inicializar i a -1.

Nota: Todo lo comentado aquí vale tanto con preincremento/postincremento como con predecremento/postdecremento (–a, a–), ya que son operaciones muy similares.

También podría interesarte....

There are 6 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Santiago Valdarrama /
    Usando Google Chrome Google Chrome 8.0.552.237 en Windows Windows 7

    Como bien dices, ambos operadores funcionan de forma diferente, y efectivamente pueden ser utilizados para reducir la cantidad de código que escribes, pero esto muchas veces hace más daño de lo que ayuda.

    Menos código la gran mayoría de las veces redunda en una menor legibilidad. Usando operadores como estos, el código puede complicarse extremadamente haciéndolo bastante difícil de traducir incluso para ti mismo que eres el desarrollador.

    Yo no recomendaría el uso de los operadores ++ y — en sentencias donde se realicen asignaciones u otras operaciones. Por ejemplo:

    if (++a == 5)

    es completamente diferente a:

    if (a++ == 5)

    lo cual resulta bastante complicado de entender, y puede introducir errores innecesarios. El codigo deberia ser:

    a++;
    if (a == 5)

    o

    if (a == 5)
    // do whatever you want to do
    a++;

    Por ejemplo, aqui:

    http://blog.svpino.com/2011/01/java-tricky-java-identificadores.html

    Podras ver algo bien interesante con Java, pero que de la misma forma complica sobremanera la legibilidad del codigo.

    Gracias por tu articulo.

  3. admin / Post Author
    Usando Mozilla Firefox Mozilla Firefox 3.6 en Linux Linux

    @Santiago Valdarrama
    Gracias por el comentario Santiago. Es verdad que a veces lo podemos tomar como ofuscación y otras personas optarán por no usarlo, es más siempre podemos usarlo en una sentencia sin obtener valor; pero es importante conocer la potencia y las posibilidades de la programación.

  4. Pingback: BlogESfera.com /

  5. Pendejito Ramirez de los Rosarios /
    Usando Mozilla Firefox Mozilla Firefox 32.0 en Ubuntu Linux Ubuntu Linux

    Muchas grasias señorito, me acaba de salvar usted la vida con esto, ya que ahorita mismito tengo un examen que es bien huevon, wey, muchas grasias pueees.

  6. Pingback: Operador coma. Cómo incorporarlo a nuestro día a día con muchos ejemplos en C – Poesía Binaria /

Leave a Reply