Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Punteros y cadena.

Estas en el tema de Punteros y cadena. en el foro de C/C++ en Foros del Web. Buenos días. Tengo un problema con unos datos que quiero guardar en una cadena. Tengo la siguiente función, que cargará los datos a una memoria ...
  #1 (permalink)  
Antiguo 20/01/2014, 23:18
Avatar de guzzano  
Fecha de Ingreso: julio-2010
Ubicación: Isla de Margarita
Mensajes: 162
Antigüedad: 14 años, 3 meses
Puntos: 13
Punteros y cadena.

Buenos días. Tengo un problema con unos datos que quiero guardar en una cadena.

Tengo la siguiente función, que cargará los datos a una memoria dinámica que reciba desde un socket.

Código C:
Ver original
  1. int recv_text (int s_socket, int hlength,
  2.   const char * header, httpstruct * st)
  3. {
  4.   char *buffer = NULL;
  5.   char *bfflen;
  6.  
  7.   unsigned long long allrecv = 0;
  8.   int brecv = 0;
  9.   int bsend = 0;
  10.  
  11.   int r_timeout;
  12.   int s_timeout;
  13.  
  14.   timeout t_out;
  15.  
  16.   t_out.tv_sec = RESOLVED_TIMEOUT;
  17.   t_out.tv_usec = 0;
  18.  
  19.   /* recv timeout */
  20.   r_timeout = setsockopt (s_socket,  
  21.     SOL_SOCKET, SO_RCVTIMEO, &t_out,
  22.     sizeof (timeout));
  23.  
  24.   /* send timeout */
  25.   s_timeout = setsockopt (s_socket,  
  26.     SOL_SOCKET, SO_SNDTIMEO, &t_out,
  27.     sizeof (timeout));
  28.  
  29.   if (r_timeout < 0 || s_timeout < 0)
  30.     return NOT_SETOPT;
  31.  
  32.   bsend = send(s_socket, header,
  33.     hlength, 0);
  34.  
  35.   if (t_out.tv_sec == 0)
  36.     return TIMEOUT;
  37.   else if (bsend != hlength)
  38.     return HEADER_IS_SHORT;
  39.  
  40.   do
  41.   {
  42.     if (allrecv > BYTES_BUFFER_TRANFER)
  43.     {
  44.       buffer = realloc(buffer, allrecv);
  45.      
  46.       if (!buffer)
  47.       {
  48.         close(s_socket);
  49.         return NOT_MEMORY;
  50.       }
  51.      
  52.       bfflen = buffer + BYTES_BUFFER_TRANFER;
  53.     }
  54.     else
  55.     {
  56.       buffer = malloc(BYTES_BUFFER_TRANFER);
  57.  
  58.       if (!buffer)
  59.         return NOT_MEMORY;
  60.      
  61.       bfflen = buffer;
  62.     }
  63.  
  64.     brecv = recv(s_socket, bfflen,
  65.       BYTES_BUFFER_TRANFER, PROTOCOL_ZERO);
  66.    
  67.     allrecv += BYTES_BUFFER_TRANFER;
  68.   } while (brecv > 0);
  69.  
  70.   /* debug without null byte; *(buffer+allrecv) = '\0'; */
  71.   puts(buffer);
  72.   free(buffer); /* for valgrind debug */
  73.   /* */
  74.  
  75.   /* st->httpcontent = buffer */
  76.   st->size_httpcontent = allrecv;
  77.  
  78.   close (s_socket);
  79.   return SUCCESS;
  80. }

El problema sucede que no guarda los datos. Creo la memoria dinámica, la lleno de datos, y cuando vuelva otra vez el bucle, reasignará un espacio a buffer y con bfflen le digo que tiene que empezar a llenar luego de x espacios (BYTES_BUFFER_TRANFER), pero no funciona. Siempre me muestra la cadena mal formada. Disculpen si no me supe explicar.

Saludos.
  #2 (permalink)  
Antiguo 25/01/2014, 04:11
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Punteros y cadena.

No se si lo has solucionado, pero por ahi veo algo raro. Cuando trabajas con sockets no puedes esperar recibir BYTES_BUFFER_TRANFER, sino que le indicas al recv que dispones de BYTES_BUFFER_TRANFER bytes para guardar datos y que te copie lo que sea posible, con eso te retorna el nº de bytes copiados (en tu codigo brecv), y es ese valor el que tienes que usar para incrementar el contador de recibidos; por lo mismo tienes que truncar el buffer de datos recibidos al nº de bytes copiados si ese no se llena.

Otra cosa, en la parte de malloc y realloc; supongamos que BYTES_BUFFER_TRANFER es 256; inicias el proceso:

Código C:
Ver original
  1. //inicio
  2. allrecv = 0;
  3.  
  4. //primer ciclo
  5. si allrecv > 256 => realloc //no porque allrecv = 0
  6. sino => malloc // estamos en este caso
  7. recv //recibes 256
  8. allrecv += 256
  9.  
  10. //segundo ciclo, ahora allrecv = 256 ok?
  11. si allrecv > 256 => realloc //tampoco porque allrecv = 256
  12. sino => malloc // volvemos a estar en este caso ?!?!
  13. //fin de la partida

Supongo que ya ves por donde van los tiros.

Aun otra cosa: supongo que cuando descomentas la linea st->httpcontent = buffer entonces comentas la de free(buffer) :)

Lo que se hace en estos casos es implementar una funcion que bloquea memoria y a la vez concatena lo recibido; te copio una que precisamente hice el otro dia (forma parte de una libreria para un proyecto que tenemos entre manos con un colega):

