[C con Clase] Punteros

David xdrtas en yahoo.es
Jue Feb 1 21:42:29 CET 2007


Hola a todos.
Quiero agradecerles por la ayuda prestada hoy, la verdad es que me han aclarado las dudas, especialmenre Steven, sin embargo las gracias van para todos :-D.

Steven, con lo que me has explicado me has demostrado que hay que tener mucho cuidado en como se manejan los punteros. Gracias por el añadido de los operadores.
En cuanto a lo del valor de 40 o 41, no es que cometiera un "error", sino que estaba haciendo pruebas cambiando los valores, yo empecé con el valor de 40 y al ver el incremento que me hacia el compilador pues cambié deliberadamente el valor en el código a 41, cuando copié el código no me di cuanta de volverlo a dejarlo como estaba. Sin embargo te digo que cuando colocaba el valor de 41, "*p" me devolvía 42. :-P

De todas formas da igual, lo importante aquí es esa explicación que me has pasado, de nuevo quiero dar las gracias a todos.

Un saludo. David Lastra.

----- Mensaje original ----
De: Steven Davidson <steven en conclase.net>
Para: cconclase en listas.conclase.net
Enviado: jueves, 1 de febrero, 2007 18:39:52
Asunto: Re: [C con Clase] Punteros

Hola David,

El pasado 2007-02-01 07:49:28, David escribió:

D> Hola a todos, tengo un pequeño problema con los punteros, veran yo uso MS Visual C++ 6.0 y al ejecutar el siguiente programa:
D> #include <iostream.h>
D> void main () {
D>     int a = 10, b = 100, c = 30, d = 1, e = 54;
D>     int m[10] = {10,20,30,41,50,60,70,80,90,100};
D>     int *p = &m[3], *q = &m[6];
D>     
D>     cout << "Son iguales? " << p << ", " << &m[3] << ", " << *p << endl;
D>     cout << "--------------------------------------------------------\n\n" << endl;
D>     cout << m[3] << " : " << &m[3] << " : " << p << " : " << *p << " : " << ++*p << " : " << *p++ << " : " << ++*p++ << endl;
D> Me da el siguiente resultado:
D> Son iguales? 0x0012FF50, 0x0012FF50, 41
D> --------------------------------------------------------
D> 42 : 0x0012FF50 : 0x0012FF58 : 61 : 61 : 50 : 42
D> Como pueden comprobar, cada vez que quiero imprimir el valor del puntero "*p" me suma 1 al valor al que apunta. Si no me equivoco, cuando mando a imprimir en pantalla "*p", debería salirme 40 y no 41. Alguien sabe que pasa, tal vez sea alguna directiva del compilador, pero hasta ahora no he dado con el fallo, si es que lo hay.

Vamos por partes. Te sale 41 porque escribiste 41 en la inicialización del array 'm'. En otro mensaje corregiste este valor inicial a 40, por lo que debería salirte 40. En cuanto a la diferencia de las direcciones de memoria, al igual que los valores impresos en la segunda línea, todo esto tiene que ver con un tema poco hablado y tratado acerca de los operadores de incremento y decremento junto con asignaciones.

Antes de explicar este tema, quiero hablar de otro para aclarar la evaluación de los operadores. Recuerda que los operadores y por tanto sus operaciones son evaluados en cierto orden según la tabla de precedencia y asociatividad. Puedes consultar el capítulo 14 del curso de C++. El enlace es: http://c.conclase.net/curso/index.php?cap=014  Aplicamos esta tabla a tu código. Las primeras operaciones evaluadas son 'm[3]'. Luego llegamos a los operadores unitarios de incremento (++), dirección de (&), y acceso o puntero a (*), que son evaluados de derecha a izquierda. La secuencia viene a ser la siguiente:

1. ++*p++  que viene a ser  (++(*(p++)))

Esto implica que a) incrementamos el puntero póstumamente, b) accedemos al valor apuntado, y c) incrementamos tal valor.

2. Luego evaluamos,

*p++  que es equivalente a  (*(p++))

Volvemos a incrementar el puntero póstumamente y luego accedemos a su valor.

3. Después tenemos que,

++*p  que equivale a  (++(*p))

Aquí, accedemos al valor apuntado para incrementarlo.

4. Seguidamente tenemos,

*p  que simplemente accede al valor apuntado.

5. Por último, obtenemos la dirección de memoria del valor-i(zquierdo) o en inglés "lvalue" de 'm[3]' con la operación '&m[3]'.

Al final, evaluamos los operadores binarios de << de izquierda a derecha. Esto es,

(...(((cout << m[3]) << " : ") << &m[3])...<<...)


Bien. Volvamos al tema "poco hablado" que mencioné al principio. Este tema tiene que ver con la asignación de variables que son incrementados o restados en la misma expresión. Por ejemplo,

int i=10;

++i = i++ + i++;

La pregunta es ¿cuál es el valor final de 'i' después de evaluar la expresión? Pues me temo que no hay una respuesta definitiva. Esto depende del diseño del compilador.

Algunos compiladores darán como respuesta: 24, ya que incrementa 'i' debido a '++i' para luego resultar en 22. Luego, incrementa dos veces este resultado por las dos operaciones de incremento póstumo: 'i++'.

Otros compiladores pueden decidir que el resultado es: 23, porque se realiza un solo incremento póstumo.

Y algunos otros compiladores pueden evaluar la expresión como 22, porque ignoran el incremento de 'i++' ya que esta operación modificaba el valor original de 11 (después del incremento antecedente de '++i'). Sin embargo, como 'i' es reasignado, entonces el incremento póstumo no tiene "validez".

Dicho lo anterior, puede haber otro compilador que resuelva el problema dando la solución: 13. Su "razonamiento" tiene que ver con la implementación de 'i++'. Primero hacemos el pre-incremento '++i' obteniendo 11. Al evaluar 'i++', el compilador asigna el valor incrementado a 'i' después de la expresión: de 11 á 12 y de 12 á 13. Se generaría una secuencia de instrucciones como la siguiente:

int i=10;

++i;
// i++
__copia__ = i;
__nuevo1__ = i+1;
__nuevo2__ = i+1;   // otro i++
i = __copia__ + __copia__;
i = __nuevo2__;  // final de i++


Existen otros problemas al evaluar algo similar con otras combinaciones de asignaciones e incrementos y reducciones tanto antecedentes como póstumos. La conclusión es que depende del compilador. La solución es no escribir algo así, sino ser más explícito. Por ejemplo, podemos reescribir la expresión anterior como:

int i=10;

++i;
i = i + i;
i++;
i++;


Espero haber aclarado las dudas.

Steven
_______________________________________________
Lista de correo Cconclase Cconclase en listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ







	
	
		
______________________________________________ 
LLama Gratis a cualquier PC del Mundo. 
Llamadas a fijos y móviles desde 1 céntimo por minuto. 
http://es.voice.yahoo.com
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20070201/65ac03fe/attachment.html>


Más información sobre la lista de distribución Cconclase