const char * concatenación

116

Necesito concatenar dos caracteres constantes como estos:

const char *one = "Hello ";
const char *two = "World";

¿Cómo podría hacer eso?

Recibí estos char*mensajes de una biblioteca de terceros con una interfaz C, por lo que no puedo usarlos simplemente std::string.

Anthoni Caldwell
fuente
6
Estoy confundido - el interrogador original escribió la etiqueta "c ++" - luego alguien más la eliminó. ¿Cuál es la situación de esta pregunta? ¿Se permite el código C ++?
Johannes Schaub - litb
1
@Johannes: Esa es una mejor pregunta xD.
Prasoon Saurav
También tenga en cuenta que la pregunta original NO se refería a C: eliminé esa etiqueta.
Cambié la etiqueta C ++ a C porque el OP aceptó una respuesta que usa matrices en la pila strcpyy strcatllamadas, pensé que tenía sentido cambiar las etiquetas.
Gregory Pakosz
7
Se agregaron etiquetas C y C ++. Como explica el OP en un comentario, está escribiendo código C ++, pero llamando a una biblioteca que usa una interfaz C. La pregunta es relevante en ambos idiomas.
jalf

Respuestas:

110

En su ejemplo, uno y dos son punteros char, apuntando a constantes char. No puede cambiar las constantes de caracteres a las que apuntan estos punteros. Así que algo como:

strcat(one,two); // append string two to string one.

no trabajará. En su lugar, debe tener una variable separada (matriz de caracteres) para contener el resultado. Algo como esto:

char result[100];   // array to hold the result.

strcpy(result,one); // copy string one into the result.
strcat(result,two); // append string two to the result.
codaddict
fuente
7
¿qué pasa con char * result; resultado = calloc (strlen (uno) + strlen (dos) +1, sizeof (char)); y LUEGO el strcpy + strcat?
luiscubal
3
@luiscubal: Sí, eso también funcionaría ... solo use un (char *) cast, ya que calloc devuelve void *
codaddict
5
El problema con esta respuesta es el tamaño de la matriz codificada de forma rígida. Es un hábito realmente malo, especialmente si no sabes qué tamaño son "uno" y "dos".
Paul Tomblin
1
En el primer ejemplo, strcpy(one,two);debería ser strcat(one,two);(no es que eso lo haga correcto, como señala correctamente).
Alok Singhal
1
¿Qué tal sprintf(dest,"%s%s",one,two)y olvidas la copia?
mpen
81

La forma C:

char buf[100];
strcpy(buf, one);
strcat(buf, two);

La forma C ++:

std::string buf(one);
buf.append(two);

La forma en tiempo de compilación:

#define one "hello "
#define two "world"
#define concat(first, second) first second

const char* buf = concat(one, two);
Idan K
fuente
31

Si está usando C ++, ¿por qué no usa en std::stringlugar de cadenas de estilo C?

std::string one="Hello";
std::string two="World";

std::string three= one+two;

Si necesita pasar esta cadena a una función C, simplemente pase three.c_str()

Prasoon Saurav
fuente
7
Porque estoy usando una biblioteca que fue codificada en C, por lo que las funciones devuelven const char *
Anthoni Caldwell
1
@AnthoniCaldwell: Gracias por la risa. No pude debido a la presión del trabajo
.: D
¿Parece que es hora de un nuevo trabajo? ...
Max
20

Usando std::string:

#include <string>

std::string result = std::string(one) + std::string(two);
Gregory Pakosz
fuente
10
La segunda llamada explícita al constructor no es necesaria
sellibitze
17
const char *one = "Hello ";
const char *two = "World";

string total( string(one) + two );

// to use the concatenation as const char*, use:
total.c_str()

Actualizado: cambiado string total = string(one) + string(two); a string total( string(one) + two );por razones de rendimiento (evita la construcción de la cadena dos y la cadena temporal total)

// string total(move(move(string(one)) + two));  // even faster?
Pedro Reis
fuente
@iburidu ¿lo has medido? ¿Qué pasa con las situaciones en las que la seguridad triunfa sobre el rendimiento? (Son situaciones comunes)
Sqeaky
3
@Sqeaky No hay absolutamente ninguna situación en la que esto sea más seguro que cualquier otra solución, pero SIEMPRE es más lento que una solución en tiempo de compilación, ya que invoca el comportamiento en tiempo de ejecución y es casi seguro que invoca la asignación de memoria.
Alice
8

