C ++ 'da bir dizi dizisi nasıl bildirilir?


90

Statik dizeler dizisinin tüm öğelerini mümkün olan en iyi şekilde yinelemeye çalışıyorum. Numarayı takip etmek zorunda kalmadan tek satırda ilan edebilmek ve kolayca eleman ekleyip çıkarabilmek istiyorum. Kulağa çok basit geliyor, değil mi?

Olası çözüm olmayanlar:

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

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

Sorunlar - vektörü dizeler listesiyle tek satırda oluşturmanın yolu yok

Olası çözüm olmayan 2:

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

Sorunlar - dizelerin sayısını otomatik olarak almanın bir yolu yok (bildiğim kadarıyla).

Bunu yapmanın kolay bir yolu olmalı.


Boost atama kütüphane aradığınız tam olarak ne gibi görünüyor. Sabitleri kapsayıcılara atamayı her zamankinden daha kolay hale getirir.
Craig H

Yanıtlar:


108

C ++ 11, aşağıdaki sözdizimine izin vermek için başlatma listeleri ekledi:

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

Bu C ++ 11 özelliği için destek, en az GCC 4.4'te ve yalnızca Visual Studio 2013'te eklenmiştir .


2018. C ++ 'ı yeni başlattım ve esnek dizilerle ilgili epeyce araştırma yaptım. Sadece vektörleri kullanarak sona erdi ...
Robert Molina

37

vector<string>Statik olarak oluşturulmuş bir char*diziden kısaca bir başlatabilirsiniz :

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

Bu arada bu, tüm dizeleri kopyalar, böylece hafızanın iki katı kullanırsınız. Will Dean'ın önerisini burada sihirli sayı 3'ü arraysize (str_array) ile değiştirmek için kullanabilirsiniz - ancak arraysize'ın belirli bir sürümünün Something Badthing'ı yapabileceği bazı özel durumlar olduğunu hatırlıyorum (üzgünüm ayrıntıları hemen hatırlayamıyorum) . Ancak çoğu zaman doğru şekilde çalışır.

Ayrıca, tek satırlık şey hakkında gerçekten hevesliyseniz, değişken bir makro tanımlayabilirsiniz, böylece tek bir satır DEFINE_STR_VEC(strvector, "hi", "there", "everyone");çalışır.


Yana strarraybir başlık olduğunu, bu bir tanım kuralını ihlal değil mi?
jww

22

Sorunlar - dizelerin sayısını otomatik olarak almanın bir yolu yok (bildiğim kadarıyla).

Bunu yapmanın, birçok insanın (MS dahil) aşağıdakiler gibi makroları tanımladığı bataklık standardı bir yolu vardır arraysize:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))

1
Alternatif olarak, şöyle bir şey kullanılabilir: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (Satır içi anahtar kelime gerekli değildir, ancak işlevin amacını belgelemek için kullanılır. Modern bir derleyicinin teorik olarak tüm işlevi döndürebilmesi gerektiğine inanıyorum.
Justin Time - Monica'yı yeniden

1
Bu, işaretçiler için başarısız. Dizi elemanlarının sayımı C ++ 'da farklı bir şekilde yapılmalıdır.
jww

8

C ++ 'da bir dizi dizisi şu şekilde bildirin: char array_of_strings[][]

Örneğin : char array_of_strings[200][8192];

her dizge boyutu 8kb veya 8192 bayt olan 200 dizge tutacaktır.

strcpy(line[i],tempBuffer); dize dizisine veri koymak için kullanın .


Bilginize, char array_of_strings [] [] C ++ dizelerini kabul edemez, önce char * 'a dönüştürdüğünüzden emin olun. cplusplus.com/reference/string/string/c_str
Luqmaan

Yana array_of_stringsbir başlık olduğunu, bu bir tanım kuralını ihlal değil mi?
jww

7

Olasılıklardan biri, bayrak değeri olarak bir NULL gösterici kullanmaktır:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}

Char ** aslında ne anlama geliyor? Java'da dizelerin listesi olur mu?
IAmGroot

1
@Doomsknight: Bu durumda, evet. İlk satırda bir dizi tanımlıyorum char*. Hafızada, bu 3 işaretçi olarak düzenlenir - biri "köpek" i gösterir, biri "kedi" i gösterir ve diğeri NULL kalır. O ilk işaretçiye char**bir işaretçi alıp bir - işaretçi ile karaktere bir işaretçi alabilirim . Bunu artırdığımda, karakter ** 'i listedeki bir sonraki öğeye - işaretçi "kedi" yi gösteren bir işaretçi olacak şekilde hareket ettiriyorum, sonra tekrar artırıyorum ve NULL işaretçisini gösteren bir işaretçi alıyorum ve Bitirdiğimi biliyorum. (
Tutulma

4

Kullanabilirsiniz beginendİlkel bir dizinin uçlarını kolayca bulmak için Boost aralık kitaplığındaki ve işlevlerini ve makro çözümünün aksine, yanlışlıkla bir işaretçiye uygularsanız bu, bozuk davranış yerine bir derleme hatası verir.

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

3

Will Dean'in önerisini [ #define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))] burada sihirli sayı 3'ü arraysize (str_array) ile değiştirmek için kullanabilirsiniz - ancak arraysize'ın belirli bir sürümünün Something Badthing (kötü bir şey) yapabileceği bazı özel durumlar olduğunu hatırlıyorum (üzgünüm ayrıntıları hatırlayamıyorum hemen). Ancak çoğu zaman doğru şekilde çalışır.

Çalışmadığı durum, "dizi" nin gerçek bir dizi değil, gerçekten sadece bir işaretçi olduğu durumdur. Ayrıca, dizilerin işlevlere aktarılma şekli nedeniyle (ilk öğeye bir göstericiye dönüştürülür), imza bir dizi gibi görünse bile işlev çağrılarında çalışmaz - some_function(string parameter[])gerçekten some_function(string *parameter).


3

İşte bir örnek:

#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"));
}

2

Bu makro yerine şunu önerebilir miyim:

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) Derleme zamanı sabiti yapmak için bir makro kullanmak istiyoruz; işlev çağrısının sonucu bir derleme zamanı sabiti değildir.

2) Ancak, makroyu kullanmak istemiyoruz çünkü makro yanlışlıkla bir işaretçi üzerinde kullanılabilir. İşlev yalnızca derleme zamanı dizilerinde kullanılabilir.

Bu nedenle, makroyu "güvenli" hale getirmek için fonksiyonun tanımlılığını kullanırız; fonksiyon varsa (yani sıfır olmayan boyuta sahipse), o zaman makroyu yukarıdaki gibi kullanırız. İşlev yoksa, kötü bir değer döndürürüz.


2
#include <boost/foreach.hpp>

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

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

1

Doğrudan gibi bir dizi tanımlayabilirsiniz string s[100];. Daha sonra belirli öğelere erişmek istiyorsanız, bunu doğrudan beğenebilirsiniz s[2][90]. Yineleme amacıyla, s[i].size()işlevi kullanarak dizenin boyutunu alın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.