const char * Verkettung


116

Ich muss zwei konstante Zeichen wie diese verketten:

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

Wie könnte ich das machen?

Ich habe diese char*s von einer Drittanbieter-Bibliothek mit einer C-Schnittstelle erhalten, sodass ich sie nicht einfach verwenden kann std::string.


6
Ich bin verwirrt - der ursprüngliche Fragesteller hat das "c ++" - Tag geschrieben - dann hat es jemand anderes entfernt. Wie ist der Stand der Dinge für diese Frage? Ist C ++ - Code erlaubt?
Johannes Schaub - litb

1
@ Johannes: Das ist eine bessere Frage xD.
Prasoon Saurav

Beachten Sie auch, dass sich die ursprüngliche Frage NICHT auf C bezog - ich habe dieses Tag entfernt.

Ich habe das C ++ - Tag auf C umgestellt, weil das OP eine Antwort akzeptiert hat, die Arrays auf dem Stapel verwendet, strcpyund strcatAufrufe. Ich dachte, dass es sinnvoll ist, die Tags zu ändern.
Gregory Pakosz

7
C- und C ++ - Tags hinzugefügt . Wie das OP in einem Kommentar erklärt, schreibt er C ++ - Code, ruft jedoch eine Bibliothek auf, die eine C-Schnittstelle verwendet. Die Frage ist in beiden Sprachen relevant.
Jalf

Antworten:


110

In Ihrem Beispiel sind eins und zwei Zeichenzeiger, die auf Zeichenkonstanten zeigen. Sie können die Zeichenkonstanten, auf die diese Zeiger zeigen, nicht ändern. Also so etwas wie:

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

wird nicht funktionieren. Stattdessen sollten Sie eine separate Variable (char-Array) haben, um das Ergebnis zu speichern. Etwas wie das:

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
was ist mit char * result; Ergebnis = calloc (strlen (eins) + strlen (zwei) +1, sizeof (char)); und DANN das strcpy + strcat?
luiscubal

3
@luiscubal: Ja, das würde auch funktionieren ... benutze einfach eine (char *) Besetzung, da calloc void *
zurückgibt

5
Das Problem bei dieser Antwort ist die fest codierte Arraygröße. Das ist eine wirklich schlechte Angewohnheit, besonders wenn Sie nicht wissen, wie groß "eins" und "zwei" sind.
Paul Tomblin

1
Im ersten Beispiel strcpy(one,two);sollte sein strcat(one,two);(nicht das , was es richtig macht, wie Sie richtig hervorheben).
Alok Singhal

1
Was ist mit sprintf(dest,"%s%s",one,two)und vergessen Sie die Kopie?
Mpen

81

Der C-Weg:

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

Der C ++ Weg:

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

Die Art der Kompilierung:

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

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

31

Wenn Sie C ++ verwenden, warum verwenden Sie keine std::stringZeichenfolgen im C-Stil?

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

std::string three= one+two;

Wenn Sie diesen String an eine C-Funktion übergeben müssen, übergeben Sie ihn einfach three.c_str()


7
Da ich eine Bibliothek verwende, die in C codiert wurde, geben die Funktionen const char * zurück
Anthoni Caldwell

1
@AnthoniCaldwell: Danke für das Lachen. Ich konnte nicht wegen Arbeitsdruck.:D
Rick2047

Klingt nach Zeit für einen neuen Job? ...
Max

20

Verwenden von std::string:

#include <string>

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

10
Der zweite explizite Konstruktoraufruf ist nicht erforderlich
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()

Aktualisiert: aus Leistungsgründen geändert string total = string(one) + string(two); in string total( string(one) + two );(vermeidet die Erstellung von Zeichenfolge zwei und temporäre Zeichenfolgen insgesamt)

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

@iburidu hast du es gemessen? Was ist mit Situationen, in denen Sicherheit die Leistung übertrifft? (Sie sind häufige Situationen)
Sqeaky

3
@Sqeaky Es gibt absolut keine Situationen, in denen dies sicherer als jede andere Lösung ist, aber es ist IMMER langsamer als eine Lösung zur Kompilierungszeit, indem das Laufzeitverhalten sowie mit ziemlicher Sicherheit die Speicherzuweisung aufgerufen werden.
Alice

8

Noch ein Beispiel:

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

Aber wenn Sie die C ++ - Standardbibliothek nicht ausdrücklich wollen oder nicht verwenden können, ist die Verwendung std::stringwahrscheinlich sicherer.


1
Wenn das OP C ++ nicht verwenden kann, kann er es nicht verwenden new. Und wenn er es benutzen kann, sollte er es benutzen std::string, wie Sie sagen.
Alok Singhal

5

Es scheint, als würden Sie C ++ mit einer C-Bibliothek verwenden und müssen daher damit arbeiten const char *.

Ich schlage vor, diese zu verpacken const char *in std::string:

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

5

Zunächst müssen Sie einen dynamischen Speicherplatz erstellen. Dann können Sie einfach die beiden Zeichenfolgen einfügen. Oder Sie können die c ++ - Klasse "string" verwenden. Der C-Weg der alten Schule:

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

Neuer C ++ Weg

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

Warum brauchen Sie dynamischen Speicher?
Luca Matteis

4
-1 für mich, zuerst mit dem C-Weg müssen Sie malloc und kostenlos verwenden. Selbst wenn Sie etwas Neues tun, sollte es delete [] und nicht delete sein.
Naveen

Die von mir verwendete Bibliothek ist in C und nicht in C ++ codiert, sodass alle Funktionen const char * not string zurückgeben.
Anthoni Caldwell

1
@Naveen, das Tag sagte "C ++". Wenn Sie new und delete nicht verwenden können, hätte er das C ++ - Tag nicht verwenden sollen.
Paul Tomblin

5

Wenn Sie die Größe der Zeichenfolgen nicht kennen, können Sie Folgendes tun:

#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

Sie können verwenden strstream. Es ist formal veraltet, aber es ist immer noch ein großartiges Werkzeug, wenn Sie mit C-Strings arbeiten müssen, denke ich.

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

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

Dies schreibt oneund dann twoin den Stream und fügt eine Beendigung \0mit hinzu std::ends. Für den Fall, dass beide Zeichenfolgen genau 99Zeichen schreiben könnten - so dass kein Platz mehr zum Schreiben übrig bleibt \0- schreiben wir eines manuell an die letzte Position.


Abwertung sollte nicht zu viel ausmachen. Selbst wenn es aus einer zukünftigen Version des Standards entfernt wird, ist es nicht so viel Arbeit, es in Ihrem eigenen Namespace erneut zu implementieren.
Steve Jessop

@Steve, in der Tat :) Und streambufes ostreamist auch nicht allzu schwierig , eine eigene Direktionsausgabe in einen Zeichenpuffer zu schreiben, der mit verwendet wird.
Johannes Schaub - litb

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

0

Verbinden von zwei konstanten Zeichenzeigern ohne Verwendung des Befehls strcpy bei der dynamischen Speicherzuweisung:

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;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.