I want to have a pointer to a constant, and pass its address to a function that will increment it.
int f1(const int **ptr) {
int n = **ptr; //use pointer
(*ptr)++; //increment pointer
return n;
}
void foo(const int *data) {
const int *p = data;
const int n = f1(&p); //error: invalid conversion from ‘const int**’ to ‘int**’
//error: initializing argument 1 of ‘int LevelLoader::readWord(byte**)’
}
How do I declare the pointers?
Try
int f1(const int *& ptr) {
int n = *ptr;
++ptr;
return n;
}
void foo(const int *data) {
const int *p = data;
const int n = f1(p);
}
instead.
The error message indicates that LevelLoader::readWord doesn't take a const byte**.
This:
const int *data;
is a pointer to a constant integer. That means that you are not allowed to change the data pointed to by data. You can read and copy the data, but you can't do:
(*data) = 5;
That's illegal in C++ because it was declared const int *.
If you take the address of a const int *, you get a const int **, which is a pointer to a pointer to a constant integer. So you still cannot change the integer. Any attempt to do so will cause the compiler to complain.
If you want to be able to change the integer, then foo and f1 should not take const int * values. They should take int * values.
I don't want to modify the constant. I want to modify the pointer to it (p in foo())
So, you're given a pointer. And you want to increment the pointer. So just do so:
void foo(const int *data) {
const int *p = data;
data++;
}
You have incremented the pointer. This will not affect the caller to foo, as the pointer itself is copied by value.
Check again, this code is correct. It shouldn't generate the errors you claim.
EDIT: You fixed the void problem so answer amended accordingly.
Related
I know from this answer that a pointer const int** z is supposed to be read as
Variable z is [a pointer to [a pointer to a const int object]].
In my humble opinion, this would mean if z=&y then y should be a pointer to a const int object. However, the following code also compiles:
int x=0;
int const* y=&x;
const int** z=&y;
Why is an int const* object i.e. a const pointer to an int instead of a pointer to a const int acceptable to be the pointed object of z?
You are misunderstanding what the const refers to. A const always refers to the element to the left of it - unless it is the leftmost element itself, in which it refers to the element to the right.
This means that
int const * is a pointer to a const int, not a const pointer to int as you think. To get that, you would have to write int * const
int const * and const int * are two ways of writing exactly the same: a pointer to a const int.
You get it right if you read declarations from right to left. If const is the leftmost element, add a "that is" before it when reading. Ex:
const int *: pointer to int that is const.
int const *: pointer to const int.
int * const: const pointer to int.
const int * const: const pointer to int that is const.
int const * const: const pointer to const int.
Note that 1/2 are the same, and 4/5 are the same. 1 and 4 are called "west const" since const is on the west/left side, while 2 and 5 are called "east const".
Why is an int const* object i.e. a const pointer to an int
No.
int const * and const int * are the same type.
People sometimes prefer writing int const * because it reads right-to-left as "pointer to a const int", whereas const int * really reads as "pointer to an int (which is const)".
A const pointer to an int is int * const.
Try it:
int a = 42;
const int * y = &a;
int const * z = &a;
*y = 24; // compile error assigning to const
*z = 24; // compile error assigning to const
int b = 0;
y = &b;
z = &b; // re-pointing non-const pointers is fine
*z = 1; // still a compile error
int * const x = &a;
*x = 24; // fine, assigning via pointer to non-const
x = &b; // error reassigning a const pointer
have some issues with const qualifier.
I tried to do smth like this:
int a{ 3 };
int *p{ &a };
//const int **pp{ &p }; // FIXME: Compiler demands that p must have a const int *type
const int *const* pp{ &p }; // works here but it means, that I have a pointer to the const pointer to the const value
*pp = nullptr; // doesn't work cause of upper type
Results in error:
<source>:8:5: error: read-only variable is not assignable
*pp = nullptr; // doesn't work cause of upper type
~~~ ^
BUT: if i deal with new it works funny
const int **pp1{ new const int* {&p} }; // Here I have a poiner to pointer to const int, so I can change it
*pp1 = nullptr; // works
So, why does compiler demands a const int* const*? Compiler - MSVC, standart - c++17
UPD:
const int *p{ nullptr };
const int **pp{ &p }; // My intention
*pp = nullptr; // it works cause pointer non - const
But how can i get same result without const in const int *p?
There are cases where this site https://cdecl.org/ for C syntax can also help with C++. For this:
const int *const* pp
it tells me:
declare pp as pointer to const pointer to const int
For this:
const int **pp1
it tells me:
declare pp1 as pointer to pointer to const int
Let's use that....
*pp = ... // ERROR !
When you dereference pp then you get a "const pointer to const int" (because pp is "pointer to const pointer to const int"). You cannot assign to a const whatever. What counts it the top level const!
*pp1 ... // OK !?!
When you dereference pp1 you get a "pointer to const int" (because pp1 is a "pointer to pointer to const int"). A pointer to const int is not constant. What counts is the top level const! It points to a const int but the pointer itself is not const.
Conclusion: The difference between your two versions is not the use of new but the type of the pointer that you dereference (and then try to assing to the pointee).
I have the following base code:
Base Code
int main()
{
int i = 1;
const int* p = &i;
int* q = &i;
test_ptr(p);
test_ptr(q);
}
Can anyone explain why the first and third example work with the above base code, but the second one doesn't?
Example Implementation test_ptr()
Example 1 works. This works because function with pointer to const int will also accept a pointer to non-const int (but not the other way around)
void test_ptr(const int* p) // pointer to const int
{
}
Example 2 doesn't work. I don't really understand why. It is still a pointer to const int, but passed as a reference. This doesn't align with my understanding about how references work. It fails when I pass a non-const pointer to the function.
void test_ptr(const int*& p) // reference to pointer to const int
{
}
Example 3 works again and I am completely lost. So if case 2 does not work, why does it work again if I express the int* as a typedef?
typedef int* int_ptr;
void test_ptr(const int_ptr& p) // like case 2 but int* expressed as typedef
{
}
This also happens when I use pointer-to-pointer instead of reference-to-pointer.
Edit: Example 3 needs a different main function to make use of the typedef:
int main()
{
int i = 1;
const int_ptr p = &i; // use typedef here
int_ptr q = &i; // use typedef here
test_ptr(p);
test_ptr(q);
}
Example 2:
void test_ptr(const int*& p);
This works for const int* but not int* because the conversion from int* to a const int* implies a temporary and binding to a temporary has to be done using a const& for life extension to kick in.
Example 3 (when using the first main version):
typedef int* int_ptr; // or: using int_ptr = int*;
void test_ptr(const int_ptr& p);
This is the same as both of these:
void test_ptr(int_ptr const& p);
void test_ptr(int* const& p);
const is applied to the new type from right to left so it's not the int that is const, it's the pointer. The function will therefore accept int*, but not const int* since the function is allowed to change the int:s according to its signature.
The function that would accept both int* and const int* should have one of these equivalent signatures:
void test_ptr(const int* const& p);
void test_ptr(int const* const& p);
Disclaimer: I'm very unsure about the wording used in this answer
I notice that this is a valid prototype while reading through the ANSI C grammar spec from 1985 published by Jeff Lee and I compiled a function with this signature. What exactly might a function with this prototype return? What would a simple body of this function look like?
The return type is a pointer to const pointer to int. Read the declaration from right to left, and it will make things much easier. My favourite tutorial for complicated pointer declarations: http://c-faq.com/decl/spiral.anderson.html
Some (quite artificial) example:
#include <iostream>
int* const * foo(int x)
{
static int* const p = new int[x]; // const pointer to array of x ints
for(int i = 0; i < x ; ++i) // initialize it with some values
p[i] = i;
return &p; // return its address
}
int main()
{
int* const* p = foo(10); // our pointer to const pointer to int
//*p = nullptr; // illegal, cannot modify the dereferenced pointer (const)
std::cout << (*p)[8]; // display the 8-th element
}
foo is a function that takes an int parameter and returns a pointer to a const pointer to an int.
the below code doesn't compile
void aaa(const int **a) {
}
int *a[] = {new int[2]};
aaa(a);
I got "cannot convert parameter 1 from 'int [1]' to 'const int *" in VS2010 and similar error in gcc
when I change my declaration to:
int const *a[] = {new int[2]};
or
const int *a[] = {new int[2]};
it compiles, but I don't understand why it doesn't accept a non const variable declaration
The type of a is int*[]; the type you want is int const**.
int*[] converts to int**, but this will not convert implicitly to
int const**. Consider the following code to understand why:
static int const ci = 42;
void aaa( int const** out )
{
*out = &ci;
}
int
main()
{
int* pa;
aaa( &pa ); // NOT LEGAL, because...
*pa = 0; // would now change ci
std::cout << ci << std::endl;
return 0;
}
As you can see, allowing this conversion would break const without
requiring a cast.
Depending on what you are doing, you might want to use:
void aaa( int const* const* out );
The implicit conversion of int** to int const *const * is legal.
(Otherwise, you'll need a const_cast somewhere, to tell the compiler
that you know what you're doing, and that it isn't really a problem.)
The function aaa expects a pointer-to-pointer-to-constant-int.
Your variable a is a pointer-to-pointer-to-int.
It is an error to assign the latter to the former.
both int const *a[] and const int *a[] is actually the same thing, matching the signature of aaa. If you tried int * const a[], that would be a different type (pointer-to-constant-pointer-to-int) and you would trigger the type error again.
If you want your function aaa to take a constant-pointer-to-pointer-to-int, you need to write aaa(int ** const a), but having a const-ness on parameter values has actually no effect on what you can call with.
Edit: "But isn't constness added implicitly - done with an implicit cast? (Which is the actual question)"
Constness can be implicitly added to the value you are passing, e.g.
void aaa(const int a) {}
int b=5;
aaa(b);
... or one level pointer
void aaa(const int* a) {}
int *b=new int;
aaa(b);
... but cannot be added deeper. For example this is invalid:
void aaa(const int** a) {}
int* b=new int;
int** c=&b;
aaa(c);
I think James Kanze explains it much better in his answer.