为什么strcpy不使用const指针作为目标(dest)?

6

为什么strcpy的函数签名是这样的:

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

不要使用这个?

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

据我所知,该函数永远不会改变指针。
我是否误解了const指针的用途?在我的想法中,当我编写的函数接受一个指针且该指针不会被更改(通过realloc等),那么我会将其标记为const指针,以便调用者可以确保他们的指针不会移动。(如果他们有其他结构体/等引用该指针位置,那么这些引用将变得过时)
这样做是否可以,或者会产生意想不到的后果?

我认为常量只能在声明时初始化/赋值/定义一次。 - marshal craft
不仅函数永远不会改变指针,而且即使没有const,strcpy也无法改变dest - Jabberwocky
5个回答

11

strcpy 的源代码大致如下:

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

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

但是下面的代码不会编译,因为dest是一个常量:

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变量。


1
注意:这三个示例不会为char *strcpy()函数返回值,因此它们是未定义的——当然它们很粗糙。有趣的是看到没有“非必要临时变量”的代码,该代码将按照C库中指定的方式返回原始的dest - chux - Reinstate Monica
@chux 你说得完全正确,但这只是演示目的。 - Jabberwocky

3

在函数声明(原型)中,函数参数的限定符完全被忽略。这是C语言所要求的,并且有道理,因为对于调用函数的调用者来说,此类限定符无法产生任何意义。

对于const char *src的情况,参数src并没有被限定,而是指向它的类型被限定了。在您假想的dest声明中,该限定符应用于dest上,因此无意义。


2

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`.

1
你建议将其标记为const毫无意义。在C语言中,函数参数是按副本传递的。这意味着在strcpy()内部的变量dest实际上是一个新变量(推入堆栈),它保存相同的内容(此处为地址)。
看一下这个函数原型:
void foo(int const a);

这段文字没有语义价值,因为我们知道传递给 foo() 的原始变量 a 是一个副本,不会被更改。只有副本可能会发生更改。当 foo 返回时,我们保证原始变量 a 不会被更改。
在函数参数中,只有在函数实际上可以持续更改变量状态时,才应使用关键字 const。例如:
size_t strlen(const char *s);

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

-1
据我所知,该函数不会改变指针。
是的,但您可以。您可以自由更改指针。无需使“dest”指针为“const”。
例如:
int main(void)
{
    char *s = "Hello";
    char *d = malloc(6);

    strcpy(d, s);
    puts(d);
    strcpy(d, "World");
    puts(d);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接