webentwicklung-frage-antwort-db.com.de

So kopieren Sie einen String in ein Char-Array in C++, ohne den Puffer zu überschreiten

Ich möchte einen String in ein Char-Array kopieren und den Puffer nicht überfahren.

Wenn ich also ein Char-Array der Größe 5 habe, möchte ich maximal 5 Bytes aus einem String in ihn kopieren.

was ist der Code dafür?

20
neuromancer

Vor allem ist strncpy fast sicher nicht was Sie wollen. strncpy wurde für einen bestimmten Zweck entwickelt. Sie befindet sich fast ausschließlich in der Standardbibliothek, weil sie bereits existiert, nicht weil sie allgemein nützlich ist.

Der einfachste Weg, um das zu tun, was Sie wollen, ist Folgendes:

sprintf(buffer, "%.4s", your_string.c_str());

Im Gegensatz zu strncpy garantiert dies, dass das Ergebnis NUL beendet wird, füllt jedoch keine zusätzlichen Daten in das Ziel ein, wenn die Quelle kürzer als die angegebene ist (obwohl letzteres kein Problem ist, wenn die Ziellänge 5 ist).

19
Jerry Coffin

Dies ist genau das, was die Kopierfunktion von std::string tut.

#include <string>
#include <iostream>

int main()
{

    char test[5];
    std::string str( "Hello, world" );

    str.copy(test, 5);

    std::cout.write(test, 5);
    std::cout.put('\n');

    return 0;
}

Wenn Sie eine Nullkündigung benötigen, sollten Sie Folgendes tun:

str.copy(test, 4);
test[4] = '\0';
37
CB Bailey

Funktion verwenden strlcpydefekter Link und Material auf der Zielseite nicht gefunden Wenn Ihre Implementierung eine enthält (die Funktion befindet sich nicht in der Standard-C-Bibliothek), wird sie doch weithin als De-facto-Standardname für eine "sichere" Kopierfunktion mit begrenzter Länge für nullterminierte Zeichenfolgen akzeptiert.

Wenn Ihre Implementierung keine strlcpy-Funktion bietet, implementieren Sie eine selbst. Zum Beispiel könnte so etwas für Sie funktionieren

char *my_strlcpy(char *dst, const char *src, size_t n)
{
  assert(dst != NULL && src != NULL);

  if (n > 0)
  {
    char *pd;
    const char *ps;

    for (--n, pd = dst, ps = src; n > 0 && *ps != '\0'; --n, ++pd, ++ps)
      *pd = *ps;

    *pd = '\0';
  }

  return dst;
}

(Tatsächlich hat die De-facto-Annahme strlcpy die Rückgabe von size_t zur Folge, sodass Sie die akzeptierte Spezifikation lieber als die oben beschriebene implementieren möchten).

Hüten Sie sich vor den Antworten, die die Verwendung von strncpy für diesen Zweck empfehlen. strncpy ist keine sichere Funktion zum Kopieren von Zeichenketten mit begrenzter Länge und sollte nicht für diesen Zweck verwendet werden. Während Sie strncpy zwingen können, zu diesem Zweck "zu arbeiten", ist es immer noch so, als würden Sie Holzschrauben mit einem Hammer antreiben.

7
AnT

Einige libc-Versionen von Nice bieten einen nicht standardmäßigen, aber guten Ersatz für strcpy(3)/strncpy(3) - strlcpy(3) .

Wenn nicht, ist der Quellcode hier aus dem OpenBSD - Repository frei verfügbar.

3

Update: Ich dachte, ich würde versuchen, einige der Antworten zusammenzubinden. Antworten, die mich überzeugt haben, dass meine eigene originelle Antwort auf den Knie-Ruck nur schlecht war. 

Erstens, wie AndreyT in den Kommentaren zu dieser Frage feststellte, sind Kürzungsverfahren (snprintf, strlcpy und strncpy) oft keine gute Lösung. Es ist oft besser, die Größe der Zeichenfolge string.size() anhand der Pufferlänge zu überprüfen und einen Fehler zurückzugeben oder zu werfen oder die Größe des Puffers zu ändern.

Wenn das Abschneiden in Ihrer Situation in Ordnung ist, ist IMHO, strlcpy die beste Lösung, da es sich um die schnellste/am wenigsten Overhead-Methode handelt, die eine Nullbeendigung gewährleistet. Leider ist es nicht in vielen/allen Standarddistributionen und daher nicht portierbar. Wenn Sie viele davon machen, lohnt es sich vielleicht, Ihre eigene Implementierung bereitzustellen, AndreyT gab ein Beispiel . Es läuft in O (Ergebnislänge). Die Referenzspezifikation gibt auch die Anzahl der kopierten Bytes zurück, die bei der Erkennung helfen kann, ob die Quelle abgeschnitten wurde.

Andere gute Lösungen sind sprintf und snprintf . Sie sind Standard und somit portabel und bieten ein sicheres Ergebnis, das mit Null beendet wird. Sie haben mehr Aufwand als strlcpy (analysieren den Format-String-Bezeichner und die Liste der Variablenargumente), aber wenn Sie nicht viele davon ausführen, werden Sie den Unterschied wahrscheinlich nicht bemerken. Es läuft auch in O (Ergebnislänge). snprintf ist immer sicher und dieser Sprintf kann überlaufen, wenn der Formatbezeichner falsch angezeigt wird (wie bereits erwähnt, sollte der Formatstring "%.<N>s" und nicht "%<N>s" sein). Diese Methoden geben auch die Anzahl der kopierten Bytes zurück.

Eine Sonderfalllösung ist strncpy . Es läuft in O (Pufferlänge), da der Rest des Puffers auf Null gesetzt wird, wenn er das Ende des Befehls erreicht. Nur nützlich, wenn Sie das Ende des Puffers auf Null setzen müssen oder sicher sind, dass die Längen der Ziel- und Quellstrings gleich sind. Beachten Sie auch, dass es nicht sicher ist, dass die Zeichenfolge nicht unbedingt null ist. Wenn die Quelle abgeschnitten wird, wird null nicht angehängt. Rufen Sie daher in Reihenfolge mit einer Nullzuweisung auf, um die Beendigung der Null zu gewährleisten: strncpy(buffer, str.c_str(), BUFFER_LAST); buffer[BUFFER_LAST] = '\0';

3
academicRobot
void stringChange(string var){

    char strArray[100];
    strcpy(strArray, var.c_str()); 

}

Ich denke, das sollte funktionieren. Es wird die Formularzeichenfolge in ein Char-Array kopieren.

2
Sunil
std::string str = "Your string";
char buffer[5];
strncpy(buffer, str.c_str(), sizeof(buffer)); 
buffer[sizeof(buffer)-1] = '\0';

Die letzte Zeile ist erforderlich, da strncpy nicht garantiert wird, dass NUL die Zeichenfolge beendet (es wurde gestern über die Motivation diskutiert).

Wenn Sie breite Zeichenfolgen verwenden, würden Sie anstelle von sizeof(buffer)sizeof(buffer)/sizeof(*buffer) oder noch besser ein Makro wie verwenden

#define ARRSIZE(arr)    (sizeof(arr)/sizeof(*(arr)))
/* ... */
buffer[ARRSIZE(buffer)-1]='\0';
0
Matteo Italia

ich denke, snprintf () ist sehr sicher und am einfachsten

snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );

nullzeichen wird automatisch angehängt :)

0
Dark Corp
char mystring[101]; // a 100 character string plus terminator
char *any_input;
any_input = "Example";
iterate = 0;
while ( any_input[iterate] != '\0' && iterate < 100) {
    mystring[iterate] = any_input[iterate];
    iterate++;
}
mystring[iterate] = '\0';

Dies ist das grundlegende effiziente Design. 

0
user922475
std::string my_string("something");
char* my_char_array = new char[5];
strncpy(my_char_array, my_string.c_str(), 4);
my_char_array[4] = '\0'; // my_char_array contains "some"

Mit strncpy können Sie höchstens n Zeichen von der Quelle zum Ziel kopieren. Beachten Sie jedoch, dass, wenn die Quellzeichenfolge höchstens n Zeichen lang ist, das Ziel nicht mit null beendet wird. Sie müssen das abschließende Nullzeichen selbst eingeben.

Ein Char-Array mit einer Länge von 5 kann höchstens eine Zeichenfolge von 4 Zeichen enthalten, da das 5. Zeichen das abschließende Nullzeichen sein muss. Daher ist im obigen Code n = 4.

0
Péter Török