Un ejemplo más:

// calculate the required buffer size (also accounting for the null terminator):
int bufferSize = strlen(one) + strlen(two) + 1;

// allocate enough memory for the concatenated string:
char* concatString = new char[ bufferSize ];

// copy strings one and two over to the new buffer:
strcpy( concatString, one );
strcat( concatString, two );

...

// delete buffer:
delete[] concatString;

Pero a menos que específicamente no desee o no pueda usar la biblioteca estándar de C ++, std::stringprobablemente usar sea ​​más seguro.

stakx - ya no contribuye
fuente
1
Si el OP no puede usar C ++, no puede usar new. Y si puede usarlo, debería usarlo std::string, como usted dice.
Alok Singhal
5

Parece que estás usando C ++ con una biblioteca C y, por lo tanto, necesitas trabajar con const char *.

Sugiero envolverlos const char *en std::string:

const char *a = "hello "; 
const char *b = "world"; 
std::string c = a; 
std::string d = b; 
cout << c + d;
Luca Matteis
fuente
5

En primer lugar, debe crear un espacio de memoria dinámico. Entonces puedes simplemente insertar las dos cadenas en él. O puede utilizar la clase "string" de c ++. La forma C de la vieja escuela:

  char* catString = malloc(strlen(one)+strlen(two)+1);
  strcpy(catString, one);
  strcat(catString, two);
  // use the string then delete it when you're done.
  free(catString);

Nueva forma de C ++

  std::string three(one);
  three += two;
Paul Tomblin
fuente
¿Por qué necesitas memoria dinámica?
Luca Matteis
4
-1 para mí, primero con C-way necesitas usar malloc y free. Entonces, incluso si lo hace nuevo, debe eliminar [] y no eliminar.
Naveen
La biblioteca que estoy usando está codificada en C, no en C ++, por lo que todas las funciones devuelven const char * not string.
Anthoni Caldwell
1
@Naveen, la etiqueta decía "C ++". Si no puede usar new y delete, entonces no debería haber usado la etiqueta C ++.
Paul Tomblin
5

Si no conoce el tamaño de las cadenas, puede hacer algo como esto:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(){
    const char* q1 = "First String";
    const char* q2 = " Second String";

    char * qq = (char*) malloc((strlen(q1)+ strlen(q2))*sizeof(char));
    strcpy(qq,q1);
    strcat(qq,q2);

    printf("%s\n",qq);

    return 0;
}
Iraklis Moutidis
fuente
3

Puede utilizar strstream. Está en desuso formalmente, pero creo que sigue siendo una gran herramienta si necesitas trabajar con cadenas C.

char result[100]; // max size 100
std::ostrstream s(result, sizeof result - 1);

s << one << two << std::ends;
result[99] = '\0';

Esto escribirá oney luego twoen la secuencia, y agregará una terminación \0using std::ends. En caso de que ambas cadenas terminen escribiendo exactamente 99caracteres, por lo que no quedaría espacio para escribir \0, escribimos una manualmente en la última posición.

Johannes Schaub - litb
fuente
La depreciación no debería importar demasiado. Incluso si se elimina de una versión futura del estándar, no es mucho trabajo volver a implementarlo en su propio espacio de nombres.
Steve Jessop
@Steve, de hecho :) Y escribir su propia streambufsalida de dirección en un búfer de caracteres utilizado con ostreamtampoco es demasiado difícil.
Johannes Schaub - litb
3
const char* one = "one";
const char* two = "two";
char result[40];
sprintf(result, "%s%s", one, two);
Jagannath
fuente
0

Conectando dos punteros de caracteres constantes sin usar el comando strcpy en la asignación dinámica de memoria:

const char* one = "Hello ";
const char* two = "World!";

char* three = new char[strlen(one) + strlen(two) + 1] {'\0'};

strcat_s(three, strlen(one) + 1, one);
strcat_s(three, strlen(one) + strlen(two) + 1, two);

cout << three << endl;

delete[] three;
three = nullptr;
Edin Jašarević
fuente