Wie deklariere ich ein Array von Strings in C ++?

89

Ich versuche, alle Elemente eines statischen Arrays von Zeichenfolgen bestmöglich zu durchlaufen. Ich möchte in der Lage sein, es in einer Zeile zu deklarieren und Elemente einfach hinzuzufügen / zu entfernen, ohne die Nummer verfolgen zu müssen. Klingt wirklich einfach, nicht wahr?

Mögliche Nichtlösungen:

vector<string> v;
v.push_back("abc");
b.push_back("xyz");

for(int i = 0; i < v.size(); i++)
    cout << v[i] << endl;

Probleme - keine Möglichkeit, den Vektor in einer Zeile mit einer Liste von Zeichenfolgen zu erstellen

Mögliche Nichtlösung 2:

string list[] = {"abc", "xyz"};

Probleme - keine Möglichkeit, die Anzahl der Zeichenfolgen automatisch zu ermitteln (von denen ich weiß).

Es muss einen einfachen Weg geben, dies zu tun.

Naumcho
quelle
Die Boost-Zuweisungsbibliothek scheint genau das zu sein, wonach Sie suchen. Dies macht das Zuweisen von Konstanten zu Containern einfacher als je zuvor.
Craig H

Antworten:

108

C ++ 11 hat Initialisierungslisten hinzugefügt, um die folgende Syntax zu ermöglichen:

std::vector<std::string> v = {"Hello", "World"};

Die Unterstützung für diese C ++ 11-Funktion wurde in mindestens GCC 4.4 und nur in Visual Studio 2013 hinzugefügt .

Anthony Cramp
quelle
2018. Ich habe gerade C ++ gestartet und einige Untersuchungen zu flexiblen Arrays durchgeführt. Endete nur mit Vektoren ...
Robert Molina
37

Sie können a vector<string>aus einem statisch erstellten char*Array präzise initialisieren :

char* strarray[] = {"hey", "sup", "dogg"};
vector<string> strvector(strarray, strarray + 3);

Dadurch werden übrigens alle Zeichenfolgen kopiert, sodass Sie den doppelten Speicher verwenden. Sie können Will Deans Vorschlag verwenden, um die magische Nummer 3 hier durch Arraysize (str_array) zu ersetzen - obwohl ich mich erinnere, dass es einen Sonderfall gibt, in dem diese bestimmte Version von Arraysize möglicherweise etwas Schlechtes bewirkt (Entschuldigung, ich kann mich nicht sofort an die Details erinnern). . Aber es funktioniert sehr oft richtig.

Wenn Sie sich wirklich für das Ding mit einer Zeile interessieren, können Sie auch ein variadisches Makro definieren, sodass eine einzelne Zeile wie z DEFINE_STR_VEC(strvector, "hi", "there", "everyone");.

Tyler
quelle
strarrayVerstößt es nicht gegen die One-Definition-Regel, da es sich in einem Header befindet?
JWW
22

Probleme - keine Möglichkeit, die Anzahl der Zeichenfolgen automatisch zu ermitteln (von denen ich weiß).

