简体   繁体   English

C ++指向const指针的指针

[英]C++ pointer to const pointer

I'm still confusing where to place const in pointers with more than one indirection. 我仍然困惑在哪里将const放在具有多个间接的指针中。 Can someone clarify? 有人可以澄清吗?

Eg right now I need a pointer to const pointer, meaning such a variable int **ppTargets that I can assign int *pTargets variable to it, like: 例如,我现在需要一个指向const指针的指针,这意味着我可以将int *pTargets变量分配给它的变量int **ppTargets ,如:

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

The above code lacks const . 上面的代码缺少const So in foo I want pTargets to point to constant memory and be unassignable after initialization (so that one cannot write eg pTargets++ ), that would be int const *const pTargets = /* assigned once */ . 所以在foo我希望pTargets指向常量内存并且在初始化后无法分配(因此无法写入例如pTargets++ ),这将是int const *const pTargets = /* assigned once */ Next I want to declare ppTargets that ppTargets itself can be assigned, but then *ppTargets can only be read. 接下来,我要声明ppTargetsppTargets本身可以分配,但随后*ppTargets只能读取。

In the other words, in the caller code I want: 换句话说,在我想要的来电代码中:

int const* pTargets;
foo(&pTargets);

I tried to declare foo as follows, but get an error you cannot assign to a variable that is const : 我尝试按如下方式声明foo ,但是得到一个错误, you cannot assign to a variable that is const

int foo(int *const *const ppTargets)

I always read C/C++ definitions from the right-most variable name leftwards. 我总是从左边最右边的变量名读取C / C ++定义。

So: 所以:

  • const char *p;

    p is a pointer to a char that is const p是指向constchar的指针

    So p can be modified, but *p can't. 所以p可以修改,但*p不能。

  • const char * * const p = &a;

    p is a const pointer to a pointer to a char that is const . p是一个const指向指针的指针到一个charconst

    So p cannot be modified (hence I initialised it); 所以p不能被修改(因此我初始化它); *p can; *p可以; but **p can't. **p不能。

[EDIT - added arrays for completeness] [编辑 - 为完整性添加了数组]

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

    p is a 4-element array of const pointers to... p是一个4元素的const指针数组...

What you're looking for is int const * const * ppTarget . 你要找的是int const * const * ppTarget No, wait, you're looking for int const ** const ppTarget . 不,等等,你正在寻找int const ** const ppTarget No no, it's int * const * const * ppTarget . 不,不,它是int * const * const * ppTarget

Chances are one of them is correct (I'm betting the first one). 机会是其中之一是正确的(我打赌第一个)。 However, you don't want people reading your code to guess what it is you mean. 但是,您不希望人们阅读您的代码来猜测您的意思。 It's just too confusing. 这太令人困惑了。 C++ can do that to you. C ++可以帮到你。

What you should do, is use typedef s to make sure people who read the code understand what you want. 你应该做的是使用typedef来确保阅读代码的人理解你想要的东西。

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

Since pTargets is a const int * , its address is a const int ** , which is the type you want for the function parameter: 由于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;
}

EDIT: 编辑:

If the variable to set is defined as int const * const pTargets; 如果要设置的变量定义为int const * const pTargets; , the only way to set it is when it is initialized. ,设置它的唯一方法是初始化时。 You can then do this instead: 然后你可以这样做:

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;
}

So I want pTargets to point to constant memory and be const itself, that would be int const *const pTargets = /* assigned once */ . 所以我希望pTargets指向常量内存并且是const本身,这将是int const *const pTargets = /* assigned once */ Next I want to declare ppTargets that ppTargets itself can be assigned, but then *ppTargets can only be read. 接下来,我要声明ppTargetsppTargets本身可以分配,但随后*ppTargets只能读取。

Unfortunately, that does not make sense. 不幸的是,这没有意义。 Your example code assigns to *ppTargets , as indeed appears to be the primary objective of function foo() . 您的示例代码分配给*ppTargets ,实际上似乎是函数foo()的主要目标。 If *ppTargets can be assigned once, then it can be assigned again. 如果*ppTargets可以分配一次,则可以再次分配。

It is unclear why you want foo() 's local pTargets to be const , as opposed to just not modifying it, but you may assign a const value to an object of the corresponding non- const -qualifed type. 目前还不清楚为什么你希望foo()的本地pTargetsconst ,而不是只修改它,但是你可以为相应的非const -qualifed类型的对象赋一个const值。 Thus, what you're actually looking for might be 因此,你真正想要的是什么

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

And that seems to be consistent with your intended usage: 这似乎与您的预期用法一致:

In the other words, in the calling code I want: 换句话说,在我想要的调用代码中:

 int const* pTargets; foo(&pTargets); 

For any type T , the type of a pointer to a T can be spelled T * . 对于任何类型T ,指向T的指针的类型可以拼写为T * In particular, the type of this &pTargets is int const ** (look familiar?), and that's the appropriate type for a function parameter through which the function should be able to set the value of the caller's pTargets . 特别是,这个&pTargets的类型是int const ** (看起来很熟悉?),这是函数参数的合适类型,函数应该通过它来设置调用者的pTargets的值。

And again, calling foo() to have it to set the value of the caller's pTargets seems to be exactly the point. 再次,调用foo()让它设置调用者的pTargets的值似乎正是重点。 If foo() were supposed to be prevented from doing that, then the ideal approach would be to pass pTargets itself (by value), instead of passing its address and wrangling const qualifiers. 如果假设foo()被禁止这样做,那么理想的方法是传递pTargets本身(通过值),而不是传递它的地址和争论const限定符。

