Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: SebaC en 23 Mayo 2016, 23:58 pm



Título: Salida inesperada de este programa
Publicado por: SebaC en 23 Mayo 2016, 23:58 pm
Tengo este sencillo programa

Código
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. int i = 0;
  6. int arr[20];
  7.  
  8.    while(i < 20)
  9. {
  10. arr[i++] = i;
  11. printf("%d\n", arr[i]);
  12. }
  13.  
  14.    return 0;
  15. }

En el cual inicializo un array de enteros pero cuando imprimo el contenido me da números extraños que no corresponden a la variable i
Que pasa aquí?


Título: Re: Salida inesperada de este programa
Publicado por: AlbertoBSD en 24 Mayo 2016, 00:07 am
Código
  1. arr[i++] = i;
Estas asignado e incrementando i
y despues imprimes el i no inicializado.

Tienes que incrementar en el printf o despues


Título: Re: Salida inesperada de este programa
Publicado por: SebaC en 24 Mayo 2016, 01:42 am
y despues imprimes el i no inicializado.

Yo inicialice i a cero no entiendo porque dices eso


Título: Re: Salida inesperada de este programa
Publicado por: AlbertoBSD en 24 Mayo 2016, 01:52 am
el i++ lo tienes dentro de los corchetes

i vale 0
asignas 0 a arr[0]
incrementas i y ahora vale 1
imprimes arr[1]
asignas 1 a arr[1]
incrementas i y ahora vale 2
....


Tu codigo tendria que estar asi
Código
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. int i = 0;
  6. int arr[20];
  7.  
  8.    while(i < 20)
  9. {
  10. arr[i] = i;
  11. printf("%d\n", arr[i]);
  12.                i++;
  13. }
  14.  
  15.    return 0;
  16. }

o bien

Código
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. int i = 0;
  6. int arr[20];
  7.  
  8.    while(i < 20)
  9. {
  10. arr[i] = i;
  11. printf("%d\n", arr[i++]);
  12. }
  13.  
  14.    return 0;
  15. }

¿Vez la diferencia?


Título: Re: Salida inesperada de este programa
Publicado por: geeke en 24 Mayo 2016, 02:10 am
Código
  1. arr[i++] = i;

La variable i se está modificando en el lado derecho de la asignación y tambien se hace referencia a ella en la izquierda el estándar de C no permite esto porqué no hay punto de secuencia para mas info http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points (http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points)


Título: Re: Salida inesperada de este programa
Publicado por: AlbertoBSD en 24 Mayo 2016, 02:54 am
Yo estoy con que la asignacion es totalemente valida.

Con el codigo que el presento solo es necesario modificatr el printf esta es otra version valida.

Código
  1. #include <stdio.h>
  2.  
  3. int main(void) {
  4. int i = 0;
  5. int arr[20];
  6. while(i < 20) {
  7. arr[i++] = i;
  8. printf("%d\n", arr[i-1]);
  9. }
  10. return 0;
  11. }


Salida:

Código:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


Se le podria agregar

Código
  1. printf("i actualmente vale %i",i);

Para ver cuando vale i al momento de imprimir el contenido del arreglo. O antes de la asignacion  del valor. O ambos aun mejor XD

Código
  1. #include <stdio.h>
  2.  
  3. int main(void) {
  4. int i = 0;
  5. int arr[20];
  6. while(i < 20) {
  7. printf("i actualmente vale %i\n",i);
  8. arr[i++] = i;
  9. printf("Asignacion del arreglo\n")
  10. printf("i actualmente vale %i\n",i);
  11. printf("%d\n", arr[i-1]);
  12. }
  13. return 0;
  14. }

Salida:

Código
  1. i actualmente vale 0
  2. Asignacion del arreglo
  3. i actualmente vale 1
  4. 1
  5. i actualmente vale 1
  6. Asignacion del arreglo
  7. i actualmente vale 2
  8. 2
  9. i actualmente vale 2
  10. Asignacion del arreglo
  11. i actualmente vale 3
  12. 3
  13. i actualmente vale 3
  14. Asignacion del arreglo
  15. i actualmente vale 4
  16. 4
  17. i actualmente vale 4
  18. Asignacion del arreglo
  19. i actualmente vale 5
  20. 5
  21. i actualmente vale 5
  22. Asignacion del arreglo
  23. i actualmente vale 6
  24. 6
  25. i actualmente vale 6
  26. Asignacion del arreglo
  27. i actualmente vale 7
  28. 7
  29. i actualmente vale 7
  30. Asignacion del arreglo
  31. i actualmente vale 8
  32. 8
  33. i actualmente vale 8
  34. Asignacion del arreglo
  35. i actualmente vale 9
  36. 9
  37. i actualmente vale 9
  38. Asignacion del arreglo
  39. i actualmente vale 10
  40. 10
  41. i actualmente vale 10
  42. Asignacion del arreglo
  43. i actualmente vale 11
  44. 11
  45. i actualmente vale 11
  46. Asignacion del arreglo
  47. i actualmente vale 12
  48. 12
  49. i actualmente vale 12
  50. Asignacion del arreglo
  51. i actualmente vale 13
  52. 13
  53. i actualmente vale 13
  54. Asignacion del arreglo
  55. i actualmente vale 14
  56. 14
  57. i actualmente vale 14
  58. Asignacion del arreglo
  59. i actualmente vale 15
  60. 15
  61. i actualmente vale 15
  62. Asignacion del arreglo
  63. i actualmente vale 16
  64. 16
  65. i actualmente vale 16
  66. Asignacion del arreglo
  67. i actualmente vale 17
  68. 17
  69. i actualmente vale 17
  70. Asignacion del arreglo
  71. i actualmente vale 18
  72. 18
  73. i actualmente vale 18
  74. Asignacion del arreglo
  75. i actualmente vale 19
  76. 19
  77. i actualmente vale 19
  78. Asignacion del arreglo
  79. i actualmente vale 20
  80. 20


