why cant int** be converted to const int** in c++ [duplicate] - c++

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
why isnt it legal to convert (pointer to pointer to non-const) to a (pointer to pointer to a const)
Hi I have the following code, but cannot wrap my head around why this doesn't work - I get an error saying "cannot convert from int** to const int**". However, if I change the first argument of printValues to be "const int *const * myArray", it all works fine. I know I probably shouldn't be using the one below anyway, but I don't understand why it doesn't compile at all. Can you not have a pointer to a pointer to a constant integer without declaring it constant in main()?
#include <iostream>
int printValues(const int ** myArray, const long nRows, const long nCols)
{
for (long iRow = 0; iRow < nRows; iRow++)
{
for (long iCol = 0; iCol < nCols; iCol++)
{
std::cout << myArray[iRow][iCol] << " ";
}
std::cout << "\n";
}
return 0;
}
int main()
{
const long nRows = 5;
const long nCols = 8;
int** myArray = new int* [nRows];
for (long iRow = 0; iRow < nRows; iRow++)
{
myArray[iRow] = new int [nCols];
}
for (long iRow = 0; iRow < nRows; iRow++)
{
for (long iCol = 0; iCol < nCols; iCol++)
{
myArray[iRow][iCol] = 1;
}
}
printValues(myArray, nRows, nCols);
return 0;
}

int ** is: "a pointer to a pointer to an integer".
const int ** is: "a pointer to a pointer to a constant integer".
A far-fetched analogy:
a note that describes the location of another note that describes the location of a jar
a note that describes the location of another note that describes the location of a closed jar
You can only put a cookie inside a jar that is not closed.
Now, think of replacing the second note with a photocopy of the first note. Do you have any guarantee that the ultimate jar that this note points to will be closed and cannot accept any cookies? The use of const is a contract and you cannot meet this contract by going through the indirection of two references.

Basically, this is because it's possible via changing the level of indirection and other valid, non-const-violating semantics that you can work around the const if it's only on the top level. You have to add const on more than one level for the const to be actually safe.

Edit:
You are violating const-correctness. By saying you want a pointer-to-a-pointer, you are setting yourself up by allowing the original const object to be modified. Const is a contract. By allowing this to happen without a cast, you are setting yourself up to allow a const object to be modified later on.

Related

Why can a function take (int *&) as a parameter? [duplicate]

This question already has answers here:
Difference between pointer to a reference and reference to a pointer
(6 answers)
Closed 4 years ago.
Following is a code to split an array. The
first output array will contain the input array entries in between the given two indices and the second
output array will contain the rest of the entries.
void splitArray(int *arr, int size, int ind1, int ind2,
int *&first, int &firstSize, int *&second, int &secondSize){
firstSize = ind2 - ind1 + 1;
secondSize = size - firstSize;
first = new int[firstSize];
second = new int[secondSize];
for (int i = 0; i < ind1; i++)
second[i] = arr[i];
for (int i = ind1; i <= ind2; i++)
first[i - ind1] = arr[i];
for (int i = ind2 + 1; i < size; i++)
second[i - firstSize] = arr[i];
}
The thing I can understand why it has parameters like int *&first and int *&second, arent they are same as just int first and int second but in this code they are used as pointers to dynamic arrays.
T *&foo declares a reference to a pointer to T. Don't confuse the ampersand in declarations and definitions with the address-of operator.
References to pointers are used if the called function needs to be able to modify the value of the pointer passed to it:
void bar(int *&ptr) {
ptr = 42; // change the value of the pointer (pseudo ... 42 is most likely
*ptr = 42; // change the value of the pointee not a valid pointer value)
}
// ...
int *foo = nullptr;
bar(foo);
// foo == 42;
Hint: Read types from right to left: T *& --> &* T --> reference (&) to pointer (*) to type T.

Trying to create a 3D vector that will hold pointers to a pointers to unsigned char

