【问题标题】:Splitting declaration and assignment with string array in C++在 C++ 中使用字符串数组拆分声明和赋值
【发布时间】:2020-02-11 13:23:33
【问题描述】:

这可能有一个非常简单的解决方案,但我似乎无法弄清楚。我可以找到无数关于如何在 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]'

【问题讨论】:

  • 你必须使用 const char 吗?如果是这样,它只能在创建时初始化。
  • const char *desc[3] = { "apple", "banana", "orange" };不会有问题
  • @DavidC.Rankin 是的,有。我想要一个if 语句,它为desc 分配不同的值。
  • 你不会被阻止这样做。 const char *desc[3] 声明了一个包含 3 个指向 const char* 的指针的数组。如果您使用 const char *desc[3] = { "apple", "banana", "orange" }; 进行初始化,则没有任何东西可以阻止您稍后对其中一个指针进行分配,if (somecondition) desc[2] = "grapes";(现在您无法修改每个指针指向的 string-literals指针,但您可以更改指针指向的内容)
  • 我希望全部更改或不更改,因此如果将它们全部更改,则设置初始值是没有意义的,并且有更改每个语句的语句会很烦人元素。

标签: c++ arrays variable-assignment assign variable-declaration


【解决方案1】:

您的第一个示例在堆栈上分配数组,这只有在编译器知道大小时才有可能(因为所有字符串都是固定长度并在声明期间提供)。

当你将声明和初始化分开时,你的编译器无法知道要在堆栈上分配多少内存,所以你需要将你的类型更改为指针(它具有固定大小,无论它指向什么) :

static const char** desc;

然后使用new为数组分配足够的内存:

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

但是,这意味着您现在还必须delete[] desc 指向的数组,否则会发生内存泄漏。

最好使用现代容器类型,例如 std::vectorstd::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");

但是我真的不建议这样做,因为从长远来看,当您添加或删除字符串或更改其长度等时,您可能会遇到错误。

【讨论】:

  • 在我的具体情况下,我分配的可能值在内存中总是完全相同的大小。如果我知道这一点,有没有办法优化代码?
  • @AaronFranke 优化总是取决于多种因素,因此没有真正的包罗万象。有时问题也是:您真的需要特定的优化吗?我的一般方法是首先实现可读和可理解的代码,然后分析它的性能和资源使用情况,并优化代码中被确定为关键的特定部分。我真的建议您使用std::vector&lt;std::string&gt;std::array&lt;std::string, 3&gt;。话虽如此,Emil Vatai 回答中的最后一个解决方案可能是您正在寻找的“优化”。
【解决方案2】:

我目前有一个看起来像这样的赋值声明:

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

【讨论】:

  • 错字:initialisation.??
  • @DavidC.Rankin 不是错字。
  • 呃.....好吧,我猜是池塘的另一边:)(西边 - "initialization"
  • "数组不可赋值。你不能赋值给数组。"为什么?
  • @AaronFranke 因为语言规则是这样说的。
【解决方案3】:

Max Vollmer 给出了一些很好的建议,尽管在“现代 C++”(C++11 后)中不鼓励使用 new 和原始指针。参见 [1](Sutter 是 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/

【讨论】:

    【解决方案4】:

    您的声明是错误的,因为当您编写 char [3] 时,它会使您的字符数组包含 3 个字符,而不是包含 3 个不同的无限字符的数组。

    【讨论】:

    • 我在问题中没有看到char [3]
    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多