为什么创建指向C中的const的指针的指针是非法的?

时间:2019-01-15 06:43:02

标签: c pointers memory

这是常见的“分配时丢弃的const限定词”错误的来源。但是,我不明白为什么这样做是非法的?

考虑此代码,

int sum_array(const int *a, int n){
   int sum, *i;
   sum = 0;
   for(i = a; i<a+n; i++)
       sum += *i;
   return sum;
}

很明显,我可以使用i = 0并比较a + i < a+n来执行相同的操作;但是,对我而言,为什么简单地将一个变量的地址复制到另一个变量中是非法的?

通常,const变量指示变量的值不能更改。例如。 const int x = 7,这里我们声明x的值不应从7更改。

但是,使用const指针创建“电位”来更改变量也是非法的。即i = a不会改变指向的值,真正的“非法”值是* i = 0,但是,i = a仍然是非法的,因为它使我们有可能改变a。

我知道您可以通过“因为语言是通过这种方式创建的”来回答我,我只是想知道这里是否缺少任何内容。

3 个答案:

答案 0 :(得分:2)

const的主要目的是争取编译器的帮助,以确保您不会意外修改给定的对象。为此使用类型系统。您实际上可以通过编写显式强制转换来规避它。但通常您不想要那个,因为如果您想要那个,那通常意味着您并不真正希望const开始。

答案 1 :(得分:2)

const有两个用途:

  1. 在函数调用协定中(此处为int sum_array(const int *a, int n)),这意味着函数将不使用参数a来修改a所指向的内容( a不是常数,它是指向被认为是常数的事物的指针。然后,调用者知道不会通过调用修改数据,并且编译器必须尽可能执行以下操作:

  2. 在函数定义中,然后保护实现器,防止意外修改a所指向的内容。即。如果他尝试编写类似*a = someValue;的内容,则编译器将因违反合同而提出投诉。但是,这也验证了该合同是否得到了尊重。因此,来自a的任何派生变量可能会提供对相同数据的访问权限,必须将其视为const,否则将违反合同。然后写入int *p = a显然是违反此规定的,因为p不是指向const数据的指针,这将使您可以写入*p = someValue来修改数据。

请注意const并不意味着数据是const,而只是通过指针禁止修改数据。然后:

const int *a...
int *p = a;

被禁止,但是

int *a...
const int *p = a;

是正确的,因为在这种情况下,您有一个指针,可以通过它修改数据,并构造一个派生的指针,该指针限制通过派生的指针访问同一数据。数据可以通过a修改,但不能通过p修改。限制从来没有危险,开放可以。

当然,您可以通过强制转换(强制删除const)来强制执行危险的派生操作,但我不建议这样做。 建议,如果您想这样做,请避免自己动手,再想一想,如果此后您确实想这样做,那就让它挂一整夜,然后第二天再考虑一下。 ..食谱是:

const *a...;
int *p = (int *)a; // "seriously refrain" advice

答案 2 :(得分:1)

该问题提出,给定const int *a,可以允许int *i = a;,而不允许随后的*i = 0;(“非法”)。

这是不可行的,因为它要求编译器跟踪i中有关数据源的信息。在出现*i = 0;的那一点上,编译器必须知道i包含一个从a初始化而来的值。

我们可以用非常简单的代码来做到这一点。但是考虑到代码可能非常复杂,带有循环,分支和函数调用。在*i = 0;出现的地方,编译器通常无法知道i是否仍然保存着a的地址或已更改为其他地址。 (我希望这等同于暂停问题,因此从逻辑上讲是不可能的)。

C使用类型来管理它。如果a是指向const的指针,则只能将其分配给指向const的指针(除非被显式强制转换覆盖)。因此,i必须是指向const的指针,这样编译器才能知道它指向的内容不应该被修改。