改变常量指针的地址

时间:2013-04-18 19:47:35

标签: c++

我试图理解一件事。

我知道我无法更改常量指针的值,但如果我按以下方式初始化指针,我可以更改其地址:

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关键字将无法按预期工作。真的吗?如果是这样,那么原因是什么?

4 个答案:

答案 0 :(得分:12)

你正在搞这个术语很多,所以我要从那里开始,因为我认为这是你混淆的一个主要原因。考虑:

int x;
int* p = &x;

xintp是“指向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类型的数组。