So I want pTargets to point to constant memory and be const itself 所以我希望pTargets指向常量内存并且是const本身

Next I want to declare ppTargets that ppTargets itself can be assigned, but then *ppTargets can only be read. 接下来我想声明可以分配ppTargets本身的ppTargets,但是* ppTargets只能被读取。

For clarity, let int const * be Ptr and let int const * const (ie Ptr const ) be CPtr . 为清楚起见,让int const *Ptr ,让int const * const (即Ptr const )为CPtr

Just like you correctly wrote int const *const pTargets (ie CPtr ) when you wanted a const pointer to const int, so too when you want a non-const pointer to const pointer to const int (ie the type of &pTargets ie CPtr* ), you need int const *const * ppTargets . 就像你想要一个指向const int的const指针一样正确地编写了int const *const pTargets (即CPtr ),当你想要一个指向const int的const指针的非const指针时也是如此(即&pTargets的类型即CPtr* ) ,你需要int const *const * ppTargets Note that a Ptr* will implicitly convert to CPtr* . 请注意, Ptr*将隐式转换为CPtr*

Your attempted int *const *const ppTargets would be a const pointer to const pointer to non-const int. int *const *const ppTargets将是指向非const int的const指针的const指针。 Since the type is a const pointer, it cannot be assigned which contradicts with your requirement. 由于类型是const指针,因此无法分配与您的要求相矛盾的类型。


More generally, a simple rule of thumb is to read C pointer type declarations from right to left, and constness applies to the left of the keyword (except when it is the leftmost token in which case it applies to the right). 更一般地说,一个简单的经验法则是从右到左读取C指针类型声明,并且constness应用于关键字的左侧(除非它是最左边的标记,在这种情况下它适用于右边)。


Now that we've found a type that meets your stated requirements, let me bring your attention to your implementation of foo which does *ppTargets = pTargets . 现在我们已经找到了符合您声明要求的类型,让我将您的注意力集中在foo的实现上,它实现了*ppTargets = pTargets This contradicts with the requirement of " *ppTargets can only be read ". 这与*ppTargets只能读 ”的要求相矛盾。

After the inputs from the others, especially the Clockwise/Spiral rule by @Mahesh , as well as some debate, I understood how to read and write such things easily. 在其他人的输入,尤其是@Mahesh的顺时针/螺旋规则以及一些争论之后,我理解了如何轻松地阅读和编写这些内容。

We should look at what can and what cannot be modified. 我们应该看看哪些可以和哪些不可修改。 So consider the declaration without const s: int **ppTargets . 所以考虑没有const的声明: int **ppTargets We want that ppTargets cannot be modified itself, while *pTargets can be modified, while **pTargets cannot be modified. 我们希望ppTargets不能自行修改,而*pTargets可以修改,而**pTargets不能修改。

Then, apply these observations right to left: int const * * const ppTargets . 然后,从右到左应用这些观察: int const * * const ppTargets

The rightmost const says that ppTargets++ is not possible. 最右边的const表示ppTargets++是不可能的。

Then absence of const in the middle says that (*ppTargets)=pTargets is possible. 然后在中间缺少const表示(*ppTargets)=pTargets是可能的。

Then another, leftmost const says that (**ppTargets)++ is not possible. 然后另一个最左边的const表示(**ppTargets)++是不可能的。

The basic formalization for indirection is in my view 在我看来,间接的基本形式化

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

where <pointer> is itself a memory zone. 其中<pointer>本身就是一个内存区域。 For double indirection, the expression becomes 对于双重间接,表达式变为

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

What makes things more difficult to understand is the possibility of placing qualifiers (eg. read-only ) before OR after <memory zone> on the left size of * symbol. 使事情更难以理解的是在*符号的左侧大小上的<memory zone>之前或之后放置限定符(例如, read-only )的可能性。 On the right side of * symbol, the qualifier(s) can be placed only before <pointer> . *符号的右侧,限定符只能放在<pointer>之前。

In C++ read-only means const and read-write is the implicit qualifier. 在C ++中, read-only意味着constread-write是隐式限定符。

Thus we can have: 因此我们可以:

  • char* p read-write pointer to read-write char memory zone char* p读写指针读写char内存区
  • const char* p read-write pointer to read-only char memory zone const char* p读写指针只读 char内存区
  • char* const p read-only pointer to read-write char memory zone char* const p 只读指针读写char内存区
  • const char* const p read-only pointer to read-only char memory zone const char* const p 只读 char内存区域的只读指针

Then we can move const after the basic type resulting equivalent declarations: 然后我们可以在基本类型之后移动const得到等效声明:

  • char const* p read-write pointer to read-only char memory zone char const* p读写指针只读 char内存区
  • char const* const p read-only pointer to read-only char memory zone char const* const p 只读指针只读 char内存区

Pointer conversion is allowed having equal qualifier or less restrictive qualifier in source pointer for each level of indirection comparing to destination pointer. 对于每个间接级别与目标指针相比,允许指针转换在源指针中具有相等的限定符或限制较少的限定符。

As result the following cases are valid: 因此,以下情况有效:

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);
}

In your case the leftmost qualifier of the pointer passed as argument ( &pTargets ) is not equal or less restrictive than the leftmost qualifier of the pointer from foo function. 在您的情况下,作为参数( &pTargets )传递的指针的最左边限定符与foo函数中指针的最左边限定符不相等或更少限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM