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?
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).
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';
Funktion verwenden defekter 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.strlcpy
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.
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.
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';
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.
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';
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 :)
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.
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.