Разделение объявления и присваивания с массивом строк в C ++ - PullRequest
1 голос
/ 15 октября 2019

Возможно, есть действительно простое решение, но я не могу понять это. Я могу найти бесчисленные примеры того, как создать строковый массив в C ++, но я не могу найти тот, который показывает, как сделать присвоение отдельным.

В настоящее время у меня есть объявление с присваиванием, которое выглядит примерно так:

static const char *desc[3] = { "apple", "banana", "orange" };

То, что я хотел бы сделать, это разделить объявление и присвоение отдельным операторам. Объявление:

static const char *desc[3];

... но я не могу понять, как выполнить задание. Я пробовал следующее:

desc = { "apple", "banana", "orange" }; // Expression must have a modifiable lvalue. error: assigning to an array from an initializer list
*desc = { "apple", "banana", "orange" }; // Too many initializer values. error: cannot convert '<brace-enclosed initializer list>' to 'const char*' in assignment
desc[3] = { "apple", "banana", "orange" }; // Too many initializer values. error: cannot convert '<brace-enclosed initializer list>' to 'const char*' in assignment
*desc[3] = { "apple", "banana", "orange" }; // Expression must have a modifiable lvalue. error: assignment of read-only location '* desc[3]'

Ответы [ 5 ]

3 голосов
/ 15 октября 2019

Ваш первый пример размещает массив в стеке, что возможно только потому, что компилятор знает размер (поскольку все строки имеют фиксированную длину и указываются во время объявления).

Когда вы разделяете объявление и инициализацию, вашу компилятора нет возможности узнать, сколько памяти выделить в стеке, поэтому вам нужно изменить тип на указатель (который имеет фиксированный размер, независимо от того, на что он указывает):

static const char** desc;

изатем используйте new, чтобы выделить достаточно памяти для массива:

desc = new const char*[3]{ "apple", "banana", "orange" };

Однако это означает, что теперь вы также должны delete[] массив, на который указывает desc, иначе вы получите утечку памяти.

Намного лучше было бы использовать современные типы контейнеров, такие как std::vector и std::string:

static std::vector<std::string> desc;

, а затем

desc.push_back("apple");
desc.push_back("banana");
desc.push_back("orange");

Эти классы заботятся обо всехнеприятное управление памятью для вас под капотом.


Другая альтернатива, если вы действительно хотите необработанный массив и не хотите полагаться на new[] и delete[], это объявить фиксированныйразмер массива с достаточным пространством для ваших строк, например:

static const char desc[3][128];

и последующее копирование строковых значений в этот блок памяти:

std::strcpy(desc[0], "apple");
std::strcpy(desc[1], "banana");
std::strcpy(desc[2], "orange");

Однако я действительно не рекомендую делатьЭто связано с тем, что вы рискуете ошибками в долгосрочной перспективе при добавлении или удалении строк, изменении их длины и т. д.

2 голосов
/ 15 октября 2019

В настоящее время у меня есть объявление с присваиванием, которое выглядит примерно так:

static const char *desc[3] = { "apple", "banana", "orange" };

Это не «назначение». Это инициализация.

Кажется, я не могу понять, как выполнить присваивание.

Массивы не могут быть назначены. Вы не можете присвоить массиву.

Если вы хотите изменить элементы массива после его инициализации, вам нужно либо итерировать каждый элемент и назначать их один за другим:

const char *arr[] = {"apple", "banana", "orange"};
static_assert(std::size(arr) == std::size(desc));
std::copy_n(arr, std::size(arr), desc);

Или вы можете заключить массив в класс, и в этом случае вам будет сгенерирован оператор присваивания. Существует стандартный шаблон для такой обертки массива std::array:

static std::array<const char*, 3> desc;
// later
desc = {"apple", "banana", "orange"};
1 голос
/ 15 октября 2019

Макс Воллмер дает несколько превосходных советов, хотя использование "1001 *" и необработанных указателей не рекомендуется в "современном C ++" (пост C ++ 11). См. [1] (Саттер является членом комитета по стандартизации C ++, поэтому он знает свое дело.

Так что, если вы собираетесь «истинным путем C ++» иметь массив строк, то вам следует пойти на:

std::vector<std::string> dest_a;
dest_a.push_back("apple");
dest_a.push_back("banana");
// or
std::vector<std::string> dest_b(3);
dest_b[0] = "orange";
dest_b[1] = "pear";
dest_b[2] = "plumb";

Если вам нужны необработанные указатели, я думаю, я бы пошел на старые функции C strcpy.


Хотя, вывозможно, просто ищет это.

  static const char *ptr[2];
  ptr[0] = "orange";
  ptr[1] = "pear";

[1] https://herbsutter.com/elements-of-modern-c-style/

0 голосов
/ 15 октября 2019

ваше объявление неверно, потому что когда вы пишете char [3], ваш массив символов будет содержать 3 символа, а не массив с 3 различными неограниченными символами.

0 голосов
/ 15 октября 2019

Ваша первая попытка считается присваиванием (что нельзя сделать с массивом), а не инициализацией.

Это определение должно работать:

const char* foo::desc[] = { "apple", "banana", "orange" };

для объявления, похожего наэто:

class foo {
    static const char* desc[];
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...