C++指向常量指针的指针

C++ pointer to const pointer

本文关键字:指针 常量 C++      更新时间:2023-10-16

我仍然混淆了在具有多个间接寻址的指针中放置const的位置。有人可以澄清一下吗?

例如,现在我需要一个指向 const 指针的指针,这意味着我可以为其分配int *pTargets变量int **ppTargets这样的变量,例如:

int foo(int **ppTargets) {
int *pTargets = /* calculate here */;
*ppTargets = pTargets;
return 37; // just e.g.
}

上面的代码缺少const。所以在foo我希望pTargets指向常量内存并且在初始化后不可分配(这样就不能写例如pTargets++),那将是int const *const pTargets = /* assigned once */.接下来,我想声明ppTargetsppTargets本身可以分配,但*ppTargets只能读取。

换句话说,在我想要的调用方代码中:

int const* pTargets;
foo(&pTargets);

我试图按如下方式声明foo,但you cannot assign to a variable that is const出现错误:

int foo(int *const *const ppTargets)

我总是从最右边的变量名向左读取 C/C++ 定义。

所以:

  • const char *p;

    p是指向constchar的指针

    所以p可以修改,但*p不能。

  • const char * * const p = &a;

    p是一个指向constchar的指针的const指针。

    所以p不能修改(因此我初始化了它);*p可以;但**p不能。

[编辑 - 为完整性添加了数组]

  • const char * * const p[4] = { &a, &b, &c, &d };

    p是一个 4 元素const数组

    ,其中包含指向...

您要查找的是int const * const * ppTarget。不,等等,你正在寻找int const ** const ppTarget.不不,这是int * const * const * ppTarget.

其中之一可能是正确的(我打赌第一个)。但是,您不希望阅读您的代码的人猜测您的意思。实在是太混乱了。C++可以这样对你。

你应该做的是使用typedef来确保阅读代码的人理解你想要什么。

typedef const int *CINT_PTR;
CINT_PTR pTarget = ....;
CINT_PTR *ppTarget = &pTarget;

由于pTargets是一个const int *,它的地址是一个const int **,这是你想要的函数参数类型:

int foo(const int **ppTargets)
{
int *pTargets = malloc(sizeof(int)*4);
pTargets[0] = 1;
pTargets[1] = 2;
pTargets[2] = 3;
pTargets[3] = 4;
*ppTargets = pTargets;
return 37;
}
int main()
{
int const *pTargets;
foo(&pTargets);
return 0;
}

编辑:

如果要设置的变量定义为int const * const pTargets;,则设置它的唯一方法是在初始化时。 然后,您可以改为执行以下操作:

const int *foo2()
{
int *pTargets = malloc(sizeof(int)*4);
pTargets[0] = 1;
pTargets[1] = 2;
pTargets[2] = 3;
pTargets[3] = 4;
return pTargets;
}
int main()
{
int const * const pTargets = foo2();
return 0;
}

所以我希望pTargets指向常量内存并const它本身, 那将是int const *const pTargets = /* assigned once */.下一页 I 想要声明ppTargets可以分配ppTargets本身,但是 那么*ppTargets只能被读取。

不幸的是,这是没有意义的。 您的示例代码分配给*ppTargets,这确实似乎是函数foo()的主要目标。 如果*ppTargets可以分配一次,则可以再次分配。

目前还不清楚为什么你希望foo()的局部pTargetsconst,而不是只是不修改它,但你可以为相应的非const-qualifed类型的对象分配一个const值。 因此,您实际上正在寻找的可能是

int foo(int const **ppTargets) {
int const * const pTargets = /* calculate here */;
*ppTargets = pTargets;
return 37; // just e.g.
}

这似乎与您的预期用途一致:

换句话说,在我想要的调用代码中:

int const* pTargets;
foo(&pTargets);

对于任何类型的T,指向T的指针的类型可以拼写为T *。 特别是,此&pTargets的类型是int const **(看起来很熟悉?),这是函数参数的适当类型,函数应该能够通过该类型设置调用方pTargets的值。

