为什么strcpy不使用dest指针的const指针?

问题描述:

是否有一个原因的strcpy的签名是这样的:为什么strcpy不使用dest指针的const指针?

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

,而不是这个?

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

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

我误解了什么const指针应该用于?在我看来,当我写一个函数接受一个不会被改变的指针(通过realloc等),然后我把它标记为一个const指针,这样调用者可以确定它们的指针不会被移动。 (如果他们有其他结构/等参考指针位置将变得过时)

这是一种好的做法,或者它会产生意想不到的后果吗?

+0

左侧的const我觉得一个常数,只能被初始化/ assighned /定义一次控制或在声明时定义。 –

+0

不仅_函数不会改变pointer._,但是即使没有const,strcpy也无法改变dest。 –

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

注意:3个例子不会返回值为'char * strcpy()'函数渲染它们UB - 当然它们是_rough_。看到没有“非必要的临时变量”的代码会很有趣,它会返回C库中指定的原始“dest”。 – chux

+0

@chux你完全正确,但它仅用于演示目的。 –

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

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

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

是的,但你可以。你可以自由改变指针。无需制作dest指针const

例如:

int main(void) 
{ 
    char *s = "Hello"; 
    char *d = malloc(6); 

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

这是没有意义的,将其标记为const你的建议。在C中,函数参数作为副本传递。这意味着strcpy()里面的变量dest实际上是一个新的变量(压入堆栈),它保存着相同的内容(这里是地址)。

看看这个函数原型:

void foo(int const a); 

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

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

size_t strlen(const char *s); 

这标志着可变s为const(即,存储在该地址s点值)的含量。因此,你保证你的字符串在strlen返回时不会改变。

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

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

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

在调用像strcpy(d,s)foo(d,s)这样的函数时,调用代码并不关心函数是否更改指针的副本。所有调用代码关心的是如果数据指向sd改变,这是由*

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