【问题标题】:Needing to use char** in C++ instead of std::string*需要在 C++ 中使用 char** 而不是 std::string*
【发布时间】:2016-04-22 23:41:16
【问题描述】:

我正在为我的操作系统课程做作业。我们可以选择使用 C 或 C++,所以我决定使用 C++,因为我在工作中比 C 更早地练习它。

我需要打电话(来自“ $ man execvp "在 Linux 上)

int execvp(const char *file, char *const argv[]);

这(除非我弄错了)意味着我需要一个 C 风格的 char* 数组(C 中的字符串数组),并且不能使用 C++ 中的 std::string。

我的问题是:在 C++ 中制作/使用 char* 数组而不是字符串数组的正确方法是什么?大多数人倾向于说 malloc 在 C++ 中不再使用(我现在尝试了一些并发症)

char** cmdList = (char**)malloc(128 * sizeof(char*));

但我不知道如何在没有的情况下制作 char* 数组。 即使我使用的是 C++,我仍然可以在 C 中解决这个问题吗?我从未遇到过无法在 C++ 中使用字符串的情况。

感谢大家的时间。

【问题讨论】:

标签: c++ c arrays string char


【解决方案1】:

如果您将参数放入 std::vector<std::string> 中,就像在 C++ 中应该做的那样,那么您需要进行小的转换才能得到 execvp 想要的字符**。幸运的是,std::vectorstd::string 在内存中都是连续的。但是,std::vector<std::string> 不是指针数组,因此您需要创建一个。但是你也可以使用vector

// given:
std::vector<std::string> args = the_args();
// Create the array with enough space.
// One additional entry will be NULL to signal the end of the arguments.
std::vector<char*> argv(args.size() + 1);
// Fill the array. The const_cast is necessary because execvp's
// signature doesn't actually promise that it won't modify the args,
// but the sister function execlp does, so this should be safe.
// There's a data() function that returns a non-const char*, but that
// one isn't guaranteed to be 0-terminated.
std::transform(args.begin(), args.end(), argv.begin(),
  [](std::string& s) { return const_cast<char*>(s.c_str()); });

// You can now call the function. The last entry of argv is automatically
// NULL, as the function requires.
int error = execvp(path, argv.data());

// All memory is freed automatically in case of error. In case of
// success, your process has disappeared.

【讨论】:

    【解决方案2】:

    new[]代替malloc

    char ** cmdlist = new char*[128];
    

    不需要sizeof,因为new 知道它创建的类型的大小。对于类,如果存在,它还会调用默认构造函数。但要小心:如果没有(公共)默认构造函数的类型你不能使用new[]

    完成后使用delete[] 代替free 释放内存:

    delete[] cmdlist;
    

    当然,您也可以使用vector。这样做的好处是当vector被销毁时,用来存储vector内容的内存会自动释放。

    #include <vector>
    ...
    std::vector<char*> cmdlist(128, nullptr);   // initialize with nullpointers
    // access to entries works like with arrays
    char * firstCmd = cmdList[0];
    cmdlist[42] = "some command";
    // you can query the size of the vector
    size_t numCmd = cmdlist.size();
    // and you can add new elements to it
    cmdlist.push_back("a new command");
    ...
    // the vector's internal array is automatically released
    // but you might have to destroy the memory of the char*s it contains, depending on how they were created
    for (size_t i = 0; i < cmdlist.size(); ++i)
        // Free cmdlist[i] depending on how it was created.
        // For example if it was created using new char[], use delete[].
    

    【讨论】:

    • 谢谢!我看到其他解决方案也有效,但我选择了这个解决方案并设法让一切正常工作。
    【解决方案3】:

    假设您有一个表示参数列表的 std::vector&lt;std::string&gt; args 变量,您可以执行以下操作来获取 C 样式的字符串数组:

    auto argvToPass = std::make_unique<const char*[]>(args.size() + 1);
    int i = 0;
    for (const auto& arg : args)
    {
        argvToPass[i++] = arg.c_str();
    }
    
    // make we have a "guard" element at the end
    argvToPass[args.size()] = nullptr;
    
    execvp(yourFile, argvToPass.get());
    

    【讨论】:

    • 实际上,argvToPass 中的最后一个条目必须是 nullptr(execvp 需要)。
    • @MikeMB 谢谢,已修复。
    【解决方案4】:

    您可以创建一个const char* 的数组,并通过使用string.c_str() 仍然使用字符串,代码将如下所示

    const char ** argv  = new const char*[128];
    string arg1 = "arg";
    argv[0] = arg1.c_str();
    

    【讨论】:

      【解决方案5】:

      如果您想了解(并且安全)它,您可以使用std::unique_ptr 来确保在发生错误或异常时正确删除/释放所有内容:

      // Deleter to delete a std::vector and all its
      // malloc allocated contents
      struct malloc_vector_deleter
      {
          void operator()(std::vector<char*>* vp) const
          {
              if(!vp)
                  return;
      
              for(auto p: *vp)
                  free(p);
      
              delete vp;
          }
      };
      
      // self deleting pointer (using the above deleter) to store the vector of char*
      std::unique_ptr<std::vector<char*>, malloc_vector_deleter> cmds(new std::vector<char*>());
      
      // fill the vector full of malloc'd data
      cmds->push_back(strdup("arg0"));
      cmds->push_back(strdup("arg1"));
      cmds->push_back(strdup("arg2"));
      
      // did any of the allocations fail?
      if(std::find(cmds->begin(), cmds->end(), nullptr) != cmds->end())
      {
          // report error and return
      }
      
      cmds->push_back(nullptr); // needs to be null terminated
      
      execvp("progname", cmds->data());
      
      // all memory deallocated when cmds goes out of scope
      

      【讨论】:

      • 请注意,在 C++11 中,这不再是必需的; std::unique_ptr 将自动为数组调用 delete[]
      • @szczurcio std::unique_ptr 将在一个数组上调用delete[],但不是它的每个元素。所以为此我必须制作一个自定义删除器 - 在删除向量之前删除元素。
      • 哦,真的,我没看到你在使用strdup
      【解决方案6】:

      这(除非我弄错了)意味着我需要一个 C 风格的 char* 数组(C 中的字符串数组),并且不能使用 C++ 中的 std::string。

      不,您仍然可以在 C++ 中使用 stringstring 类有一个采用 C 字符串的构造函数:

      char str[] = "a string";
      string cppStr(str);
      

      现在您可以使用 C++ 中的string 类来操作字符串。

      【讨论】:

      • 问题不在于是否可以从char* 中获取c++ 字符串,而是如何从数组/向量/集合中获取char* 的数组(函数需要) c++ 字符串
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-19
      • 1970-01-01
      • 1970-01-01
      • 2016-06-03
      • 2010-10-22
      相关资源
      最近更新 更多