“const int * ptr =&i”究竟是什么意思?为什么它接受非常数的地址?

你的答案非常寻求清除我对今天意识到的const理解中的这个主要缺陷。

在我的程序中,我使用了语句const int *ptr=&i; 但是没有对变量i使用任何const限定符。两件事令我困惑:

1)当我尝试使用ptr修改i的值时,我使用了const int *ptr=&i; ,我得到assignment of read-only location '*ptr'|的错误assignment of read-only location '*ptr'| ,即使我没有用const限定符声明变量i 。那究竟是什么语句const int *ptr=&i; 是什么意思,它与int * const ptr=&i;什么不同int * const ptr=&i;

我把它钻进了我的脑袋里, const int *ptr=&i; 表示指针存储常量的地址,而int * const ptr=&i; 指的是指针本身是常量并且不能改变。但今天有一个用户在讨论中告诉我( LINK ) const int *ptr means the memory pointed to must be treated as nonmodifiable _through this pointer_ 。我发现这个新的东西就像这个意思是“一些选择指针不能改变值(而其他人可以改变)”。我不知道这样的选择性声明!!但是一个180k的老手certificate了那个用户是正确的!!所以你能说出来吗更清晰,更详细,更严谨的方式?“const int * ptr =&i;究竟是什么? 意思?

2)我还被告知我们可以在语句const int *ptr=&i;对程序撒谎 const int *ptr=&i; 通过为指针指定非常量的地址。这意味着什么?为什么我们允许这样做?如果我们将非常量的地址分配给预期的指针ptr ,为什么不得到警告?一个常量的地址?如果它是如此宽容被分配非常量的地址,为什么当我们试图改变那个非常数的值时会抛出一个错误,这是一个合理的事情,指向的变量是一个非常数?

 #include  int main () { int i=8; const int *ptr=&i; *ptr=9; printf("%d",*ptr); } 

错误: assignment of read-only location '*ptr'|

定义const int *ptr = &i; 本质上说“我不会通过ptr修改i 。”它没有说ptr指向的intconst ,它说ptr不应该用来修改它。

这种转换是允许的,因为它是有道理的:因为i不是const ,我可以修改它,但我也可以选择不修改它。 当我选择不修改i时,没有规则被破坏。 并且,如果我创建一个指向i的指针并说“我不会使用此指针来修改i ”,那也没关系。

您希望这样做的原因是您可以将对象的地址传递给一个带有指向const对象的指针的例程。 例如,考虑strlen例程。 strlen例程不会修改其输入,因此其参数是指向const char的指针。 现在,我有一个指向char的指针,我想知道它的长度。 所以我打电话给strlen 。 现在我传递一个指向char的指针作为参数的参数,该参数是指向const char指针。 我们希望转换工作。 它完全有道理:如果我愿意, 可以修改我的char ,但strlen例程不会,所以它将它们视为const char

1)你得到*ptr = something;的错误*ptr = something; 因为你将ptr声明为指向const int的指针,但是你违反了你不使用ptr修改int承诺。 事实上, ptr指向一个非const的对象并不否定你不使用ptr来修改它的承诺。

2)将非const对象的地址分配给指向const的指针并不是一个谎言。 赋值并没有说对象是const ,它表示不应该使用指针来修改对象。

此外,虽然您没有问过这个问题,但C中的const属性并不完全绑定。 如果将对象定义为const ,则不应对其进行修改。 但是,在其他情况下,将指向const的指针传递给例程,该例程将其转换为指向非const的指针。 这实际上是语言中的缺陷,无法保留以我们可能更喜欢的方式处理const所需的所有信息。 一个例子是strchr例程。 它的声明是char *strchr(const char *s, int c) 。 参数sconst char *因为strchr不会更改其输入。 但是, strchr例程的指针是从s派生s (它指向字符串中的一个字符)。 因此,在内部, strchr已将const char *转换为char *

这允许您编写将char *传递给strchr并使用返回的指针修改字符串的代码,这很好。 但这意味着编译器无法完全保护您免受错误的影响,例如将const char *传递给strchr并使用返回的指针尝试修改字符串,这可能是一个错误。 这是C的一个缺点。

解开这个:

const int * ptr表示“* ptr是一个const int”; 即“ptr是指向const int的指针”。 你不能写* ptr = 9,因为* ptr是一个常量。 但是你可以写int j; ptr =&j; 因为你可以允许指针ptr指向不同的int。

int * const ptr表示“ptr是指向int的常量指针”。 您可以编写* ptr = 9,因为您没有更改ptr指向的地址。 你不能把它分配给其他东西; 即int j; ptr =&j; 不会编译。

对于第二部分(2),使用const int * ptr是非常有用的,特别是在函数原型中,因为它告诉函数的调用者ptr指向的变量不会被函数修改。 至于赋值,如果你有int * m =&i,那么ptr = m就可以,但是m = ptr是不行的,因为后者将“抛弃constness”; 即你已经绕过了常规。