【问题标题】:Changing constant pointer's address改变常量指针的地址
【发布时间】:2013-04-18 19:47:34
【问题描述】:

我试图理解一件事。

我知道我不能改变常量指针的值,但是我可以改变它的地址,如果我用下面的方式初始化一个指针:

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

【问题讨论】:

  • 拒绝学习新的编程语言 - 我喜欢这个网站:P
  • @userXXX 因为没有表现出足够的研究努力而投反对票。我喜欢懒惰的用户:P
  • @user2252786 您已经从网站上的四位顶级人物那里获得了全面的答案。
  • 这就是我说我喜欢这个网站的原因:P
  • 我很欣赏这个问题。我很高兴人们有足够的勇气提出这些“简单”的问题,即使他们被指责“搞砸”了“很多”事情。

标签: c++


【解决方案1】:

你把术语搞砸了,所以我要从那里开始,因为我认为这是你困惑的主要原因。考虑:

int x;
int* p = &x;

xintp 是“指向 int 的指针”。 修改p 的值 意味着将p 本身更改为指向其他地方。指针值是它保存的地址。此指针p 保存int 对象的地址。改变指针的值并不意味着改变int 对象。例如,p = 0; 将修改 p 的值。

除此之外,p 的地址并不是它所持有的地址。 p 的地址将是您执行 &amp;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 = &amp;bar; 时,您只是将bar 的地址分配给指针arr。这对arr 指向的数组元素没有影响。为什么要呢?您只是在更改 arr 指向的位置,而不是它指向的对象。事实上你不能改变它指向的对象,因为它们是constints。

【讨论】:

  • 关键字const 实际上与“常数”的含义不同(尽管它显然是从这个词派生的)。 const 表示“只读”。 constant 表达式是可以在编译时计算的。例如:const int r = rand(); 是合法的; r 的值显然不是常量,而是只读的。
  • 哇,我终于明白了很多c++中对我来说很难的东西,非常感谢!
  • @KeithThompson 是的,这是一个很好的观点。不过,将const 变量称为“常量变量”是很常见的。不过,我将编辑我的问题以消除歧义。
  • 我发现了一个非常好的记住这一点的方法是从变量名开始并移开。所以const int *p 是:p*int constint *const p; 是:pconst *int。这是right-left rule 的简单形式
【解决方案2】:

我知道我不能改变常量指针的值,但我可以改变它的地址

不。你不能改变任何东西的地址。你的意思是你不能改变它指向的对象,但你可以改变指针本身?因为这就是事实 - 在指向 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 生成更多这些时髦的声明

【讨论】:

  • “将 foo 声明为指向函数的指针 (void),返回指向指向 int 数组 3 的指针的指针”——难怪对于大多数新手来说,指针是 c++ 中的里程碑:D
  • @user2252786 嗯...不能从指向成员函数的指针开始,即返回指针到数组,可以这么说。
【解决方案3】:

首先是使用正确的术语,这实际上有助于理解:

const int *ptr = &foo;

这是一个指向一个常量整数的指针,而不是一个一个指向一个整数的常量指针。您无法更改指向的对象,但您可以更改指针以引用不同的对象。

void change(const int arr[], int size);

编译器将该签名处理为void change( const int *arr, int size ),我建议您这样输入,因为这样可以减少混淆。在调用函数change(foo,2) 的地方,编译器会将参数foo(类型为int[2])转换为类型为const int*&amp;foo[0](这两种转换通常称为decay数组的指针)。

现在就像在第一个代码块中一样,您无法更改指向的内存,但您可以更改指针以引用不同的对象。

此外,在 C++ 中,默认模式是按值传递。 change 内的指针arr 是值&amp;foo[0]副本。在函数内部,您正在更改该副本,但这不会影响函数上下文之外的任何内容。

【讨论】:

    【解决方案4】:

    const int *正在做它应该做的事情,让你困惑的是它的目的。

    将其视为指向只读 int 的指针。你可以指向任何你想要的 int,但无论如何它都是只读的。

    例如,您可以使用它来遍历 const int 类型的数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多