Discussion:
error en bucle while
(demasiado antiguo para responder)
s***@hotmail.com
2005-07-14 15:30:39 UTC
Permalink
Necesito saber si a alguno de vosotros le ha ocurrido algo parecido y
sabeis como arreglarlo: A mí no me había pasado hasta ahora...



Estoy usando un bucle while para realizar determinada accion sobre cada
uno de los nodos de una lista simplemente enlazada. La cuestión es que
si pongo un printf antes o después de avanzar al siguiente nodo o
incluso al entrar en el bucle, el bucle funciona correctamente, pero si
lo quito, ocurre fallo de puntero a nulo.

/* Así da error. De forma imprevisible se rompe el bucle. Además no
siempre se rompe en el mismo sitio*/

int funcion(...){

nodo * p;

p = lista; //puntero a primer nodo de la lista

while (p!=NULL){

if(....){

//no escribo el tratamiento

}

p=p->siguiente;

}

return OK;
}

/*Si pongo un simple printf , funciona el bucle correctamente*/

int funcion(...){

nodo * p;

p = lista; //puntero a primer nodo de la lista

while (p!=NULL){

if(....){

//no escribo el tratamiento

}

printf("\nSi lo pongo funciona\n");
p=p->siguiente;

}

return OK;
}

El bucle va también bien si se añade el printf después de avanzar
al nodo siguiente , dentro del bucle while o incluso antes de la
llamada a esta función.


¿Sabría alguien decirme qué hacer ?

Un saludo ,SONIA
Oscar Garcia
2005-07-14 15:35:37 UTC
Permalink
Post by s***@hotmail.com
Estoy usando un bucle while para realizar determinada accion sobre cada
uno de los nodos de una lista simplemente enlazada. La cuestión es que
si pongo un printf antes o después de avanzar al siguiente nodo o
incluso al entrar en el bucle, el bucle funciona correctamente, pero si
lo quito, ocurre fallo de puntero a nulo.
Lo siento, con el código que nos has entregado es imposible determinar
tu error (sí, desde mi punto de vista siempre eres culpable de un
error de punteros hasta que se demuestra lo contrario :).

Péganos el código completo y el código que llama a la función (o llena
la lista).

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
s***@hotmail.com
2005-07-15 07:15:44 UTC
Permalink
Te adjunto la función que me da problemas aunque por si sola no tiene
mucho sentido.....


/* Función que comprueba si existen CN del CC que tienen mensajes
pendientes de enviarle
* Parámetros
* Nodo del CC del que queremos comprobar si existen mensajes por
recibir.
*
* Devuelve
OK si habiendo mensajes pendientes se han logrado enviar
ERROR_CONEXION si al escribir en el socket del CC da error
*/

