[Ayuda] Problema con cadenas de caracteres

Iniciado por jospar, 7 Mayo 2015, 11:05 AM

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

jospar

Buenas! Estoy realizando un programa que simula un NAT, en concreto estoy terminando la comprobacion del fichero de entrada, que sea correcto. En principio el codigo no tiene errores, compila y casi funciona como es debido, pero una cadena de caracteres almacenada en una tabla de caracteres me esta dando problemas. Paso el codigo y gracias de antemano!


int leeFichEnt(FILE *fich)
{
 struct IP orig;
 struct IP dest;
 struct IP auxorig;
 struct IP auxdest;
 int error=0;
 //Contadores, i para la cadena completa y c para cada dato que saque
 int i;
 int c;
 //Cadena entera
 char cad[256];
 //Procedencia del paquete
 char tipo[TIPO];
 //Datos de la IP origen
 char auxori[IPP];
 int puertori;
 int tamori;
 int tamportori;
 //Datos de la IP destino
 char auxdes[IPP];
 int puertdes;
 int tamdes;
 int tamportdes;
 //Tamaño de los datos del paquete
 char tamanio[2];
 int tam;
 //Cadena auxiliar
 char *aux=NULL;
 char *datos=NULL;
 
 while(fgets(cad, 256, fich)!=NULL)
   {  
     //Hay que obtener la procedencia del paquete
     for(i=0,c=0; i<=TIPO; c++,i++)
tipo[c]=cad[i];
     printf("%s\n", tipo);
     if(strcmp(tipo,PRIVADO) && strcmp(tipo, PUBLICO))
//Hay que guardar la cadena en errores
error=1;
     else
{
 //Obtenemos el tamanio de lo que hay entre [[ ]]
 for(c=0; c<=2; c++,i++)
   tamanio[c]=cad[i];
 tam=atoi(tamanio);
 aux=(char*) calloc(tam,sizeof (char));
 datos=(char*) calloc(tam-(2*MINIP+1), sizeof(char));
 if(aux==NULL)
   {
     printf(MENS_ERR6);
     error=2;
   }
 else
   {
     //Sacamos una cadena con datos e IPs
     for(c=0; c<=tam;c++,i++)
aux[c]=cad[i];

Aqui es donde viene el problema, espero que los comentarios os dejen claro cual es el problema que tengo

              //Desde aqui! sscanf hace algo raro con tipo
     printf("%s\n", tipo);
     //Guardamos segun el dato
     sscanf(aux, "%s %s %s", auxori, auxdes, datos);
     printf("%s\n", tipo);
     //Hasta aqui! La variable tipo cambia su contenido... Por que?

Si alguien puede decirme que pasa en ese sscanf seria de gran ayuda

     sscanf(auxori, "%d.%d.%d.%d:%d", &auxorig.d1, &auxorig.d2, &auxorig.d3, &auxorig.d4, &puertori);
     sscanf(auxdes, "%d.%d.%d.%d:%d", &auxdest.d1, &auxdest.d2, &auxdest.d3, &auxdest.d4, &puertdes);

     //Calculamos tamanio del puerto origen
     if(puertori<10)
tamportori=1;
     else if(puertori>=10 && puertori<100)
tamportori=2;
     else if(puertori>=100 && puertori<1000)
tamportori=3;
     else
tamportori=4;
     //Calculamos tamanio del puerto destino
     if(puertdes<10)
tamportdes=1;
     else if(puertdes>=10 && puertdes<100)
tamportdes=2;
     else if(puertdes>=100 && puertdes<1000)
tamportdes=3;
     else
tamportdes=4;
     //Obtenemos tamanio de las cadenas IP
     tamori=strlen(auxori)-(tamportori+1);
     tamdes=strlen(auxdes)-(tamportdes+1);
     //Comprobamos que las IP son correctas
     error=compruebaIP(&orig, auxori, puertori, tamori);
     if(error==0)
error=compruebaIP(&dest, auxdes, puertdes, tamdes);
     printf("%s %d %s %s %s\n", tipo, tam, auxori, auxdes, datos);
   }
 free(aux);
 aux=NULL;
 free(datos);
 datos=NULL;
}
   }
 return error;
}
La vida es larga y dura, por eso chupame la vida.

do-while

#1
¡Buenas!

Sin ver el código completo no se que es lo que estará pasando exactamente, pero bueno, ahí van posibles errores que pueden suceder:

