【问题标题】:Initializing a Struct's variable const char* const* with C++使用 C++ 初始化 Struct 的变量 const char* const*
【发布时间】:2018-11-26 02:07:06
【问题描述】:

我正在尝试解决一个要求使用给定结构返回结果的编码问题。结构体定义为:

struct Answer
{
    const char* const* lastNames;
    unsigned numberOfPeople;

}

其中 lastNames 是指向姓氏的指针,每个姓氏都以非字母字符结尾。我似乎找不到任何方法来将用于编译所有姓氏的字符串向量转换为可以分配给 lastNames 的变量。我尝试使用所有姓氏创建一个字符串并使用 c_str() 分配它,如下所示: Ans->lastName = allNames.c_str(); 但这给了我一个错误。由于问题的限制,我无法将 struct 变量更改为其他任何内容。如何将字符串分配给 const char* const*

【问题讨论】:

    标签: c++


    【解决方案1】:

    所使用的结构有效地使用了 C 风格的方法来定义一个可变大小的指针数组,该数组指向 char(上面覆盖着 const)。您需要存储char const* 的数组以及指向的实体。以下是您可以从 std::vector<std::string> 构建它的方法:

    std::vector<std::string> strings = somehow_compute_the_strings();
    std::vector<char const*> array;
    for (std::string const& s: strings) {
        array.push_back(s.c_str());
    }
    
    Answer answer = { array.data(), array.size() };
    

    当然,如果没有指向过期数据的指针,你不能返回 answer:你需要保持两个 std::vectors 活着。这两个对象可能会成为调用该函数的对象的成员。要实际返回 Answer 类型的对象,而没有地方可以保留 std::vectors,您可以分配相关实体并接受结果将产生内存泄漏,除非调用者可以清理结果。

    【讨论】:

      【解决方案2】:

      你不能只是投射东西。 struct Answer 需要一个 char**,因此只要使用 struct Answer,您就必须构建它并使其保持有效。至少他们很友好地让我们知道他们不打算修改它或清理内存,因为它需要“const char * const *”。

      #include <iostream>
      #include <vector>
      #include <string>
      #include <assert.h>
      
      typedef std::vector<std::string> VectorOfStrings_type;
      
      struct Answer
      {
          const char* const* lastNames;
          unsigned numberOfPeople;
      };
      
      class AnswerWrapper
      {
      private:
          // construct and maintain memory so the pointers in the Answer struct will be valid
          char ** lastNames;
          unsigned int numberOfPeople;
      
      public:
          AnswerWrapper(const VectorOfStrings_type &input){
              numberOfPeople = input.size();
      
              // create the array of pointers
              lastNames = static_cast<char**>(
                  malloc(numberOfPeople * sizeof(char*)) 
              );
      
              // create each string
              for (unsigned int i = 0; i < numberOfPeople; ++i){
                  const std::string &name = input[i];
      
                  // allocate space
                  lastNames[i] = static_cast<char*>(
                      malloc(name.size() + 1)
                  );
      
                  // copy string
                  strncpy(lastNames[i], name.data(), name.size());
      
                  // add null terminator
                  lastNames[i][name.size()] = '\0';
              }
          }
      
          operator Answer (){
              return Answer{ lastNames, numberOfPeople };
          }
      
          ~AnswerWrapper(){
              // critcally important, left as an exercise
              assert(0);
          }
      };
      
      void SomeFunctionWhichUsesAnswer(Answer a){
          // presumably you have some legacy C code here
          // but here's a quick and easy demo
          for (unsigned int i = 0; i < a.numberOfPeople; ++i)
              std::cout << a.lastNames[i] << std::endl;
      }
      
      int main() {
          // Here is your vector of strings
          VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
      
          // You must construct a buffer for the "Answer" type, which must remain in scope
          AnswerWrapper temp{ myData };
      
          // AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
          SomeFunctionWhichUsesAnswer(temp);
      }
      

      另外,我注意到 Answer 中的字符串不被称为空终止。这是您可以处理的单独问题。

      【讨论】:

      • Dietmar Kuhl 的数据结构看起来不错。您可以在 AnswerWrapper 中使用它。
      【解决方案3】:

      const 成员变量只能在构造函数中赋值。
      如果您可以添加到结构,定义一个构造函数,并使用: lastname(value) 语法;或者使用 struct Answer myVar{value,number}; 初始化,就在你声明你的实例的地方。

      另一个 - 丑陋、危险且不受欢迎 - 替代方案是演员表:(char**) lastname = value;,或 C++ 语法 reinterpret_cast&lt;char**&gt;(lastname) = value。 如果有人教你这些方法中的任何一种,请更换老师。

      【讨论】:

      • 该成员不是const。它是指向const 的[可变] 指针,指向char const 对象。即使成员是const,它也可以通过直接初始化来初始化。真正的问题是增加的间接性。
      • 第二段中的代码格式不正确(编译器应该拒绝它)。这些转换的结果是一个指针纯右值,它作为赋值运算符的左操作数无效
      • 您的答案中的“价值”是什么?您是否将字符串向量转换为 char**?您应该明确指出这是绕过编译器错误并在运行时崩溃的方法。
      猜你喜欢
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-01
      相关资源
      最近更新 更多