int obtenerCCMensajes ( nodo * cc){

nodo * cn;
int control;
nodoMensaje *msg = NULL;
nodoMensaje *aux = NULL;
nodoMensaje *primero=NULL;
char *mensaje=NULL, *paquete=NULL;

cn=lSocketClientesCN; //es variable global
//para cada una de las cajas negras en la lista de CN

while(cn!=NULL){
//si la CN pertenece al CC
if ( strcmp(devolverEmpresaAsociada(cn),cc->dato->identificativo)==0 )
{
//obtenemos el primer mensaje almacenado
recuperarNodoMensaje(cn, &msg);
while ( msg != NULL )
{ //recuperamos el texto del mensaje
recuperarMensaje(msg, &mensaje);
//se envía al socket del CC al que le corresponde la CN
printf("\nEl mensaje es : %s\n", mensaje);
control=Escribe_Socket( devolverSocket(cc), mensaje, strlen(mensaje)
);
//si el envío ha sido correcto
if(control>0){
//eliminamos el mensaje de la cola de mensajes de la CN
// y avanzamos al siguiente mensaje.
aux=msg->sig;
eliminarMensaje( cc, msg ); msg=aux;
}//if
//si no se ha podido enviar, avisamo del posible
// problema y retornamos error de conexion
else{
printf("\nError en el envío de mensaje. Posible desconexión del
socket del CC %s\n", cc->dato->identificativo);
return ERROR_CONEXION;
} //else

//vaciamos buffer del mensaje.
strcpy(mensaje,"");
}//while
}//if
//comprobamos la siguiente CN
cn=cn->sig;
}//while
return OK;

}

Como ves esta función implica muchas otras por lo que enviarte el
código para compilar es un tanto difícil.....

El problema ocurre en el bucle while externo: si pongo un printf antes
o después de avanzar (cn=cn->sig) el bucle funciona correctamente ,
pero si lo dejo tal cual está , se rompe antes de lo debido .
Te adjunto las estructuras de los nodos para mayor orientación:

struct nodo_Mensaje{
char *mensaje;
char *destino;
struct nodo_Mensaje *sig;};
typedef struct nodo_Mensaje nodoMensaje;

struct datos_Socket{
char *identificativo;
int conectado;
int socket;
char *empresaAsociada;
nodoMensaje *listaMensajes;};
typedef struct datos_Socket datosSocket;

struct nodoLista{
datosSocket *dato;
struct nodoLista *sig;};
typedef struct nodoLista nodo;
s***@hotmail.com
2005-07-15 07:15:50 UTC
Permalink
Te adjunto la función que me da problemas aunque por si sola no tiene
mucho sentido.....


/* Función que comprueba si existen CN del CC que tienen mensajes
pendientes de enviarle
* Parámetros
* Nodo del CC del que queremos comprobar si existen mensajes por
recibir.
*
* Devuelve
OK si habiendo mensajes pendientes se han logrado enviar
ERROR_CONEXION si al escribir en el socket del CC da error
*/

int obtenerCCMensajes ( nodo * cc){

nodo * cn;
int control;
nodoMensaje *msg = NULL;
nodoMensaje *aux = NULL;
nodoMensaje *primero=NULL;
char *mensaje=NULL, *paquete=NULL;

cn=lSocketClientesCN; //es variable global
//para cada una de las cajas negras en la lista de CN

while(cn!=NULL){
//si la CN pertenece al CC
if ( strcmp(devolverEmpresaAsociada(cn),cc->dato->identificativo)==0 )
{
//obtenemos el primer mensaje almacenado
recuperarNodoMensaje(cn, &msg);
while ( msg != NULL )
{ //recuperamos el texto del mensaje
recuperarMensaje(msg, &mensaje);
//se envía al socket del CC al que le corresponde la CN
printf("\nEl mensaje es : %s\n", mensaje);
control=Escribe_Socket( devolverSocket(cc), mensaje, strlen(mensaje)
);
//si el envío ha sido correcto
if(control>0){
//eliminamos el mensaje de la cola de mensajes de la CN
// y avanzamos al siguiente mensaje.
aux=msg->sig;
eliminarMensaje( cc, msg ); msg=aux;
}//if
//si no se ha podido enviar, avisamo del posible
// problema y retornamos error de conexion
else{
printf("\nError en el envío de mensaje. Posible desconexión del
socket del CC %s\n", cc->dato->identificativo);
return ERROR_CONEXION;
} //else

//vaciamos buffer del mensaje.
strcpy(mensaje,"");
}//while
}//if
//comprobamos la siguiente CN
cn=cn->sig;
}//while
return OK;

}

Como ves esta función implica muchas otras por lo que enviarte el
código para compilar es un tanto difícil.....

El problema ocurre en el bucle while externo: si pongo un printf antes
o después de avanzar (cn=cn->sig) el bucle funciona correctamente ,
pero si lo dejo tal cual está , se rompe antes de lo debido .
Te adjunto las estructuras de los nodos para mayor orientación:

struct nodo_Mensaje{
char *mensaje;
char *destino;
struct nodo_Mensaje *sig;};
typedef struct nodo_Mensaje nodoMensaje;

struct datos_Socket{
char *identificativo;
int conectado;
int socket;
char *empresaAsociada;
nodoMensaje *listaMensajes;};
typedef struct datos_Socket datosSocket;

struct nodoLista{
datosSocket *dato;
struct nodoLista *sig;};
typedef struct nodoLista nodo;
Oscar Garcia
2005-07-15 09:47:20 UTC
Permalink
Post by s***@hotmail.com
Te adjunto la función que me da problemas aunque por si sola no tiene
mucho sentido.....
//se envía al socket del CC al que le corresponde la CN
printf("\nEl mensaje es : %s\n", mensaje);
Supongo que si estás trabajando con sockets reales sabrás que ellos no
tienen porqué finalizar sus mensajes con un carácter \0, ¿verdad?
Cuidado con ese punto.
Post by s***@hotmail.com
control=Escribe_Socket( devolverSocket(cc), mensaje, strlen(mensaje)
);
Sabías que si haces eso envías la cadena de caracteres al otro extremo
sin la terminación de cadena \0, ¿verdad?
Post by s***@hotmail.com
//eliminamos el mensaje de la cola de mensajes de la CN
// y avanzamos al siguiente mensaje.
aux=msg->sig;
eliminarMensaje( cc, msg ); msg=aux;
¿Exactamente cómo haces para eliminar un elemento de una lista sin
estar doblemente enlazada y perdiendo el valor de la cadena anterior
para poder hacer el "salto" en la lista?
Post by s***@hotmail.com
//vaciamos buffer del mensaje.
strcpy(mensaje,"");
Sería más sencillo hacer:
*mensaje = 0;

O bien:
mensaje[0] = 0;

El problema lo tienes en que esta variable "mensaje" apunta a una zona
de memoria que posiblemente haya sido liberada al hacer
"eliminarMensaje". ¿Has tenido en cuenta ese detalle?

Por cierto... usas memoria dinámica para las cadenas por lo que estoy
viendo. Estás haciendo correctamente los mallocs, ¿no?
Post by s***@hotmail.com
Como ves esta función implica muchas otras por lo que enviarte el
código para compilar es un tanto difícil.....
Creo que me haría falta examinar las funciones de creación y gestión
de colas. Creo que en ellas está la clave del error.
Post by s***@hotmail.com
El problema ocurre en el bucle while externo: si pongo un printf antes
o después de avanzar (cn=cn->sig) el bucle funciona correctamente ,
pero si lo dejo tal cual está , se rompe antes de lo debido .
Tiene una pinta de ser error de punteros asombrosa :) Posiblemente el
error no lo genere cn=cn->sig, si no cualquier otra parte de la
función que prepara la pila (el heap) para un desastre inminente al no
ser llamada una función por parámetros antes de dicha línea.

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
Antoine Leca
2005-07-15 11:53:29 UTC
Permalink
Post by s***@hotmail.com
nodoMensaje *msg = NULL;
char *mensaje=NULL, *paquete=NULL;
recuperarNodoMensaje(cn, &msg);
while ( msg != NULL )
{ //recuperamos el texto del mensaje
recuperarMensaje(msg, &mensaje);
Hasta aquí tiene su lógica.
En este punto deberías añadir un test (assert) que mensaje != NULL (o
strlen(mensaje) es «razonable», de 1 a 1500 o cualquier cosa)
Post by s***@hotmail.com
eliminarMensaje( cc, msg );
¿Pór que está el parametro cc? Revisa si no debería ser cn (y son los
mismos, el test con strcmp al principio es demasiado complejo, cc == cn
bastaría).

Supongo que elimarMensaje debe hacer algo como free(msg.mensaje),
free(msg.destino), free(msg), entonces no entiendo por que se debe pasar un
nodo también...
¿O hay algo como cc.dato->listaMensajes = msg.sig;?

Podrias añadir algo como strcpy(msg.mensage, "BORRADO") antes del free, a
ver si después te sale este BORRADO que indicaría un error de allocación...
Post by s***@hotmail.com
//vaciamos buffer del mensaje.
strcpy(mensaje,"");
Sea coherente, pon
mensaje=NULL;
tal como lo hacias arriba. strcpy() posiblamente puede escribir en una parte
de la memoría que está equivocada.
De hecho, no veo la razón de hacer eso. ¿Qué pasa si lo borres?


Antoine

Antoine Leca
2005-07-15 07:05:18 UTC
Permalink
Post by s***@hotmail.com
Necesito saber si a alguno de vosotros le ha ocurrido algo parecido
Errores de punteros todos ya hemos tenido.
Logicamente, inspectando el contenido del objeto puntado en el bucle y
señalando cuando se sale de la norma... Pero eso ya lo sabias, ¿verdad?

¿Tienes debugger? ¿Sigue dando problemas con él? (a veces los problemas como
este desaparecen cuando pones el debugger, por que depiende del número de
cosas que hay cerca de la instrucción mala)
Si es así, es tan senzillo como utilizar el debugger hasta que ves la
instrucción que cambia el p a una valor no esperada. Los debuggers de hoy en
día tienen opciones para saltar fuera del sueño cuando varia la valor de
alguna variable, o cuando se asigna un valor a un objeto: es la función que
se debe usar en este caso.

Otra idea, puedes cambiar las opciones de optimización.
Post by s***@hotmail.com
/* Así da error. De forma imprevisible se rompe el bucle. Además no
siempre se rompe en el mismo sitio*/
A ver si lo he entendido: a veces el p se cambia a NULL (o otra cosa) en
lugar del siguiente de la lista. Pero eso no ocurre siempre en el mismo
objeto, y jamás ocurre si hay un printf por aquí andando.
Post by s***@hotmail.com
while (p!=NULL){
if(....){
//no escribo el tratamiento
Pues ¡debería!

El problema está basicamente en alguna instrucción que tiene un efecto
incorrecto, que a veces modifica la valor de p de manera inesperada. ¡Todas
las líneas que portan p son suspechosas en principio!
Post by s***@hotmail.com
printf("\nSi lo pongo funciona\n");
Pregunta 1: ¿tu printf anti-bug es tan senzillo como este?

Pregunta 2: ¿es preciso el \n inicial para que desaparece el error? Si es
ací, mira si no hace falta algun fflush(stdout); en el bucle...


Antoine
Loading...