Título: Re: Salida inesperada de este programa
Publicado por: geeke en 24 Mayo 2016, 05:36 am
Yo estoy con que la asignacion es totalemente valida.

Con el codigo que el presento solo es necesario modificatr el printf esta es otra version valida.

Te invito a leer la página que proporcioné mas arriba al parecer no tomaste tiempo en leerlo, esa asignación provoca comportamiento indefinido por lo tanto no existe garantía de que el resultado sea lo esperado. Compila ese código con el nivel de advertencia -Wall luego me cuentas


Título: Re: Salida inesperada de este programa
Publicado por: engel lex en 24 Mayo 2016, 05:54 am
AlbertoBSD lo que dice JOWELL es cierto, los incrementos de ese tipo pueden generar comportamiento indefinido y diferentes compiladores pueden tomarlo en diferentes maneras


Código
  1. int add(int x, int y)
  2. {
  3.    return x + y;
  4. }
  5.  
  6. int main()
  7. {
  8.    int x = 5;
  9.    int value = add(x, ++x); // is this 5 + 6, or 6 + 6?  It depends on what order your compiler evaluates the function arguments in
  10.  
  11.    std::cout << value; // value could be 11 or 12, depending on how the above line evaluates!
  12.    return 0;
  13. }

Citar
C++ does not define the order in which function arguments are evaluated. If the left argument is evaluated first, this becomes a call to add(5, 6), which equals 11. If the right argument is evaluated first, this becomes a call to add(6, 6), which equals 12! Note that this is only a problem because one of the argument to function add() has a side effect.

Código
  1. int main()
  2. {
  3.    int x = 1;
  4.    x = x++;
  5.    std::cout << x;
  6.  
  7.    return 0;
  8. }

Citar
What value does this program print? The answer is: it’s undefined. If the ++ is applied to x before the assignment, the answer will be 1. If the ++ is applied to x after the assignment, the answer will be 2.

There are other cases where C++ does not specify the order in which certain things are evaluated, so different compilers will make different assumptions. Even when C++ does make it clear how things should be evaluated, some compilers implement behaviors involving variables with side-effects incorrectly. These problems can generally all be avoided by ensuring that any any variable that has a side-effect applied is used no more than once in a given statement.

http://www.learncpp.com/cpp-tutorial/33-incrementdecrement-operators-and-side-effects/ (http://www.learncpp.com/cpp-tutorial/33-incrementdecrement-operators-and-side-effects/)


Título: Re: Salida inesperada de este programa
Publicado por: AlbertoBSD en 24 Mayo 2016, 14:10 pm
Tienen razon, me dormi pensando en ese problema y me pregunte si estubiera compilando ese codigo que instruccion pondria primero y todas las formas llevan a un reaultado diferente.

Opciones:

Seleccionar la direccion la direccion de memoria para guardar el valor, incrementar i y copiar el valor a la direccion previamemte seleccionada.

Seleccionar la direccion de memoria, copiar el valor e incrementar i.

incrementar i, seleccionar la direccion y copiar el valor.

Copiar el valor a un registro interno, incrementar i y copiar el valor a la direccion de i actual.

Copiar el valor a un registro interno, seleccionar la direccion de memoria, incrementar i

En fin...


Conclusión

Colocar el incremento de i en una linea separada abajo del printf. O en el printf.


Muy didactico el topic parece sencillo, aunque mis primeras  respuesta no eran del todo correctas.

Falta ver que responde Sosar a todo esto.

Saludos.


Título: Re: Salida inesperada de este programa
Publicado por: SebaC en 24 Mayo 2016, 16:15 pm
Ya decía yo que algo andaba mal en esa asignación, en síntesis aquí el orden de evaluación es indefinido  ;-)