unidos - ¿Cómo concatenar cadenas const/literales en C?
problema de armas en estados unidos (17)
Estoy trabajando en C, y tengo que concatenar algunas cosas.
Ahora mismo tengo esto:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Ahora, si tiene experiencia en C, estoy seguro de que se da cuenta de que esto le da un error de segmentación cuando intenta ejecutarlo. Entonces, ¿cómo puedo trabajar alrededor de eso?
Amigos, use str n cpy (), str n cat () o s n printf ().
¡Excediendo el espacio de tu búfer se trash lo que sigue en la memoria!
(¡Y recuerde dejar espacio para el carácter ''/ 0'' nulo final!)
Como la gente señaló, el manejo de cuerdas mejoró mucho. Por lo tanto, es posible que desee aprender a usar la biblioteca de cadenas de C ++ en lugar de las cadenas de estilo C. Sin embargo aquí hay una solución en C puro.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void appendToHello(const char *s) {
const char *const hello = "hello ";
const size_t sLength = strlen(s);
const size_t helloLength = strlen(hello);
const size_t totalLength = sLength + helloLength;
char *const strBuf = malloc(totalLength + 1);
if (strBuf == NULL) {
fprintf(stderr, "malloc failed/n");
exit(EXIT_FAILURE);
}
strcpy(strBuf, hello);
strcpy(strBuf + helloLength, s);
puts(strBuf);
free(strBuf);
}
int main (void) {
appendToHello("blah blah");
return 0;
}
No estoy seguro de si es correcto / seguro, pero en este momento no pude encontrar una mejor manera de hacerlo en ANSI C.
El primer argumento de strcat () debe ser capaz de contener suficiente espacio para la cadena concatenada. Entonces, asigne un búfer con suficiente espacio para recibir el resultado.
char bigEnough[64] = "";
strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);
/* and so on */
strcat () concatenará el segundo argumento con el primer argumento, y almacenará el resultado en el primer argumento, el char * devuelto es simplemente este primer argumento, y solo para su conveniencia.
No obtiene una cadena recién asignada con el primer y el segundo argumento concatenado, lo que supongo que esperaba según su código.
En C, las "cadenas" son simplemente matrices de caracteres. Por lo tanto, no puede concatenarlos directamente con otras "cadenas".
Puede usar la función strcat
, que agrega la cadena apuntada por src
al final de la cadena apuntada por dest
:
char *strcat(char *dest, const char *src);
Aquí hay un ejemplo de cplusplus.com :
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
Para el primer parámetro, debe proporcionar el búfer de destino. El búfer de destino debe ser un búfer de matriz de caracteres. Ej .: char buffer[1024];
Asegúrese de que el primer parámetro tenga suficiente espacio para almacenar lo que está intentando copiar en él. Si está disponible para usted, es más seguro usar funciones como: strcpy_s
y strcat_s
donde tiene que especificar explícitamente el tamaño del búfer de destino.
Nota : un literal de cadena no se puede usar como un búfer, ya que es una constante. Por lo tanto, siempre debe asignar una matriz de caracteres para el búfer.
El valor de retorno de strcat
puede simplemente ignorarse, simplemente devuelve el mismo puntero que se pasó como primer argumento. Está allí para su comodidad y le permite encadenar las llamadas en una sola línea de código:
strcat(strcat(str, foo), bar);
Entonces tu problema podría ser resuelto de la siguiente manera:
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
Es un comportamiento indefinido intentar modificar los literales de cadena, que es algo así como:
strcat ("Hello, ", name);
intentará hacer. Intentará pegar la cadena de name
al final de la cadena literal "Hello, "
, que no está bien definida.
Intenta algo esto. Logra lo que pareces estar tratando de hacer:
char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);
Esto crea un área de búfer que se puede modificar y luego copia el literal de la cadena y otro texto en él. Sólo ten cuidado con los desbordamientos de búfer. Si controla los datos de entrada (o los verifica de antemano), está bien usar buffers de longitud fija como los que tengo.
De lo contrario, debe usar estrategias de mitigación, como asignar suficiente memoria del montón para asegurarse de que puede manejarlo. En otras palabras, algo como:
const static char TEXT[] = "TEXT ";
// Make *sure* you have enough space.
char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);
// Need to free message at some point after you''re done with it.
Está intentando copiar una cadena en una dirección que está asignada estáticamente. Necesitas meterte en un búfer.
Específicamente:
...recorte...
destino
Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.
...recorte...
http://www.cplusplus.com/reference/clibrary/cstring/strcat.html
Hay un ejemplo aquí también.
Esta fue mi solucion
#include <stdlib.h>
#include <stdarg.h>
char *strconcat(int num_args, ...) {
int strsize = 0;
va_list ap;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++)
strsize += strlen(va_arg(ap, char*));
char *res = malloc(strsize+1);
strsize = 0;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++) {
char *s = va_arg(ap, char*);
strcpy(res+strsize, s);
strsize += strlen(s);
}
va_end(ap);
res[strsize] = ''/0'';
return res;
}
pero necesitas especificar cuántas cadenas vas a concatenar
char *str = strconcat(3, "testing ", "this ", "thing");
Evite usar strcat
en el código C. La forma más limpia y, lo que es más importante, la más segura es usar snprintf
:
char buf[256];
snprintf(buf, sizeof buf, "%s%s%s%s", str1, str2, str3, str4);
Algunos comentaristas plantearon el problema de que la cantidad de argumentos puede no coincidir con la cadena de formato y el código aún se compilará, pero la mayoría de los compiladores ya emiten una advertencia si este es el caso.
Intenta algo similar a esto:
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// Insert code here...
char firstname[100], secondname[100];
printf("Enter First Name: ");
fgets(firstname, 100, stdin);
printf("Enter Second Name: ");
fgets(secondname,100,stdin);
firstname[strlen(firstname)-1]= ''/0'';
printf("fullname is %s %s", firstname, secondname);
return 0;
}
La mejor manera de hacerlo sin tener un tamaño de búfer limitado es usando asprintf ()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
Las cadenas también se pueden concatenar en tiempo de compilación.
#define SCHEMA "test"
#define TABLE "data"
const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry = // include comments in a string
" SELECT * " // get all fields
" FROM " SCHEMA "." TABLE /* the table */
" WHERE x = 1 " /* the filter */
;
No te olvides de inicializar el búfer de salida. El primer argumento de strcat debe ser una cadena terminada en nulo con suficiente espacio adicional asignado para la cadena resultante:
char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string );
// null_terminated_string has less than 1023 chars
Puedes escribir tu propia función que hace lo mismo que strcat()
pero que no cambia nada:
#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
static char buffer[MAX_STRING_LENGTH];
strncpy(buffer,str1,MAX_STRING_LENGTH);
if(strlen(str1) < MAX_STRING_LENGTH){
strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
}
buffer[MAX_STRING_LENGTH - 1] = ''/0'';
return buffer;
}
int main(int argc,char *argv[]){
printf("%s",strcat_const("Hello ","world")); //Prints "Hello world"
return 0;
}
Si ambas cadenas juntas tienen más de 1000 caracteres, cortará la cadena a 1000 caracteres. Puede cambiar el valor de MAX_STRING_LENGTH
para que se adapte a sus necesidades.
Si tiene experiencia en C, notará que las cadenas son solo matrices de caracteres donde el último carácter es un carácter nulo.
Ahora eso es bastante incómodo ya que tienes que encontrar el último carácter para agregar algo. strcat
hará eso por ti.
Por lo tanto, strcat busca en el primer argumento un carácter nulo. Luego reemplazará esto con el contenido del segundo argumento (hasta que termine en un nulo).
Ahora vamos a revisar tu código:
message = strcat("TEXT " + var);
Aquí está agregando algo al puntero al texto "TEXTO" (el tipo de "TEXTO" es const char *. Un puntero).
Eso normalmente no funcionará. Además, la modificación de la matriz "TEXTO" no funcionará, ya que generalmente se coloca en un segmento constante.
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Eso podría funcionar mejor, excepto que nuevamente está intentando modificar textos estáticos. strcat no está asignando nueva memoria para el resultado.
Propondría hacer algo como esto en su lugar:
sprintf(message2, "TEXT %s TEXT %s", foo, bar);
Lea la documentación de sprintf
para comprobar sus opciones.
Y ahora un punto importante:
Asegúrese de que el búfer tenga suficiente espacio para contener el texto Y el carácter nulo. Hay un par de funciones que pueden ayudarlo, por ejemplo, strncat y versiones especiales de printf que le asignan el búfer. No garantizar que el tamaño del búfer provoque daños en la memoria y errores explotables de forma remota.
Suponiendo que tiene un char [tamaño_figurado] en lugar de un char *, puede usar una macro única y creativa para hacerlo todo de una vez con un orden <<cout<<like
("más bien% s el% s / n" inconexo, "que", "formato de estilo printf"). Si está trabajando con sistemas integrados, este método también le permitirá dejar de lado malloc y la gran familia de funciones *printf
como snprintf()
(Esto evita que Dietlibc se queje de * printf también)
#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ /
char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ /
const char *s, /
*a[] = { __VA_ARGS__,NULL}, /
**ss=a; /
while((s=*ss++)) /
while((*s)&&(++offset<(int)sizeof(buf))) /
*bp++=*s++; /
if (offset!=sizeof(buf))*bp=0; /
}while(0)
char buf[256];
int len=0;
strcpyALL(buf,len,
"The config file is in:/n/t",getenv("HOME"),"/.config/",argv[0],"/config.rc/n"
);
if (len<sizeof(buf))
write(1,buf,len); //outputs our message to stdout
else
write(2,"error/n",6);
//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don''t want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!/n");
if (len<sizeof(buf))
write(1,buf,len); //outputs both messages
else
write(2,"error/n",6);
- Nota 1, normalmente no usarías argv [0] de esta manera, solo un ejemplo
- En la Nota 2, puede usar cualquier función que genere un carácter *, incluidas funciones no estándar como itoa () para convertir enteros en tipos de cadena.
- Nota 3, si ya está usando printf en cualquier parte de su programa, no hay razón para no usar snprintf (), ya que el código compilado sería más grande (pero en línea y significativamente más rápido)
También malloc y realloc son útiles si no sabe de antemano cuántas cadenas se están concatenando.
#include <stdio.h>
#include <string.h>
void example(const char *header, const char **words, size_t num_words)
{
size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
char *message = (char*) malloc(message_len);
strncat(message, header, message_len);
for(int i = 0; i < num_words; ++i)
{
message_len += 1 + strlen(words[i]); /* 1 + for separator '';'' */
message = (char*) realloc(message, message_len);
strncat(strncat(message, ";", message_len), words[i], message_len);
}
puts(message);
free(message);
}
int main()
{
char input[100];
gets(input);
char str[101];
strcpy(str, " ");
strcat(str, input);
char *p = str;
while(*p) {
if(*p == '' '' && isalpha(*(p+1)) != 0)
printf("%c",*(p+1));
p++;
}
return 0;
}