我试图理解一件事。
我知道我无法更改常量指针的值,但如果我按以下方式初始化指针,我可以更改其地址:
int foo = 3;
const int *ptr = &foo;
*ptr = 6; // throws an error
int bar = 0;
ptr = &bar; // foo == 0
现在,让我说我声明(/ define,我永远不记得哪一个)函数:
void change(const int arr[], int size);
int main() {
int foo[2] = {};
change(foo, 2);
std::cout << foo[0];
}
void change(const int arr[], int size) {
// arr[0] = 5 - throws an error
int bar = 5;
arr = &bar;
}
上面代码中的最后一行不会引发任何错误。但是,当函数结束并且我显示第一个元素时,它显示0 - 所以没有任何改变。
为什么会这样?
在这两种情况下,我都有常量指针,我尝试更改其地址。在第一个例子中它起作用。在第二个中它没有。
我还有另一个问题。我被告知如果我想将两个指针类型传递给函数,const关键字将无法按预期工作。真的吗?如果是这样,那么原因是什么?
答案 0 :(得分:12)
你正在搞这个术语很多,所以我要从那里开始,因为我认为这是你混淆的一个主要原因。考虑:
int x;
int* p = &x;
x
是int
,p
是“指向int
的指针”。要修改p
的值,意味着将p
本身更改为指向其他位置。指针值是它所拥有的地址。该指针p
包含int
对象的地址。更改指针的值并不意味着更改int
对象。例如,p = 0;
将修改p
的值。
除此之外,p
的地址不是它所拥有的地址。 p
的地址将是您获得的&p
并且类型为“指向int
的指针”的地址。也就是说,p
的地址是您在内存中找到指针p
的地方。由于对象不会在内存中移动,因此没有“更改其地址”的内容。
所以现在已经不在了,让我们理解一个常量指针是什么。 const int*
不是常量指针。它是一个指向常量对象的指针。它指向的对象是常量,而不是指针本身。常量指针类型看起来更像int* const
。这里const
适用于指针,因此它的类型为“const
指针int
”。
好的,现在我会很快给你一个简单的方法来记住声明和定义之间的区别。如果你买了一本字典而且它里面只有一个单词列表,你真的会把它称为字典吗?不,字典应该填充单词的定义。它应该告诉你这些词的意思。没有定义的字典只是声明这些单词存在于给定的语言中。所以声明说存在某种东西,定义给出了它的含义。在你的情况下:
// Declaration
void change(const int arr[], int size);
// Definition
void change(const int arr[], int size) {
// arr[0] = 5 - throws an error
int bar = 5;
arr = &bar;
}
现在在这里解释一下这个问题。没有数组参数类型这样的东西。任何数组类型参数都将转换为指针。所以change
的声明实际上与:
void change(const int arr*, int size);
当您执行arr = &bar;
时,您只需将bar
的地址指定给指针arr
。这对arr
指向的数组元素没有影响。为什么要这样?您只需更改arr
指向的位置,而不是指向的对象。实际上,您无法更改它指向的对象,因为它们是const
int
s。
答案 1 :(得分:5)
我知道我无法更改常量指针的值,但我可以更改其地址
罗。您无法更改任何地址。你的意思是你不能改变它指向的对象,但你可以改变指针本身吗?因为这就是事实 - 在指向const类型的情况下。但是,如果你有一个指向非const对象的const指针,那么你就不能改变指针,你只能改变它指向的任何东西。
附录(编辑):一个方便的经验法则是const
适用于其左侧的内容,除非左侧没有任何内容,因为它适用于其右侧的类型侧。例子:
const int *ptr;
int const *ptr; // these two are equivalent: non-const pointer to const int
int *const ptr; // const pointer to non-const int
int const *const ptr; // const pointer to const int
const int *const ptr; // same as above
然而,当函数结束并且我显示第一个元素时,它显示0 - 所以没有任何改变。
范围。 arr
是一个函数参数 - 因此它是函数的本地参数。无论你用它做什么,它都不会在功能之外有效。要实现您的目标,请将其声明为参考:
void change(const int *&arr, int size)
我被告知如果我想将两个指针类型传递给函数,const关键字将无法按预期工作。这是真的吗?
这取决于您的期望。如果你仔细阅读标准并有适当的期望,那么它确实会按预期工作。例子:
const int **ptr; // pointer to pointer to const int
int const **ptr; // same as above
const int *const *ptr; // pointer to const pointer to const int
等。您可以使用CDecl
生成更多这些时髦的声明答案 2 :(得分:1)
首先使用正确的术语,这实际上有助于理解:
const int *ptr = &foo;
这是指向常量整数的指针,而不是指向整数的常量指针。您无法更改指向的对象,但您可以更改指针以引用其他对象。
void change(const int arr[], int size);
该签名由编译器处理为void change( const int *arr, int size )
,我建议您将其键入,因为它可以减少混淆。在调用函数change(foo,2)
的地方,编译器会将参数foo
(类型为int[2]
)转换为类型&foo[0]
的{{1}}(两个转换都是通常将数组的衰减称为指针。)
现在,与第一个代码块一样,您无法更改指向的内存,但您可以更改指针以引用其他对象。
此外,在C ++中,默认模式是按值传递。 const int*
内的指针arr
是值change
的副本。在函数内部,您正在更改该副本,但这不会影响函数上下文之外的任何内容。
答案 3 :(得分:0)
const int *
正在做它应该做的事情,令你困惑的是它的目的。
将其视为指向readonly int的指针。你可以指向任何你想要的int,但无论如何它都会是readonly。
例如,您可以使用它来循环遍历const int
类型的数组。