Es gibt eine Standardmethode, bei der viele Leute (einschließlich MS) Makros definieren wie arraysize:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))
Will Dean
quelle
1
Alternativ könnte man so etwas verwenden: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (Inline-Schlüsselwort nicht erforderlich, aber zur Dokumentation der Absicht der Funktion verwendet. Ein moderner Compiler sollte theoretisch in der Lage sein, die gesamte Funktion zurückzugeben, glaube ich.
Justin Time - Reinstate Monica
1
Dies schlägt für Zeiger fehl. Das Zählen von Array-Elementen sollte in C ++ anders erfolgen.
JWW
8

Deklarieren Sie ein Array von Zeichenfolgen in C ++ wie folgt: char array_of_strings[][]

Zum Beispiel : char array_of_strings[200][8192];

enthält 200 Zeichenfolgen, wobei jede Zeichenfolge die Größe 8 KB oder 8192 Byte hat.

Verwenden Sie strcpy(line[i],tempBuffer); diese Option, um Daten in das Array von Zeichenfolgen einzufügen.


quelle
Zu Ihrer Information, char array_of_strings [] [] kann keine C ++ - Zeichenfolgen akzeptieren. Stellen Sie sicher, dass Sie zuerst in char * konvertieren. cplusplus.com/reference/string/string/c_str
Luqmaan
array_of_stringsVerstößt es nicht gegen die One-Definition-Regel, da es sich in einem Header befindet?
JWW
7

Eine Möglichkeit besteht darin, einen NULL-Zeiger als Flag-Wert zu verwenden:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}
Finsternis
quelle
Was bedeutet char ** eigentlich? Wäre es in Java eine Liste von Zeichenfolgen?
IAmGroot
1
@ Doomsknight: In diesem Fall ja. In der ersten Zeile definiere ich ein Array von char*. Im Speicher wird dies als 3 Zeiger dargestellt - einer zeigt auf "Hund", einer zeigt auf "Katze" und einer bleibt NULL. Ich kann einen Zeiger auf diesen ersten Zeiger nehmen und char**einen Zeiger auf den Zeiger auf char bekommen. Wenn ich das inkrementiere, bewege ich das Zeichen **, um auf das nächste Element in der Liste zu zeigen - einen Zeiger auf den Zeiger, der auf "cat" zeigt, dann inkrementiere ich erneut und erhalte einen Zeiger, der auf den NULL-Zeiger zeigt, und Ich weiß, dass ich fertig bin. (
Eclipse
4

Sie können die Funktionen beginund endaus der Boost-Bereichsbibliothek verwenden, um die Enden eines primitiven Arrays leicht zu finden. Im Gegensatz zur Makrolösung führt dies zu einem Kompilierungsfehler anstelle eines fehlerhaften Verhaltens, wenn Sie ihn versehentlich auf einen Zeiger anwenden.

const char* array[] = { "cat", "dog", "horse" };
vector<string> vec(begin(array), end(array));
Ross Smith
quelle
3

Sie können Will Deans Vorschlag [ #define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))] verwenden, um die magische Nummer 3 hier durch Arraysize (str_array) zu ersetzen - obwohl ich mich erinnere, dass es einen Sonderfall gibt, in dem diese bestimmte Version von Arraysize möglicherweise etwas Schlechtes bewirkt (Entschuldigung, ich kann mich nicht an die Details erinnern sofort). Aber es funktioniert sehr oft richtig.

Der Fall, in dem es nicht funktioniert, ist, wenn das "Array" wirklich nur ein Zeiger ist, kein tatsächliches Array. Aufgrund der Art und Weise, wie Arrays an Funktionen übergeben werden (in einen Zeiger auf das erste Element konvertiert), funktioniert es auch nicht über Funktionsaufrufe hinweg, selbst wenn die Signatur wie ein Array aussieht - some_function(string parameter[])ist es wirklich some_function(string *parameter).

Matthew Crumley
quelle
3

Hier ist ein Beispiel:

#include <iostream>
#include <string>
#include <vector>
#include <iterator>

int main() {
    const char* const list[] = {"zip", "zam", "bam"};
    const size_t len = sizeof(list) / sizeof(list[0]);

    for (size_t i = 0; i < len; ++i)
        std::cout << list[i] << "\n";

    const std::vector<string> v(list, list + len);
    std::copy(v.begin(), v.end(), std::ostream_iterator<string>(std::cout, "\n"));
}
Shadow2531
quelle
2

Anstelle dieses Makros könnte ich dieses vorschlagen:

template<typename T, int N>
inline size_t array_size(T(&)[N])
{
    return N;
}

#define ARRAY_SIZE(X)   (sizeof(array_size(X)) ? (sizeof(X) / sizeof((X)[0])) : -1)

1) Wir möchten ein Makro verwenden, um es zu einer Konstante für die Kompilierungszeit zu machen. Das Ergebnis des Funktionsaufrufs ist keine Kompilierungszeitkonstante.

2) Wir möchten jedoch kein Makro verwenden, da das Makro versehentlich für einen Zeiger verwendet werden könnte. Die Funktion kann nur für Arrays zur Kompilierungszeit verwendet werden.

Wir verwenden also die Definiertheit der Funktion, um das Makro "sicher" zu machen. Wenn die Funktion vorhanden ist (dh eine Größe ungleich Null hat), verwenden wir das Makro wie oben. Wenn die Funktion nicht existiert, geben wir einen schlechten Wert zurück.

DrPizza
quelle
2
#include <boost/foreach.hpp>

const char* list[] = {"abc", "xyz"};
BOOST_FOREACH(const char* str, list)
{
    cout << str << endl;
}

quelle
1
#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>

int main()
{
    const std::vector< std::string > v = boost::assign::list_of( "abc" )( "xyz" );
    std::copy(
        v.begin(),
        v.end(),
        std::ostream_iterator< std::string >( std::cout, "\n" ) );
}
Dominic.wig
quelle
1

Sie können ein Array von Zeichenfolgen wie direkt deklarieren string s[100];. Wenn Sie dann auf bestimmte Elemente zugreifen möchten, können Sie es direkt wie erhalten s[2][90]. Nehmen Sie für Iterationszwecke die Größe der Zeichenfolge mithilfe der s[i].size()Funktion.

Kajol Jain
quelle