Im trying to create a vector that will hold pointers to other pointers to unsigned chars. my vector definition is as follows
std::vector<unsigned char**> slices; // data for each slice, in order
//populating vector
unsigned char a = 1;
for (int k = 0; k < size; k++)
{
unsigned char ** tempSlice = new unsigned char*;
slices.push_back(tempSlice);
for (int y = 0; y < height; y++)
{
unsigned char * tempY = new unsigned char;
slices[k].push_back(&tempY);
for (int x = 0; x < width; x++)
{
slices[k][y][x] = a;
}
}
}
the error i get however is something allong the lines of:
error request for member ‘push_back’ in ‘((VolImage*)this)-
>VolImage::slices.std::vector<_Tp, _Alloc>::operator[]<unsigned char**,
std::allocator<unsigned char**> >(((std::vector<unsigned
char**>::size_type)k))’, which is of non-class type
‘__gnu_cxx::__alloc_traits<std::allocator<unsigned char**> >::value_type
{aka unsigned
I dont know what im doing wrong.
Also, if anyone could have a look at my destructor method to see if im on the right track:
VolImage::~VolImage()
{
std::cout<<"Destructor"<<std::endl;
//deconstructing the vector of slices
int size = slices.size();
for (int k = 0; k < size; k++)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
delete &slices[k][y][x];
}
delete[] slices[k][y];
}
delete[] slices[k];
}
delete[] &slices;
}
You have an error already here:
slices[k].push_back(&tempY);
Which is explained by the error message, but it's well accepted that gcc's C++ error messages aren't the simplest to parse.
error request for member ‘push_back’ in ‘((VolImage*)this)-
VolImage::slices.std::vector<_Tp, _Alloc>::operator[] >(((std::vector::size_type)k))’, which is of non-class type
‘a__gnu_cxx::__alloc_traits >::value_type
{aka unsigned
This is telling you that you are requesting a member function ~push_back~ on (big complicated construct) which is of non-class type (more hard to parse stuff) {aka unsigned char*}
And there's youre problem: slices[k] gives you a reference to an ~unsigned char*~, and char ptrs don't have a member function push_back.
Looking at the rest of your code, it looks like you want to have a two dimensional array of char**'s. One way to accomplish this is a vector of vectors:
std::vector<std::vector<char**>> slices;
This will give you a two-d vector, and will allow your second push_back to succeed, but will cause your first push_back to fail, because you'll be trying to push a char** into a container of containers. Later on you'll fail again because you're treating a two-d vector as a three-d vector.
If you don't mind a little coaching, you're trying to jump too many levels of abstraction at a time. First experiment with vectors of char*'s, then maybe vectors of char**'s and then maybe make it into a 3D vector. That way you'll only have one class of errors (conceptual and compiler) to deal with at one time.
This will be a useful exersize as you'll get a better understanding of pointers and vectors in C++. When you are done with the learning process, you may find a different container more suitable for this purpose. For example Boost multi_array
From your comment
I understand you are meant to use a vector of char** as a 3D array... So in this case the char** has to be understood as a two dimensional array of characters ...see here for a description. Then you make a vector of these two-d arrays - here's an example:
int main()
{
std::vector<unsigned char**> slices; // data for each slice, in order
const unsigned int size =5;
const unsigned int rows =2;
const unsigned int cols =3;
for (int k = 0; k < size; k++)
{
unsigned char** twoD = new unsigned char*[rows];
for(int i = 0; i < rows; ++i)
twoD[i] = new unsigned char[cols];
slices.push_back(twoD);
}
slices[0][0][0] = 'x';
std::cout << slices[0][0][0] << std::endl;
}
The vector must be of type void* and then you would need to typecast to char** or char* or whatever when reusing that pointer.

2D array as return value c++

I want to build a function which returns a 2D array
TExposureType** CAteImage::GetExposureMatrix()
{
TExposureType** ptr = new TExposureType*[FORMAT_MATRIX_ROWS];
for (int i = 0; i < FORMAT_MATRIX_ROWS; i++)
{
ptr[i] = new TExposureType[FORMAT_MATRIX_COLS];
for (int j = 0; j < FORMAT_MATRIX_COLS; j++)
{
ptr[i][j] = m_ExposureMatrix[i][j];
}
}
return ptr;
}
I know my code isn't effective - i can do the same with with a single malloc + 1 memcpy.
I can't however figure how to return the member i have m_ExposureMatrix[i][j] as a const ref?
TExposureType m_ExposureMatrix[FORMAT_MATRIX_COLS][FORMAT_MATRIX_ROWS];
if I understand your question correctly, (and that's a big if), this is what you want:
In your class header:
const TExposureType (&GetExposureMatrix()) [FORMAT_MATRIX_COLS][FORMAT_MATRIX_ROWS];
and in your cpp file
const TExposureType (&CAteImage::GetExposureMatrix()) [FORMAT_MATRIX_COLS][FORMAT_MATRIX_ROWS]
{
return m_ExposureMatrix;
};
You can significantly shorten this up with decltype if you have a compliant compiler that supports it, btw. Either way, you should be able to return m_ExposureMatrix by const-reference doing the above.

why this binary conversion does not work?

#include<stdio.h>
#include<conio.h>
unsigned * bin(unsigned n) {
unsigned a[16];
int i = 0, j = 0;
for (i = 0; i < 16; i++) {
a[i] = n & 0x1;
n = n >> 1;
}
return a;
}
void main() {
unsigned n = 5;
int i = 0;
unsigned * a = bin(n);
for (i = 15; i >= 0; i--) {
printf("%d\n", (*(a + i)));
}
getch();
}
Please help this binary conversion does not work. I'm trying to calculate x^n using binary conversion.
can anybode help??
You are returning a pointer to a local variable. This variable is stored on the stack, and will not be valid after the function returns.
Dereferencing this pointer will lead to undefined behavior.
The solution is to either make the variable static, or pass in the array as an argument to the function, or (as noted in a comment by James Kanze) use a type that copies the contents.
you can not return a local array defined in the function in this way.
The content of the array will be erased when the function finish the execution.
instead of using
unsigned a[16];
you can use the following:
unsigned *a =malloc(16 * (sizeof *a));
And do not forget in your main to free the memory allocated for a when the a array become useless in your program. you can free the array with:
free(a);
Actually, this is a typical case where using new (or malloc) is a pretty bad choice. However, as others have said, returning a pointer to a local array is bad.
Instead, pass in an array:
void bin(unsigned n, unsigned a[]) {
int i = 0;
for (i = 0; i < 16; i++) {
a[i] = n & 0x1;
n = n >> 1;
}
}
and in main:
unsigned a[16];
bin(n, a);
Now you have no need to allocate or return an array from bin.

initialize array passed by pointer

The function cannot initialize an array because sizeof() returns bytes of an int pointer
not the size the memory pointed by myArray.
void assignArray(int *myArray)
{
for(int k = 0; k < sizeof(myArray); ++k)
{
myArray[k] = k;
}
}
Are there other problems ?
Thanks
Well no, there are no other problems. The problem you stated is the only thing stopping you from initialising the array.
Typically, this is solved by simply passing the size along with the pointer:
void assignArray(int* myArray, std::size_t mySize)
{
for (std::size_t k = 0; k < mySize; ++k)
myArray[k] = k;
}
Note that I've used std::size_t for the size because that is the standard type for storing sizes (it will be 8 bytes of 64-bit machines, whereas int usually isn't).
In some cases, if the size is known statically, then you can use a template:
template <std::size_t Size>
void assignArray(int (&myArray)[Size])
{
for (std::size_t k = 0; k < Size; ++k)
myArray[k] = k;
}
However, this only works with arrays, not pointers to allocated arrays.
int array1[1000];
int* array2 = new int[1000];
assignArray(array1); // works
assignArray(array2); // error
I don't see other problems. However, you probably wanted this:
template<int sz>
void assignArray(int (&myArray)[sz])
{
for(int k = 0; k < sz; ++k)
{
myArray[k] = k;
}
}
Unless, of course, even the compiler doens't know how big it is at compile time. In which case you have to pass a size explicitly.
void assignArray(int* myArray, size_t sz)
{
for(int k = 0; k < sz; ++k)
{
myArray[k] = k;
}
}
If you don't know the size, you have a design error.
http://codepad.org/Sj2D6uWz
There are two types of arrays you should be able to distinguish. One looks like this:
type name[count];
This array is of type type[count] which is a different type for each count. Although it is convertable to type *, it is different. One difference is that sizeof(name) gives you count*sizeof(type)
The other type of array looks like this:
type *name;
Which is basically just a pointer that you could initialize with an array for example with malloc or new. The type of this variable is type * and as you can see, there are no count informations in the type. Therefore, sizeof(name) gives you the size of a pointer in your computer, for example 4 or 8 bytes.
Why are these two sizeofs different, you ask? Because sizeof is evaluated at compile time. Consider the following code:
int n;
cin >> n;
type *name = new type[n];
Now, when you say sizeof(name), the compiler can't know the possible future value of n. Therefore, it can't compute sizeof(name) as the real size of the array. Besides, the name pointer might not even point to an array!
What should you do, you ask? Simple. Keep the size of the array in a variable and drag it around where ever you take the array. So in your case it would be like this:
void assignArray(int *myArray, int size)
{
for(int k = 0; k < size; ++k)
{
myArray[k] = k;
}
}