Salida inesperada de este programa

Iniciado por SebaC, 23 Mayo 2016, 23:58 PM

0 Miembros y 1 Visitante están viendo este tema.

SebaC

Tengo este sencillo programa

#include <stdio.h>

int main(void)
{
int i = 0;
int arr[20];

    while(i < 20)
{
arr[i++] = i;
printf("%d\n", arr[i]);
}

    return 0;
}


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í?

AlbertoBSD

arr[i++] = i;
Estas asignado e incrementando i
y despues imprimes el i no inicializado.

Tienes que incrementar en el printf o despues
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

SebaC

Cita de: AlbertoBSD en 24 Mayo 2016, 00:07 AM
y despues imprimes el i no inicializado.

Yo inicialice i a cero no entiendo porque dices eso

AlbertoBSD

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
#include <stdio.h>

int main(void)
{
int i = 0;
int arr[20];

    while(i < 20)
{
arr[i] = i;
printf("%d\n", arr[i]);
                i++;
}

    return 0;
}


o bien

#include <stdio.h>

int main(void)
{
int i = 0;
int arr[20];

    while(i < 20)
{
arr[i] = i;
printf("%d\n", arr[i++]);
}

    return 0;
}


¿Vez la diferencia?
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

geeke

Código (cpp) [Seleccionar]
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

AlbertoBSD

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.

#include <stdio.h>

int main(void) {
int i = 0;
int arr[20];
while(i < 20) {
arr[i++] = i;
printf("%d\n", arr[i-1]);
}
return 0;
}



Salida:


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



Se le podria agregar

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

#include <stdio.h>

int main(void) {
int i = 0;
int arr[20];
while(i < 20) {
printf("i actualmente vale %i\n",i);
arr[i++] = i;
printf("Asignacion del arreglo\n")
printf("i actualmente vale %i\n",i);
printf("%d\n", arr[i-1]);
}
return 0;
}


Salida:

i actualmente vale 0
Asignacion del arreglo
i actualmente vale 1
1
i actualmente vale 1
Asignacion del arreglo
i actualmente vale 2
2
i actualmente vale 2
Asignacion del arreglo
i actualmente vale 3
3
i actualmente vale 3
Asignacion del arreglo
i actualmente vale 4
4
i actualmente vale 4
Asignacion del arreglo
i actualmente vale 5
5
i actualmente vale 5
Asignacion del arreglo
i actualmente vale 6
6
i actualmente vale 6
Asignacion del arreglo
i actualmente vale 7
7
i actualmente vale 7
Asignacion del arreglo
i actualmente vale 8
8
i actualmente vale 8
Asignacion del arreglo
i actualmente vale 9
9
i actualmente vale 9
Asignacion del arreglo
i actualmente vale 10
10
i actualmente vale 10
Asignacion del arreglo
i actualmente vale 11
11
i actualmente vale 11
Asignacion del arreglo
i actualmente vale 12
12
i actualmente vale 12
Asignacion del arreglo
i actualmente vale 13
13
i actualmente vale 13
Asignacion del arreglo
i actualmente vale 14
14
i actualmente vale 14
Asignacion del arreglo
i actualmente vale 15
15
i actualmente vale 15
Asignacion del arreglo
i actualmente vale 16
16
i actualmente vale 16
Asignacion del arreglo
i actualmente vale 17
17
i actualmente vale 17
Asignacion del arreglo
i actualmente vale 18
18
i actualmente vale 18
Asignacion del arreglo
i actualmente vale 19
19
i actualmente vale 19
Asignacion del arreglo
i actualmente vale 20
20
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

geeke

Cita de: 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.

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

engel lex

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 (cpp) [Seleccionar]
int add(int x, int y)
{
   return x + y;
}

int main()
{
   int x = 5;
   int value = add(x, ++x); // is this 5 + 6, or 6 + 6?  It depends on what order your compiler evaluates the function arguments in

   std::cout << value; // value could be 11 or 12, depending on how the above line evaluates!
   return 0;
}


CitarC++ 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 (cpp) [Seleccionar]
int main()
{
   int x = 1;
   x = x++;
   std::cout << x;

   return 0;
}


CitarWhat 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/
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

AlbertoBSD

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.
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

SebaC

Ya decía yo que algo andaba mal en esa asignación, en síntesis aquí el orden de evaluación es indefinido  ;-)