【问题标题】:Why doesn't strcpy use a const pointer for dest?为什么 strcpy 不对 dest 使用 const 指针?
【发布时间】:2017-06-08 05:30:19
【问题描述】:

strcpy 的签名是这样的有什么原因吗:

char *strcpy(char *dest, const char *src);

而不是这个?

char *strcpy(char *const dest, const char *src);

据我所知,该函数永远不会改变指针。

我是否误解了 const 指针应该用于什么?在我看来,当我编写的函数接受不会更改的指针(通过 realloc 等)时,我会将其标记为 const 指针,以便调用者可以确保他们的指针不会在它们上移动。 (如果他们有其他结构/等引用该指针位置将变得过时)

这是一种好的做法,还是会产生意想不到的后果?

【问题讨论】:

  • 我认为一个常量只能被初始化/赋值/定义一次或在声明时定义。
  • 不仅函数永远不会改变指针。,即使没有const,strcpy也无法改变dest

标签: c pointers constants strcpy


【解决方案1】:

strcpy 的源代码大致是这样的:

char *strcpy(char *dest, const char *src)
{
  while (*dest++ = *src++);
}

这里我们实际上修改了dest,但这对调用者没有任何影响,因为在strcpy函数内部,dest是一个局部变量。

但以下代码无法编译,因为 dest 是 const:

char *strcpy(char * const dest, const char *src)
{
  while (*dest++ = *src++);
}

我们需要这样写:

char *strcpy(char * const dest, const char *src)
{
  char *temp = dest;
  while (*temp++ = *src++);
}

它引入了一个不必要的temp 变量。

【讨论】:

  • 注意:这 3 个示例不会为 char *strcpy() 函数返回值,以将它们渲染为 UB - 当然它们是粗略的。看到没有“非必要临时变量”的代码返回 C 库中指定的原始 dest 会很有趣。
  • @chux 你是完全正确的,但这只是为了演示目的。
【解决方案2】:

函数参数的限定符在声明(原型)中完全忽略。这是 C 语言所要求的,这是有道理的,因为这样的限定对函数的调用者没有可能的意义。

const char *src 的情况下,参数src 不是合格的;它指向的类型是合格的。在您对dest 的假设声明中,限定符适用于dest,因此没有意义。

【讨论】:

    【解决方案3】:

    char *foo(char *const dest, const char *src) { ... } 表示指针dest 在函数体中不会改变。

    这并不意味着dest指向的数据会改变或不会改变。

    const char *src 保证调用代码src 指向的数据不会改变。

    在调用strcpy(d,s)foo(d,s) 之类的函数时,调用代码并不关心函数是否更改了指针的 副本。调用代码关心的是sd所指向的数据是否改变,由*左侧的const控制

    char *dest,     // data pointed by `dest` may or may not change.
    const char *src // data pointed by `src` will not change change because of `src`.
    

    【讨论】:

      【解决方案4】:

      按照您的建议将其标记为 const 是没有意义的。在 C 中,函数参数作为副本传递。也就是说strcpy()里面的变量dest其实是一个新变量(压栈),里面的内容是一样的(这里是地址)。

      看看这个函数原型:

      void foo(int const a);
      

      这没有语义价值,因为我们知道我们传递给foo()的原始变量a不能更改,因为它是一个副本。只有副本可能会更改。当 foo 返回时,我们保证原始变量a 不变。

      在函数参数中,只有当函数实际上可以持续改变变量的状态时,您才需要使用关键字 const。例如:

      size_t strlen(const char *s);
      

      这将变量s 的内容(即存储在地址s 指向的值)标记为const。因此,您可以保证当 strlen 返回时您的字符串不会改变。

      【讨论】:

        【解决方案5】:

        据我所知,该函数永远不会改变指针。

        是的,但你可以。您可以随意更改指针。无需制作dest 指针const

        例如:

        int main(void)
        {
            char *s = "Hello";
            char *d = malloc(6);
        
            strcpy(d, s);
            puts(d);
            strcpy(d, "World");
            puts(d);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-28
          • 1970-01-01
          • 2018-01-03
          相关资源
          最近更新 更多