Staram się iterować wszystkie elementy statycznej tablicy ciągów w najlepszy możliwy sposób. Chcę móc zadeklarować go w jednej linii i łatwo dodawać / usuwać z niego elementy bez konieczności śledzenia liczby. Brzmi naprawdę prosto, prawda?
Możliwe nierozwiązania:
vector<string> v;
v.push_back("abc");
b.push_back("xyz");
for(int i = 0; i < v.size(); i++)
cout << v[i] << endl;
Problemy - brak możliwości stworzenia wektora w jednej linii z listą łańcuchów
Możliwy brak rozwiązania 2:
string list[] = {"abc", "xyz"};
Problemy - nie ma możliwości automatycznego uzyskania liczby ciągów znaków (o której wiem).
Musi być na to łatwy sposób.
Odpowiedzi:
C ++ 11 dodał listy inicjalizacyjne, aby umożliwić następującą składnię:
std::vector<std::string> v = {"Hello", "World"};
Obsługa tej funkcji języka C ++ 11 została dodana w co najmniej GCC 4,4 i tylko w programie Visual Studio 2013 .
źródło
Możesz zwięźle zainicjować a
vector<string>
zchar*
tablicy utworzonej statycznie :char* strarray[] = {"hey", "sup", "dogg"}; vector<string> strvector(strarray, strarray + 3);
Nawiasem mówiąc, to kopiuje wszystkie ciągi, więc zużywasz dwukrotnie więcej pamięci. Możesz skorzystać z sugestii Willa Deana, aby zastąpić magiczną liczbę 3 tutaj arraysize (str_array) - chociaż pamiętam, że był jakiś specjalny przypadek, w którym ta konkretna wersja Arraysize może zrobić coś złego (przepraszam, nie pamiętam szczegółów od razu) . Ale bardzo często działa poprawnie.
Ponadto, jeśli naprawdę zależy Ci na jednej linii, możesz zdefiniować makro wariadyczne, tak aby pojedyncza linia
DEFINE_STR_VEC(strvector, "hi", "there", "everyone");
działała.źródło
strarray
znajduje się w nagłówku, czy nie naruszy to reguły jednej definicji?Istnieje na to standardowy sposób, w którym wiele osób (w tym MS) definiuje makra, takie jak
arraysize
:#define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))
źródło
template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; }
(Inline nie słowa kluczowego konieczne, ale używane w celu udokumentowania danej funkcji zamiar nowoczesny kompilator powinien teoretycznie być w stanie powrócić całą funkcję, wierzę..Zadeklaruj tablicę ciągów w C ++ w następujący sposób:
char array_of_strings[][]
Na przykład :
char array_of_strings[200][8192];
pomieści 200 ciągów, z których każdy ma rozmiar 8kb lub 8192 bajtów.
służy
strcpy(line[i],tempBuffer);
do umieszczania danych w tablicy ciągów.źródło
array_of_strings
znajduje się w nagłówku, czy nie naruszy to reguły jednej definicji?Jedną z możliwości jest użycie wskaźnika NULL jako wartości flagi:
const char *list[] = {"dog", "cat", NULL}; for (char **iList = list; *iList != NULL; ++iList) { cout << *iList; }
źródło
char*
. W pamięci są to 3 wskaźniki - jeden punkt na „psa”, jeden na „kota”, a drugi na NULL. Mogę wziąć wskaźnik do pierwszego wskaźnika i uzyskaćchar**
- wskaźnik do wskaźnika do znaku. Kiedy to zwiększam, przesuwam znak **, aby wskazywał na następny element na liście - wskaźnik do wskaźnika, który wskazuje na „kot”, następnie ponownie zwiększam wartość i otrzymuję wskaźnik wskazujący na wskaźnik NULL i Wiem, że skończyłem. (Możesz użyć funkcji
begin
iend
z biblioteki zakresów Boost, aby łatwo znaleźć końce pierwotnej tablicy, iw przeciwieństwie do rozwiązania makr, spowoduje to błąd kompilacji zamiast zepsutego zachowania, jeśli przypadkowo zastosujesz go do wskaźnika.const char* array[] = { "cat", "dog", "horse" }; vector<string> vec(begin(array), end(array));
źródło
Sytuacja, w której to nie działa, ma miejsce, gdy „tablica” jest tak naprawdę tylko wskaźnikiem, a nie rzeczywistą tablicą. Ponadto, ze względu na sposób, w jaki tablice są przekazywane do funkcji (konwertowane na wskaźnik do pierwszego elementu), nie działa między wywołaniami funkcji, nawet jeśli podpis wygląda jak tablica -
some_function(string parameter[])
tak naprawdęsome_function(string *parameter)
.źródło
Oto przykład:
#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")); }
źródło
Zamiast tego makra mógłbym zasugerować to:
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) Chcemy użyć makra, aby uczynić z niego stałą czasu kompilacji; wynik wywołania funkcji nie jest stałą czasu kompilacji.
2) Jednak nie chcemy używać makra, ponieważ mogłoby to zostać przypadkowo użyte na wskaźniku. Ta funkcja może być używana tylko w tablicach kompilowanych w czasie.
Dlatego używamy zdefiniowanej funkcji, aby uczynić makro „bezpiecznym”; jeśli funkcja istnieje (tj. ma niezerowy rozmiar), używamy makra jak powyżej. Jeśli funkcja nie istnieje, zwracamy złą wartość.
źródło
#include <boost/foreach.hpp> const char* list[] = {"abc", "xyz"}; BOOST_FOREACH(const char* str, list) { cout << str << endl; }
źródło
#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" ) ); }
źródło
Możesz bezpośrednio zadeklarować tablicę ciągów, taką jak
string s[100];
. Następnie, jeśli chcesz uzyskać dostęp do określonych elementów, możesz to uzyskać bezpośrednio jaks[2][90]
. Na potrzeby iteracji weź rozmiar łańcucha za pomocąs[i].size()
funkcji.źródło