【问题标题】:How to pass char array as const char* arg?如何将 char 数组作为 const char* arg 传递?
【发布时间】:2018-08-07 10:49:25
【问题描述】:

如何将 char array[] 传递给接受const char* arg 类型的函数,最合适的方法是什么?

请忽略我在此示例中使用静态 100 缓冲区的事实:

char buff[100];
sprintf_s(buff, sizeof(buff), "%s", unrelated);

然后我需要将buff 传递给接受const char* 的函数

MyFunction(const char* path);

我尝试直接传递它:MyFunction(buff) 并且它有效,但有人可以解释为什么吗?是否有更好的方法来达到同样的效果?

【问题讨论】:

  • 因为char buff[100] 在将其作为参数传递给函数时会衰减为char*(并且您始终可以将非const 隐式转换为const)。更好的方法是使用std::string
  • 避免在 cmets 中回答问题。
  • What is array decaying?的可能重复
  • if there is better way to achieve the same result? 这到底是什么意思?
  • 正确的方法是通过std::stringstd::vector<char>

标签: c++ arrays arguments constants


【解决方案1】:

我尝试直接传递它:MyFunction(buff) 并且它有效,但有人可以解释为什么吗?是否有更好的方法来达到同样的效果?

“更好的方法”有很多解释。 SO 这里的一些人会坚持认为std::string 是C++ 方式,因此总是比char[] 好,但事实是这取决于你在做什么。如果您试图避免动态内存分配,那么您所拥有的当然是可以接受的,甚至可能是“最佳方式”。但是,如果您为缓冲区数组(即const char* buff = new char[BUFF_SIZE];)动态分配内存,那么我认为“更好的方法”是使用std::string,原因有很多,其中最重要的是它管理自己的内存。在您的情况下,您可以像这样使用它。

std::string buff;
MyFunction(buff.c_str());

为什么将 char[] 传递给 const char* 有效?

之所以有效,是因为数组名称在表达式中使用时会衰减为指向第一个元素的指针。在您的示例中,char buff[100] 在传递到 MyFunction 时衰减为指针 char*。您还可以将非常量参数作为const 传递,因为MyFunction 保证不会改变数据。这种到const 的隐式转换很好并且允许。

正确终止的const char* 是“特殊的”,并且在末尾会有一个\0 sentinel value,因此您不需要像处理所有其他类型一样指定传递给函数的缓冲区的大小的数组。被调用的函数将检查此空终止符并在适当的长度处停止而不会越界。我假设您的 MyFunction(const char* path); 以这种方式检查正确以空结尾的 C 字符串,如果没有,那么它必须对 path 做出一些潜在危险的假设。

【讨论】:

  • 我投了反对票,因为这个答案没有说明任何试图回答实际提出的问题 - 为什么将 char[] 传递给 const char* 工作?正确的答案是数组/指针衰减,以及从非常量到常量的隐式转换。问题中没有任何内容表明MyFunction() 如何与const char* 一起使用,因此在没有更多信息的情况下假设它期望以空字符结尾的字符串是一个错误的假设。
  • “尽可能使用 std::string 而不是 const char*。” 这是一个粗略的概括,并不是一个真正公平的陈述。充其量,您可以推荐std::string_viewstd::string 的智能组合。但有时坦率地说,const char* 就可以了。随机将动态分配添加到您的程序中,然后 .c_str() 结果是完全没有意义的。
  • @RemyLebeau 已更新以纳入您的公平批评。最后一点,将一个参数作为指向数组开头的指针(即MyFunction(const char * path))的函数更好地了解path 的长度,并且必须通过检测\0 来做到这一点。我认为这是一个公平的假设,否则它就会被打破。
  • @LightnessRacesinOrbit 关于内存分配是一个公平的观点,这就是为什么我说“尽可能”而不是一直,因为我同意你的观点,有些情况不需要分配所以std::string 可能是矫枉过正。我会争辩说,如果你动态分配你的数组,即const char * buff = new char[BUFF_SIZE];,那么在这种情况下你想要更喜欢std::string
  • @JustinRandall:在那种情况下是的——虽然BUFF_SIZE 的使用暗示了一个常数,所以我建议找到一种方法将其更改为char buf[BUFF_SIZE]
【解决方案2】:

函数签名可以改写为:

int MyFunction(char const * buff);

从右到左读取类型,该函数需要一个指向char(只读)常量缓冲区的指针。该功能承诺不会改变buff 的内容。

您可以传递一个 可变 缓冲区(非常量),因为该函数不会修改缓冲区。这是允许的。

您不能将指向常量(只读)缓冲区的指针传递给将修改缓冲区的函数。

int MutateBuffer(char * buffer);

以上是可能写入缓冲区的函数的签名。因此,不建议将只读缓冲区传递给此函数,编译器至少会发出警告。

【讨论】:

    【解决方案3】:

    数组"decays" into a pointer 到同一个内存。只要数组中的数据末尾有一个标记(NUL字节),被调用者只需要指针,就可以使用直到标记的缓冲区。

    或者,如果它不是 C 字符串(即没有标记;标记是使数组成为 C 字符串的约定),那么您还需要传递缓冲区的长度(通常sizeof(buff)) 所以被调用者知道缓冲区有多长——以避免溢出。

    【讨论】:

      猜你喜欢
      • 2020-04-15
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多