unir - string en c
Usando strcat en C (7)
Comience usando la función de strncat
más strncat
. En general, utilice siempre las funciones ''n'' más seguras que no se desbordarán si el tamaño de una cadena es mayor que un tamaño específico.
En C, usted necesita cuidar los tamaños de las cuerdas usted mismo. Entonces necesita saber qué tan grande será la cadena resultante y adaptarse a ella. Si conoce los tamaños de todas las cadenas en el lado izquierdo, debe crear un búfer lo suficientemente grande como para contener la cadena resultante.
De acuerdo, tengo el siguiente código que agrega una cadena a otra en C #, tenga en cuenta que esto es solo un ejemplo , por lo que no es necesario dar métodos alternativos de concatenación de cadenas en C #, esto es solo para simplificar el ejemplo.
string Data = "";
Data +="/n/nHTTP/1.1 " + Status_code;
Data += "/nContent-Type: " + Content_Type;
Data += "/nServer: PT06";
Data += "/nContent-Length: " + Content_Lengt;
Data += "/nDate: " + Date;
Data += "/n" + HTML;
Ahora me gustaría hacer exactamente lo mismo en C y estoy tratando de hacer esto de la siguiente manera
time_t rawtime;
time ( &rawtime );
char *message = "/n/nHTTP/1.1 ";
message = strcat(message, Status_code);
message = strcat(message, "/nContent-Type: ");
message = strcat(message, Content_Type);
message = strcat(message, "/nServer: PT06");
message = strcat(message, "/nContent-Length: ");
message = strcat(message, Content_Lengt);
message = strcat(message, "/nDate: ");
message = strcat(message, ctime(&rawtime));
message = strcat(message, "/n");
message = strcat(message, HTML);
Ahora, esto me da una falla de Segmento, sé por qué, accedo y leo en la memoria que no debería. Pero la pregunta es, ¿cómo lo resuelvo? ¿Podría usar string.h y simplemente hacerlo de la misma manera que lo hice en C #?
Como se dijo anteriormente, debe escribir en un búfer lo suficientemente grande. Desafortunadamente, hacerlo es mucho trabajo extra. La mayoría de las aplicaciones C que se ocupan de cadenas utilizan un búfer de cadena de tamaño variable dinámicamente para realizar concatenaciones.
glib incluye una implementación de esto, strings glib , que recomiendo usar para cualquier aplicación que use cadenas de texto. Hace que administrar la memoria sea más fácil y evita los desbordamientos de la memoria intermedia.
La forma más segura de hacer esto en el clásico estilo C es:
char *strconcat(char *s1, char *s2)
{
size_t old_size;
char *t;
old_size = strlen(s1);
/* cannot use realloc() on initial const char* */
t = malloc(old_size + strlen(s2) + 1);
strcpy(t, s1);
strcpy(t + old_size, s2);
return t;
}
...
char *message = "/n/nHTTP/1.1 ";
message = strconcat (message, Status_code);
message = strconcat (message, "/nContent-Type: ");
Ahora puedes decir muchas cosas malas sobre esto: es ineficiente, fragmenta tu memoria, es feo ... pero es más o menos lo que cualquier lenguaje con un operador de concatenación de cadenas y cadenas tipo C (cero-terminadas) hará ( excepto que la mayoría de estos idiomas tendrán una recolección de basura incorporada).
Me pregunto por qué nadie mencionó snprintf()
desde stdio.h
todavía. Esa es la forma C de generar múltiples valores y ni siquiera tendrá que convertir sus primitivos en cadenas de antemano.
El siguiente ejemplo usa una pila asignada de buffer de tamaño fijo. De lo contrario, tiene que malloc()
el búfer (y almacenar su tamaño), lo que haría posible realloc()
en desbordamiento ...
char buffer[1024];
int len = snprintf(buffer, sizeof(buffer), "%s %i", "a string", 5);
if(len < 0 || len >= sizeof(buffer))
{
// buffer too small or error
}
Editar: También podría considerar usar la función asprintf()
. Es una extensión de GNU ampliamente disponible y parte de TR 24731-2 (lo que significa que podría convertirse en el próximo estándar C). El ejemplo de arriba leería
char * buffer;
if(asprintf(&buffer, "%s %i", "a string", 5) < 0)
{
// (allocation?) error
}
¡Recuerde free()
el buffer cuando termine de usarlo!
No he visto ninguna mención de la función strlcpy, strlcat, que es similar a las funciones ''n'', excepto que también toma en cuenta el 0. posterior. Ambos toman un tercer argumento que indica la longitud máxima del buffer de salida y se encuentran en string.h .
ejemplo:
char blah[]="blah";
char buffer[1024];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s/n",buffer);
Producirá "herro !!! blah"
char blah[]="blah";
char buffer[10];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s/n",buffer);
producirá "herro !!! b" debido al tamaño limitado del búfer [], sin segfaulting. ^^
El único problema es que no todas las plataformas parecen incluirlo en su libc (como linux ._.), La mayoría de los variadores de BSD sí lo tienen.
En ese caso, el código para ambas funciones se puede encontrar aquí y agregar fácilmente: strlcpy , strlcat , el resto de string.h
el mensaje apunta a una char const [] en la que no se puede escribir, sin embargo, es exactamente donde está escribiendo strcat. Necesitas malloc () un buffer suficientemente grande.
Cambio
char *message = "/n/nHTTP/1.1 ";
a
char message[1024];
strcpy(message,"/n/nHTTP/1.1 ");
y debería estar bien, hasta una longitud total de mensaje de 1023.
Editar: (según el comentario de mjy). Usar strcat de esta manera es una excelente forma de obtener desbordamientos de búfer. Puede escribir fácilmente una pequeña función que compruebe el tamaño del búfer y la longitud de la adición de cadena entrante para superar esto, o use realloc en un búfer dinámico. IMO, la responsabilidad recae en el programador para verificar los tamaños de búfer correctos donde se usan, como con sprintf y otras funciones de cadenas de C. Supongo que C se está utilizando en C ++ por razones de rendimiento, y por lo tanto STL no es una opción.
Editar: Según la solicitud del comentario de Filip, una implementación strcat simple basada en un búfer char fijo de tamaño:
char buffer[MAXSIZE] = "";
int mystrcat(char *addition)
{
if (strlen(buffer) + strlen(addition) + sizeof(char) >= MaxSize)
return(FAILED);
strcat(buffer,addition);
return(OK);
}
Usando asignación dinámica:
char *buffer = NULL;
int mystrcat(char *addition)
{
buffer = realloc(buffer, strlen(buffer) + strlen(addition) + sizeof(char));
if (!buffer)
return(FAIL);
strcat(buffer, addition);
return(OK);
}
En este caso, debe liberar su búfer manualmente cuando termine de usarlo. (Manejado por destructores en C ++ equivalentes)
Adición (Pax):
De acuerdo, ya que en realidad no explicaste por qué tenías que crear el message[1024]
, aquí está.
Con char * x = "hola", los bytes reales (''h'', ''e'', ''l'', ''l'', ''o'', 0) (nulo en el extremo) se almacenan en un área de memoria separada de las variables (y muy posiblemente de solo lectura) y la variable x se establecen para apuntar a ella. Después del nulo, probablemente haya algo más muy importante. Entonces no puedes anexar eso en absoluto.
Con char x[1024]; strcpy(x,"hello");
char x[1024]; strcpy(x,"hello");
, primero asigna 1K om memoria que está totalmente dedicada a x. Luego copie "hola" en él y aún deje bastante espacio al final para agregar más cadenas. No te meterás en problemas hasta que añadas más de 1K-odd permitido.
End addéndum (Pax):