Código C:
Ver original
  1. /**
  2.     buffer, buffer de trabajo
  3.     block, datos con los que vamos a ampliar el buffer
  4.     block_size, tamaño de block
  5.     buffer_size, tamaño de buffer antes de la ampliacion
  6.     zend, boleano para añadir un 0 al final, es un parche para trabajar con texto
  7. */
  8. int hsock_alloc_strcat(void **buffer, void *block, int block_size, int buffer_size, char zend) {
  9.     char *ptr;
  10.     char endz =(zend)?1:0;
  11.  
  12.     if(!(*buffer)) {
  13.         if(!(*buffer = malloc(block_size + endz))) {
  14.             return 0;
  15.         }
  16.         memset(*buffer, 0, block_size + endz);
  17.     } else {
  18.         if(!(ptr = realloc(*buffer, block_size + buffer_size + endz))) {
  19.             return 0;
  20.         }
  21.         *buffer = ptr;
  22.     }
  23.  
  24.     memcpy(*buffer + buffer_size, block, block_size);
  25.  
  26.     return block_size;
  27. }
  28.  
  29. //ejemplo
  30. char *mibuffer = 0;
  31. char tmp[512];
  32. int nbr, nbc, ttbuffer = 0;
  33.  
  34. //tal como recibo le digo que me amplie el buffer
  35. nbr = recv(socket, tmp, sizeof(tmp), 0);
  36. nbc = hsock_alloc_strcat(&mibuffer, tmp, nbr, ttbuffer, 0);
  37. ttbuffer += nbc;
  38.  
  39. //al finalizar
  40. free(mibuffer);

Espero que te sirva
Saludos
vosk
  #3 (permalink)  
Antiguo 25/01/2014, 17:04
Avatar de guzzano  
Fecha de Ingreso: julio-2010
Ubicación: Isla de Margarita
Mensajes: 162
Antigüedad: 14 años, 3 meses
Puntos: 13
Respuesta: Punteros y cadena.

Buenas vosk.

Sobre el primer punto, ya lo tenía tomado en cuenta, estaba arreglado en el código original, pero en un momento probando y reservando 512 en cada bucle lo dejé así y no lo arreglé. Es una perdida de memoria grande, si los datos que se recibirán de de forma pequeña. Lo sé. Error mío.

Lo demás, ya está arreglado tal como me dices, muchas gracias, estaré implementando una función como la tuya a ver que tal funciona, estaba pensando hacer algo parecido, pero me pareció mejor hacerlo sin una variable temporal.

En efecto, sí, cuando descomento una línea, comento free.

Ya te comentaré resultados, saludos y suerte en ese proyecto.
  #4 (permalink)  
Antiguo 26/01/2014, 05:36
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Punteros y cadena.

"...suerte en ese proyecto..."

Gracias, la vamos a necesitar :)

Saludos
vosk
  #5 (permalink)  
Antiguo 26/01/2014, 19:27
Avatar de guzzano  
Fecha de Ingreso: julio-2010
Ubicación: Isla de Margarita
Mensajes: 162
Antigüedad: 14 años, 3 meses
Puntos: 13
Respuesta: Punteros y cadena.

Hice una función parecida a la tuya, no crees que es meter siempre el espacio del byte nulo. Así cuando se guarde una cadena, agrega al final el 0, y si se tiene que agregar otra, lo remplaza y vuelve a meter el byte nulo al final. Sé que lo agregas sobre todo para trabajar con textos, pero recuerda que muchas funciones usan el 0 para terminar la búsqueda. Así no rellenas la variable completa de 0.

Código C:
Ver original
  1. int block_mem(char **buff, char *block, size_t block_size,
  2.   size_t new_size)
  3. {
  4.   if (!(*buff))
  5.   {
  6.     /* +1 = null byte */
  7.     *buff = malloc((new_size + 1));
  8.    
  9.     if (!(*buff))
  10.       return NOT_MEMORY;
  11.   }
  12.   else
  13.   {
  14.     *buff = realloc(*buff, block_size + new_size);
  15.    
  16.     if (!*(buff))
  17.       return NOT_MEMORY;
  18.   }
  19.  
  20.   memcpy(*buff + block_size, block, new_size);
  21.   *(*buff + block_size + new_size) = '\0';
  22.  
  23.   return new_size;
  24. }
  #6 (permalink)  
Antiguo 27/01/2014, 11:59
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Punteros y cadena.

Saludos guzzano, buena observacion; la opcion del 0 final lo puse con el proposito de reutilizar la funcion: por defecto en datos bajados de red (aun en texto plano) no quiero el 0 final, pero para cualquier otro tipo de operacion si. Es lo que tienes en tu codigo:

Código C:
Ver original
  1. /* +1 = null byte */
  2. *buff = malloc((new_size + 1));

Para el proyecto no nos interesa que siempre termine en 0.

Lo de rellenar la variable completa de 0 lo puse y ahi se quedo (solo está en el malloc), tengo que quitarlo ya que no tiene sentido.

Y una observacion:

Código C:
Ver original
  1. *buff = realloc(*buff, block_size + new_size);
  2. if (!*(buff))
  3.     return NOT_MEMORY;

No apliques el realloc sobre la variable final, en caso de error obtienes una perdida de memoria (memory leak); usa un temporal para la asignacion:

Código C:
Ver original
  1. char *tmp;
  2. if(!(tmp = realloc(*buff, block_size + new_size))) {
  3.     return NOT_MEMORY;
  4. }
  5. *buff = tmp;
  6. memcpy(*buff...

Saludos
vosk

Etiquetas: funcion, int, punteros
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 18:30.