const char * konkatenacja


116

Muszę połączyć dwa znaki const, takie jak te:

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

Jak mam się do tego zabrać?

Przekazano mi te char*pliki z biblioteki innej firmy z interfejsem C, więc nie mogę po prostu użyć std::stringzamiast tego.


6
Jestem zdezorientowany - pierwotny pytający napisał tag „c ++” - po czym ktoś inny go usunął. Jaki jest stan rzeczy w przypadku tego pytania? Czy kod C ++ jest dozwolony?
Johannes Schaub - litb

1
@Johannes: To lepsze pytanie xD.
Prasoon Saurav,

Zwróć również uwagę, że pierwotne pytanie NIE odnosiło się do C - usunąłem ten tag.

Zmieniłem znacznik C ++ na C, ponieważ OP zaakceptował odpowiedź, która używa tablic na stosie strcpyi strcatwywołań, pomyślałem, że zmiana tagów ma sens.
Gregory Pakosz

7
Dodano tagi C i C ++. Jak wyjaśnia OP w komentarzu, pisze kod w C ++, ale wywołuje bibliotekę, która używa interfejsu C. Pytanie dotyczy obu języków.
jalf

Odpowiedzi:


110

W twoim przykładzie jeden i dwa to wskaźniki znaków, wskazujące na stałe char. Nie możesz zmienić stałych char wskazywanych przez te wskaźniki. Więc coś takiego:

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

nie będzie działać. Zamiast tego powinieneś mieć oddzielną zmienną (tablicę znaków) do przechowywania wyniku. Coś takiego:

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.

7
co z wynikiem char *; wynik = calloc (strlen (jeden) + strlen (dwa) +1, sizeof (char)); a WTEDY strcpy + strcat?
luiscubal,

3
@luiscubal: Tak, to też by działało ... po prostu użyj rzutowania (char *), ponieważ calloc zwraca void *
codaddict

5
Problem z tą odpowiedzią to rozmiar tablicy zakodowanej na stałe. To naprawdę zły nawyk, zwłaszcza jeśli nie wiesz, jaki jest rozmiar „jeden” i „dwa”.
Paul Tomblin,

1
W pierwszym przykładzie strcpy(one,two);powinno być strcat(one,two);(nie to sprawia , że jest poprawne, jak słusznie zauważyłeś).
Alok Singhal,

1
co sprintf(dest,"%s%s",one,two)z kopią i zapomnieć?
mpen

81

Droga C:

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

Sposób C ++:

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

Sposób kompilacji:

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

const char* buf = concat(one, two);

31

Jeśli używasz C ++, dlaczego nie używasz std::stringzamiast ciągów w stylu C?

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

std::string three= one+two;

Jeśli chcesz przekazać ten ciąg do funkcji C, po prostu przekaż three.c_str()


7
Ponieważ używam biblioteki, który został zakodowany w C więc zwracają const char *
Anthoni Caldwell

1
@AnthoniCaldwell: Dzięki za śmiech. Nie mogłem z powodu presji w pracy.:
D

Wygląda na to, że czas na nową pracę? ...
Max

20

Używając std::string:

#include <string>

std::string result = std::string(one) + std::string(two);

10
Drugie jawne wywołanie konstruktora nie jest konieczne
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()

Zaktualizowano: zmieniono string total = string(one) + string(two); na string total( string(one) + two );ze względu na wydajność (unika konstrukcji ciągu drugiego i tymczasowej sumy ciągu)

// string total(move(move(string(one)) + two));  // even faster?

@iburidu czy zmierzyłeś to? A co z sytuacjami, w których bezpieczeństwo jest ważniejsze od wydajności? (Są to typowe sytuacje)
Sqeaky

3
@Sqeaky Nie ma absolutnie żadnych sytuacji, w których jest to bezpieczniejsze niż jakiekolwiek inne rozwiązanie, ale ZAWSZE jest wolniejsze niż rozwiązanie czasu kompilacji, wywołując zachowanie w czasie wykonywania, a także prawie na pewno wywołując przydział pamięci.
Alice

8

Jeszcze jeden przykład:

// 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;

Ale jeśli wyraźnie nie chcesz lub nie możesz używać standardowej biblioteki C ++, używanie std::stringjest prawdopodobnie bezpieczniejsze.


1
Jeśli OP nie może używać C ++, nie może używać new. A jeśli może go użyć, powinien użyć std::string, jak mówisz.
Alok Singhal

5

Wygląda na to, że używasz C ++ z biblioteką C i dlatego musisz popracować const char *.

Proponuję zapakować je const char *w std::string:

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

5

Przede wszystkim musisz stworzyć dynamiczną przestrzeń pamięci. Następnie możesz po prostu włożyć do niego dwie struny. Możesz też użyć klasy „string” w języku c ++. Stara szkoła C:

  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);

Nowy sposób C ++

  std::string three(one);
  three += two;

dlaczego potrzebujesz pamięci dynamicznej?
Luca Matteis,

4
-1 dla mnie, najpierw ze sposobem C musisz użyć malloc i za darmo. Wtedy nawet jeśli zrobisz nowy, to powinien być usunięty [], a nie usuwany.
Naveen,

Biblioteka, której używam, jest zakodowana w C, a nie w C ++, więc wszystkie funkcje zwracają const char *, a nie ciąg.
Anthoni Caldwell,

1
@Naveen, w tagu jest napisane „C ++”. Jeśli nie możesz użyć new i delete, to nie powinien był używać tagu C ++.
Paul Tomblin,

5

Jeśli nie znasz rozmiaru sznurków, możesz zrobić coś takiego:

#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;
}

3

Możesz użyć strstream. Formalnie jest przestarzałe, ale wydaje mi się, że nadal jest świetnym narzędziem, jeśli potrzebujesz pracować z ciągami C.

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

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

Spowoduje to zapisanie, onea następnie twodo strumienia i dołączenie zakończenia \0using std::ends. W przypadku, gdy oba łańcuchy mogłyby zakończyć się zapisaniem dokładnie 99znaków - więc nie pozostałaby spacja \0- wpisujemy jeden ręcznie na ostatniej pozycji.


Wycofanie nie powinno mieć większego znaczenia. Nawet jeśli zostanie usunięty z przyszłej wersji standardu, ponowne zaimplementowanie we własnej przestrzeni nazw nie wymaga wiele pracy.
Steve Jessop,

@Steve, w rzeczy samej :) I napisanie własnego streambufwyjścia kierującego do bufora znaków używanego z ostreamnie jest zbyt trudne.
Johannes Schaub - litb

3
const char* one = "one";
const char* two = "two";
char result[40];
sprintf(result, "%s%s", one, two);

0

Łączenie dwóch stałych wskaźników znaków bez użycia polecenia strcpy w dynamicznej alokacji pamięci:

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;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.