【问题标题】:Why strrchr() returns `char*` instead of `const char*`?为什么 strrchr() 返回 `char*` 而不是 `const char*`?
【发布时间】:2013-05-31 15:06:38
【问题描述】:

函数char* strrchr(const char *str, int ch) 返回str (const char *) 内的指针(char*),ch 的最后一次出现所在的位置。

所以我们可以编写以下代码,无需任何转换:

#include <string.h>
int main()
{
    const char CONSTSTR[] = "foo/bar/foobar.txt";
    char *ptr = strrchr (CONSTSTR, '/');
    *ptr++ = 'B';
    *ptr++ = 'A';
    *ptr++ = 'D';
}

返回char*而不是const char*有什么好处?

编辑:
正如Shafik Yaghmour 指出的那样,How does strchr implementation work? 有很好的答案

由于我的代码是 C++,我将使用 &lt;cstring&gt; 而不是 &lt;string.h&gt;。感谢您的回答;-)

但是,Mike Seymour's answer 最适合这个问题。我什至添加了a more detailed answer below 以明确表示strrchr() 是一个C 函数(不允许重载),该声明同时适合constnon-const 字符串。因为strrchr() 可以用non-const 字符串调用,所以返回的字符串也应该是non-const

【问题讨论】:

  • 请注意,由于您将此标记为c++ 而不是c,因此您应该真正使用cstring,而不是string.h
  • 这个答案还不错:stackoverflow.com/a/14368141/1708801
  • @BoBTFish:你为什么要用 std:: 前缀噪声感染你的程序?您是否允许出于任何目的重用出现在 string.h 标头中的名称?我当然不会。所以它们在 string.h 放置它们的全局范围内很好。
  • @BoBTFish:实际上这里的区别并不是纯粹的迂腐。 &lt;cstring&gt; 提供了 C 中不可能提供的 const 正确的重载。

标签: c++ null-terminated strrchr const-string


【解决方案1】:

您正在查看 C 标准库 (&lt;string.h&gt;) 中的遗留函数。 C++ 库 (&lt;cstring&gt;) 引入了 appropriate const and non-const overloads,因此您应该尽可能使用它。

【讨论】:

  • Annex D.5p2 指出“每个 C 头文件,每个头文件都有一个名称为 name.h 的名称,其行为就像每个由相应 cname 头文件放置在标准库命名空间中的名称一样在全局命名空间范围内。...”所以提到的重载也必须在 sting.h 中,并且没有理由仅出于这个原因使用 c 版本。
  • @BalogPal 你混淆了“名称”和“声明”。 name strrchr&lt;string.h&gt; 放入全局命名空间,并由&lt;cstring&gt; 放入命名空间std。尽管如此,&lt;string.h&gt;(作为 C 头文件)不能包含重载,因此它只为名称 strrchr 提供了一种含义。 &lt;cstring&gt; 是一个 C++ 头文件,因此它为名称 strrchr 提供了两个(重载)声明。
  • @andrew:所以你说包括 我将获得 C 标准中定义的 NULL 版本,而不是 C++ 要求它被覆盖的方式,禁止 (void*)0?只是选择一个随机的增量会导致无数现有项目无法编译。抱歉,我坚持我的解释,“表现为”意味着“表现为”。
【解决方案2】:

在 C 中,函数必须是这样的,或者在许多情况下强制用户使用狡猾的强制转换:

  • 如果它采用非const 指针,则无法搜索const 字符串;
  • 如果它返回一个const 指针,则不能使用它来修改非const 字符串。

在 C++ 中,您应该包含 &lt;cstring&gt; 而不是已弃用的 C-only 标头。这将为您提供两个正确的 const 重载,这在 C 中无法完成:

const char* strchr(const char* s, int c);
      char* strchr(      char* s, int c);

【讨论】:

  • 我接受了你的回答,但我提供了更详细的回答。干杯
【解决方案3】:

const char *str 表示strrchr 保证不修改str

返回const char *表示strrchr禁止修改返回值。

【讨论】:

  • 我同意你的看法。但是为什么strrchr() 返回char*?为什么不const char*
  • 他的回答告诉你@olibre。再读一遍。
  • @crush 不是。正如 OP 所展示的,这种返回类型是不安全的。请注意,C++ 版本具有正确的重载。
  • OK 我写这个评论的时候才明白...所以答案是:strrchr() 不禁止修改返回的指针的内容,指向作为参数传递的cont字符串因为 传递的字符串可能是非常量的。我说的对吗?
  • @olibre 这就是我的意思。尤其是在包含 c 标头时。
【解决方案4】:

strrchr() from &lt;string.h&gt; 是一个 C 函数。由于 C 不允许函数重载,strrchr() 被设计为适合 constnon-const 字符串。

char* strrchr( const char *str, int ch );

strrchr() 可以用 non-const 字符串调用,因此返回的字符串也应该是 non-const,如以下示例所述。

const 没有编译错误的上下文:

#include <string.h>
int main()
{
    const char CONSTSTR[] = "foo/bar/foobar.txt";
    const char *basename = strrchr (CONSTSTR, '/');
    // basename points to "foobar.txt"
}

非常量上下文没有编译错误:

#include <string.h>
int main()
{
    char nonconst[] = "foo/bar/foobar.txt";
    char *basename = strrchr (nonconst, '/');
    basename[0] = 'G';
    basename[3] = 'D';
    // basename points to "GooDar.txt"
}

使用不当也没有编译错误:

#include <string.h>
int main()
{
    const char CONSTSTR[] = "foo/bar/foobar.txt";
    char *nonconst = strrchr (CONSTSTR, '/');
    *nonconst++ = 'B';
    *nonconst++ = 'A';  // drawback of the unique declaration: 
    *nonconst++ = 'D';  // no compilation error
}

在C++中,有two overloaded functions:

const char* strrchr( const char* str, int ch );  //1st
      char* strrchr(       char* str, int ch );  //2nd

const 上下文使用第一个:

#include <cstring>
int main()
{
    const char CONSTSTR[] = "foo/bar/foobar.txt";
    const char *basename = std::strrchr (CONSTSTR, '/');
    // basename points to "foobar.txt"
}

non-const 上下文使用第二个:

#include <cstring>
int main()
{
    char nonconst[] = "foo/bar/foobar.txt";
    char *basename = std::strrchr (nonconst, '/');
    basename[0] = 'G';
    basename[3] = 'D';
    // basename points to "GooDar.txt"
}

使用不当会产生编译错误:

#include <cstring>
int main()
{
    const char CONSTSTR[] = "foo/bar/foobar.txt";

    char *nonconst = std::strrchr (CONSTSTR, '/');
// Visual C++ v10 (2010)
// error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'

    *nonconst++ = 'B';
    *nonconst++ = 'A';
    *nonconst++ = 'D';
}

但最后一个示例使用g++ -Wall file.cpp 不会产生任何编译错误。使用 GCC 版本 4.1.2 (RedHat)4.7.2 (MinGW) 测试。

【讨论】:

    【解决方案5】:

    为什么要禁止代码修改返回的变量?请注意const char * 不是char * const,在任何情况下您都可以修改字符,但您无法控制返回值本身,这没有多大意义,因为您可能想要更改它并根据您的目的在不同位置编辑基础字符串。

    【讨论】:

    • 我不太明白你的意思。你的char * const 在哪里?是关于CONSTSTR 的吗?我认为const char CONSTSTR[] = "x" 就像const char* const CONSTSTR = "x" 除了sizeof(CONSTSTR)
    猜你喜欢
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 2012-07-21
    相关资源
    最近更新 更多