Як оголосити масив рядків у C ++?


89

Я намагаюся найкращим чином переглядати всі елементи статичного масиву рядків. Я хочу мати можливість оголосити це в одному рядку та легко додавати / видаляти елементи з нього, не відстежуючи номер. Звучить насправді просто, чи не так?

Можливі рішення:

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

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

Проблеми - немає можливості створити вектор в одному рядку зі списком рядків

Можливе рішення 2:

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

Проблеми - немає можливості автоматично отримати кількість рядків (про яку я знаю).

Це повинен бути простий спосіб.


Бібліотека Boost assign, здається, саме те, що ви шукаєте. Це робить призначення констант контейнерам простішим, ніж будь-коли.
Craig H

Відповіді:


108

C ++ 11 додав списки ініціалізації, щоб дозволити такий синтаксис:

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

Підтримка цієї функції C ++ 11 була додана принаймні у GCC 4.4 та лише у Visual Studio 2013 .


2018. Щойно запустив С ++ і провів кілька досліджень щодо гнучких масивів. Закінчився просто використанням векторів ...
Роберт Моліна,

37

Ви можете стисло ініціалізувати a vector<string>із статично створеного char*масиву:

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

Це, до речі, копіює всі рядки, тому ви використовуєте пам'ять удвічі. Ви можете скористатися пропозицією Уілла Діна, щоб замінити тут магічне число 3 на arraysize (str_array) - хоча я пам’ятаю, що був якийсь особливий випадок, коли ця конкретна версія arraysize могла зробити щось погане (вибачте, я не можу відразу згадати деталі) . Але це дуже часто працює коректно.

Крім того, якщо ви справді прихильні до одного рядка, ви можете визначити варіативний макрос, щоб один рядок, наприклад, DEFINE_STR_VEC(strvector, "hi", "there", "everyone");працював.


Оскільки strarrayє в заголовку, чи не порушить воно правило єдиного визначення?
jww

22

Проблеми - немає можливості автоматично отримати кількість рядків (про яку я знаю).

Існує стандартний спосіб зробити це, який багато людей (включаючи MS) визначають такі макроси arraysize:

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

1
Як варіант, можна використати щось подібне: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (Inline ключове слово не потрібно, але використовується для документування наміру функції. Сучасний компілятор теоретично повинен мати можливість повернути всю функцію, я вважаю.
Джастін Тайм - Відновити Моніку

1
Це не вдається для покажчиків. Підрахунок елементів масиву в С ++ повинен виконуватися по-іншому.
jww

8

Оголосіть масив рядків у C ++ таким чином: char array_of_strings[][]

Наприклад : char array_of_strings[200][8192];

міститиме 200 рядків, кожна рядок має розмір 8 кб або 8192 байт.

використовувати strcpy(line[i],tempBuffer); для розміщення даних у масиві рядків.


FYI, char array_of_strings [] [] не може приймати рядки C ++, спочатку переконайтесь у конвертацію в char *. cplusplus.com/reference/string/string/c_str
Luqmaan

Оскільки array_of_stringsє в заголовку, чи не порушить воно правило єдиного визначення?
jww

7

Однією з можливостей є використання покажчика NULL як значення прапора:

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

Що насправді означає char **? У Java це буде список рядків?
IAmGroot,

1
@Doomsknight: У цьому випадку так. У першому рядку я визначаю масив char*. На згадку, це викладається як 3 покажчики - один вказує на "собаку", один вказує на "кішку", а один залишається НУЛЬНИМ. Я можу взяти вказівник на цей перший вказівник і отримати char**- вказівник на вказівник на char. Коли я збільшую це, я переміщую char **, щоб вказувати на наступний елемент у списку - вказівник на вказівник, який вказує на "cat", потім я збільшую ще раз, і отримую вказівник, який вказує на покажчик NULL, і Я знаю, що я закінчив. (
Затьмарення

4

Ви можете використовувати функції beginта endз бібліотеки діапазону Boost, щоб легко знайти кінці примітивного масиву, і на відміну від рішення макросів, це дасть помилку компіляції замість порушеної поведінки, якщо ви випадково застосуєте її до покажчика.

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

3

Ви можете використовувати пропозицію Уілла Діна [ #define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))], щоб замінити тут магічне число 3 на arraysize (str_array) - хоча я пам’ятаю, що був якийсь особливий випадок, коли ця конкретна версія arraysize могла зробити щось погане (вибачте, я не можу згадати деталі негайно). Але це дуже часто працює коректно.

Той випадок, коли це не працює, це коли "масив" насправді є лише покажчиком, а не фактичним масивом. Крім того, через те, як масиви передаються функціям (перетворюються на покажчик на перший елемент), він не працює у всіх викликах функцій, навіть якщо підпис виглядає як масив - some_function(string parameter[])це насправді some_function(string *parameter).


3

Ось приклад:

#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

Замість цього макросу я можу запропонувати цей:

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) Ми хочемо використовувати макрос, щоб зробити його константою часу компіляції; результат виклику функції не є константою часу компіляції.

2) Однак ми не хочемо використовувати макрос, оскільки макрос може бути випадково використаний на покажчику. Функцію можна використовувати лише на масивах часу компіляції.

Отже, ми використовуємо визначеність функції, щоб зробити макрос "безпечним"; якщо функція існує (тобто вона має ненульовий розмір), тоді ми використовуємо макрос, як зазначено вище. Якщо функція не існує, ми повертаємо неправильне значення.


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

Ви можете безпосередньо оголосити масив рядків як string s[100];. Тоді, якщо ви хочете отримати доступ до певних елементів, ви можете отримати це безпосередньо, як s[2][90]. Для ітерації візьміть розмір рядка за допомогою s[i].size()функції.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.