Por lo que se vé en el último código que has dejado la variable aux es un puntero al que asignas memoria dinamicamente. No sé si al hacerlo has comprobado que el puntero devuelto no sea nulo. Si hubiese algún error en la asignación y te devuelve NULL, a la hora de intentar leer datos de la cadena estarías leyendo "basura" que se guardaría en las variables que pasas a sscanf. La lectura se podría estar haciendo incluso desde una "cadena" que no tuviese un '\0' al final, por lo que se podría estar sobrepasando los límites de las variables y posiblemente sobreescribiendo el valor de la variable tipo.

Algo parecido podría pasar si, aún habiendo podido asignar bien la memoria, al escribir el contenido en aux no pones un '\0' al final de esta, o si alguna de las palabras que contiene aux sobrepasa la longitud de las variables que pasas a sscanf.

Si mal no recuerdo, las variables en C ocupan posiciones consecutivas, por lo tanto si tienes dos cadenas, una de ellas de 3 caracteres y otra de 5 (por poner un ejemplo) te puedes encontrar con errores al sobrepasar los límites. Un ejemple si lees desde la entrada la palabra "Hola" y la guardas en la primera cadena, esta almacenara "Hol" y pasaría a la segunda, quedando esta con los caracteres que quedan por leer: {'a','\0'}. Y si por ejemplo la segunda cadena fuese un puntero los caracteres {'a','\0'} serían dos bytes seguidos que harían que el puntero apuntase a una dirección extraña (perdiendo, si lo hubiese, el contenido que tuvieses asignado dinamicamente).

Sin ver más código no puedo decirte cual es error exacto, pero puede ser alguna de las cosas mencionadas, suelen ser errores lógicos que no saltan a la hora de compilar pero que cuando ejecutas el programa dan resultados "locos" difíciles de detectar.

¡Saludos!

Se me ha olvidado mencionarlo pero es un despiste común (nos pasa a todos) olvidarnos de vez en cuando de dejar sitio para el carácter de fin de cadena, aunque sepas que el tamaño de los datos sea el correcto (porque los introduces tu y sabes que no vas a sobrepasar ningún límite o porque el formato sea fijo y sepas exactamente cuanto va a ocupar una cadena). Aunque supongo que ya lo habrás hecho, asegurate de que IPP tiene el valor correcto para almacenar todos los datos que quieras.

¡Saludos de nuevo!
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!

jospar

CitarSi mal no recuerdo, las variables en C ocupan posiciones consecutivas, por lo tanto si tienes dos cadenas, una de ellas de 3 caracteres y otra de 5 (por poner un ejemplo) te puedes encontrar con errores al sobrepasar los límites. Un ejemple si lees desde la entrada la palabra "Hola" y la guardas en la primera cadena, esta almacenara "Hol" y pasaría a la segunda, quedando esta con los caracteres que quedan por leer: {'a','\0'}. Y si por ejemplo la segunda cadena fuese un puntero los caracteres {'a','\0'} serían dos bytes seguidos que harían que el puntero apuntase a una dirección extraña (perdiendo, si lo hubiese, el contenido que tuvieses asignado dinamicamente).

Aqui puede que este la respuesta a lo que busco, la verdad es que realmente ese es el codigo entero, a excepcion de un main sencillo (que hice para probar la funcion) y las constantes simbolicas (como IPP). Muchas gracias!!
La vida es larga y dura, por eso chupame la vida.

rir3760

Cita de: jospar en  7 Mayo 2015, 11:05 AMuna cadena de caracteres almacenada en una tabla de caracteres me esta dando problemas.
En el primer fragmento el error se encuentra en el bucle donde obtienes la procedencia del paquete:
char tipo[TIPO];

/* ... */

for (i = 0, c = 0; i <= TIPO; c++,i++)
   tipo[c] = cad[i];

Ello porque el array "tipo" consiste de "TIPO" elementos y a ellos accedes mediante los indices 0 .. TIPO-1, si deseas almacenar ahí una cadena debes reservar el ultimo carácter para el '\0' con lo que los indices validos se reducen a 0 .. TIPO-2 pero en el bucle se copian los caracteres con indices 0 .. TIPO (un carácter de mas y no se agrega el '\0').

Para solucionarlo hay varias opciones, una es cambiar el bucle a:
for (i = 0; i < TIPO - 1; i++)
   tipo[i] = cad[i];
tipo[i] = '\0';

Otra es sustituir el bucle por una llamada a sprintf:
sprintf(tipo, "%.*s", TIPO - 1, cad);

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language