再说一次,调用foo()让它设置调用方pTargets的值似乎正是重点。 如果应该阻止foo()这样做,那么理想的方法是传递pTargets本身(按值),而不是传递其地址并争论const限定符。

所以我希望 pTarget 指向常量内存并成为常量本身

接下来我想声明 ppTargets 可以分配 ppTargets 本身,但随后只能读取 *ppTargets。

为了清楚起见,int const *Ptr,让int const * const(即Ptr const)CPtr.

就像你正确写int const *const pTargets一样(即CPtr),当您想要一个指向 const int 的 const 指针时,当您想要一个指向 const int 的 const 指针的非 const 指针时也是如此(即&pTargets的类型,即CPtr*),你需要int const *const * ppTargets。请注意,Ptr*将隐式转换为CPtr*

您尝试的int *const *const ppTargets将是一个常量指针,指向常量指针到非常量整数。由于类型是常量指针,因此无法分配与您的要求相矛盾的赋值。


更一般地说,一个简单的经验法则是从右到左读取 C 指针类型声明,恒常性适用于关键字的左侧(除非它是最左侧的标记,在这种情况下它适用于右侧)。


现在我们已经找到了满足您声明要求的类型,让我提请您注意您对*ppTargets = pTargetsfoo实现。这与"*ppTargets只能阅读"的要求相矛盾。

在其他人的输入之后,特别是顺时针/螺旋规则 @Mahesh 以及一些辩论,我明白了如何轻松阅读和编写这些东西。

我们应该看看什么可以修改,什么不能修改。因此,请考虑不带consts:int **ppTargets的声明。我们希望ppTargets本身不能修改,而*pTargets可以修改,而**pTargets不能修改。

然后,从右到左应用这些观察结果:int const * * const ppTargets.

最右边的constppTargets++是不可能的。

然后中间没有const说明(*ppTargets)=pTargets是可能的。

然后另一个最左边的const(**ppTargets)++是不可能的。

在我看来,间接寻址的基本形式化是

(read-only|read-write) <memory zone> * (read-only|read-write) <pointer>

其中<pointer>本身就是一个记忆区。 对于双向间接,表达式变为

(read-only|read-write) <memory zone> * (read-only|read-write) <memory zone/pointer-level2> * (read-only|read-write) <pointer-level1>

使事情更难以理解的是放置限定符的可能性(例如。read-only) 在符号左侧大小的 OR 之后<memory zone>*。在符号*右侧,限定符只能放在<pointer>之前。

在C++read-only表示常量read-write是隐式限定符。

因此,我们可以拥有:

  • char* p读写char内存区域的读写指针
  • const char* p指向只读char内存区域的读写指针
  • char* const p指向读写char内存区域的只读指针
  • const char* const p指向只读char内存区域的只读指针

然后我们可以在基本类型结果等效声明之后移动const

  • char const* p指向只读char内存区域的读写指针
  • char const* const p指向只读char内存区域的只读指针

与目标指针相比,允许指针转换在每个间接寻址级别的源指针中具有相等的限定符或限制较少的限定符。

因此,以下情况有效:

int foo(const int* const* const p);
{// equal leftmost qualifier
const int* p = nullptr;
const int** p1 = &p; // 2nd and 3rd qualifiers are less restrictive
foo(p1);
const int* const* p2 = &p; // 2nd qualifier is equal, 3rd one (implicit read-write) is less restrictive
foo(p2);
const int* const* const p3 = &p; // 2nd and 3rd qualifiers are equal
foo(p3);
}
{// less restrictive leftmost qualifier of p
int* p = nullptr;
int** p1 = &p; // 2nd and 3rd qualifiers are less restrictive
foo(p1); 
int* const* p2 = &p; // 2nd qualifier is equal, 3rd one (implicit read-write) is less restrictive
foo(p2);
int* const* const p3 = &p; // 2nd and 3rd qualifiers are equal
foo(p3);
}

在您的情况下,作为参数传递的指针最左边的限定符 (&pTargets) 不等于或小于函数中指针最左边foo限定符的限制。