I am a newbie who is learning C++ at random order.
In the following first three cases I can digest what is going on because the pattern of implicit decay is clear.
"an array of X" is implicitly decayed to "a pointer to X".
void case1()
{
int a[] = { 1,2,3,4,5,6 };
int *b = a;// array of int ---> pointer to int
}
void case2()
{
int input[][3] = { {1,2,3},{4,5,6} };
int(*output)[3] = input;// array of int[] ---> a pointer to int[]
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
cout << output[i][j] << endl;
}
int case3()
{
int input[][3] = { {1,2,3},{4,5,6} };
int* aux[2];
aux[0] = input[0];// array of int ---> pointer to int
aux[1] = input[1];// array of int ---> pointer to int
int** output = aux;// array of int* ---> pointer to int*
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
cout << output[i][j] << endl;
}
Question
However, I am really confused with the fourth case as follows.
int case4()
{
int input[][3] = { {1,2,3},{4,5,6} };
int* aux[2];
aux[0] = (int*)input;// array of int[] ---> pointer to int
aux[1] = aux[0] + 3;
int** output = aux;// array of int* ---> pointer to int*
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
cout << output[i][j] << endl;
}
How can "an array of int[]" can be explicitly decayed to "a pointer to int"?
aux[0] = (int*)input;// array of int[] ---> pointer to int
Any easy explanations are welcome!
How can "an array of int[]" can be explicitly decayed to "a pointer to int"?
To be pedantic about terminology: "explicitly decaying" is an oxymoron. Decaying is by definition an implicit conversion.
To answer "how can [array] be explicitly be [converted] to [a pointer that isn't type of the first element]?":
It is because an array can decay to a pointer, and all data pointers can be explicitly converted (reinterpreted) to any other data pointer type. In this case, input decays to a int(*)[3] which is then explicitly converted to int*.
Although it is certainly well formed, another matter is whether indirecting through an explicitly reinterpreted pointer has defined behaviour. The rules around reinterpretation of pointers are complex and subtle - it's rarely safe to assume that it's guaranteed to behave the way you observe. I would be more confident writing instead:
aux[0] = *input;
Here, the input array decays to pointer to first subarray, this pointer is indirected to get lvalue, which then decays to pointer to the element of the subarray.
More generally, be very careful when using explicit conversion (T)expr or functional conversion T(expr) or reinterpret cast reinterpret_cast<T>(expr). Unless you can quote the standard rule which makes their use well defined, don't use them.
Hmm, this sounds like it works but is it legal?.
What is known it that the first element of an array and the array itself share the same address in memory.
What works in common implementations is that all pointers share the same representation, and that this representation is just the memory address of their first byte. Simply this is not guaranteed by the standard.
But it is enough to successfully convert the address of an array to the address of its first element. The explicit cast re-interprets the representation of the address of the array as the address of the first element and because of the implementation it just happens to work.
That is what is great with Undefined Behaviour: it does not forbid the natural behaviour but does not guarantee it either.
So according to a string reading of the standard, and specifically of the strict aliasing rule converting a pointer to an array to a pointer to its first element, and using that pointer to dereference the element is UB, because an array and its element type are different types. Simply AFAIK it works on all common implementations.
TL/DR: it works on all common implementations, but do not use it if you want to write standard compliant programs.
Related
I want to pass a 2D array of characters to another function using a parameter of type "void*" and then have that function have access to the elements inside that array.
This code spits out a "Segmentation Fault:11" at the point where voidPointer tries to std::cout elements inside array2.
#include <iostream>
void voidPointer(void* userdata) {
char** array2 = static_cast<char**>(userdata);
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
std::cout << array2[i][j] << ' ';
}
std::cout << std::endl;
}
return;
}
int main() {
char array[3][3];
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
array[i][j] = 'a';
}
}
voidPointer(array);
return 0;
}
I've tried lots of different things and can't figure this out at all. I was able to get the above code to work when it's dealing with a 1D array. For example, this code
#include <iostream>
void voidPointer(void* userdata) {
char* array2 = static_cast<char*>(userdata);
for (int i=0; i<3; ++i) {
std::cout << array2[i] << ' ';
}
std::cout << std::endl;
return;
}
int main() {
char array[3];
for (int i=0; i<3; ++i) {
array[i] = 'a';
}
voidPointer(array);
return 0;
}
works as expected with the output "a a a".
Backstory: I'm working on my first project in which I'm trying to use a Mouse Callback function that accepts a parameter in the form "void* userdata". I am attempting to pass a 2D character array to this Callback function so I can then pass it on to other functions that will require access to the elements inside this array. I don't really know if this is good coding practice or not so feel free to let me know some alternatives.
To anyone that responds, thank you!
Firstly, I'll explain why your second example succeeds but your first example fails. Then I'll suggest some options for consideration to make your code work.
In short - your first example has undefined behaviour because the notional equivalence of pointers and arrays only works in one dimension.
The second example relies on the facts that;
The name of a one-dimensional array can be implicitly converted to a pointer to that array's first element. So, in main() of your second example, voidPointer(array) is equivalent to voidPointer(&array[0]). &array[0] has type char *.
A pointer can survive a round trip via a void * conversion - where "round trip" means retrieving the pointer of the original type. i.e. a char * can be converted to a void * AND that void * can be converted back to a char *. So the explicit conversion char* array2 = static_cast<char*>(userdata) done in voidPointer() successfully retrieves the pointer - so array2 in voidPointer() is equal to &array[0] passed by main();
Since the pointer passed by main() is the address of the first element of the array passed, voidPointer() can safely treat that pointer AS IF it is an array (as long as code doesn't try to access elements out of range of the original array).
The logic above is only applicable for pointers and one-dimensional arrays, so breaks down in the first example;
The name of a one-dimensional array can be implicitly converted to a pointer to that array's first element. So, in main() of your second example, voidPointer(array) is equivalent to voidPointer(&array[0]). However, the difference is that - the expression &array[0] has type char (*)[3] (a pointer to an array of three char) and that is NOT equivalent to a char **.
in voidPointer() your code converts the received pointer to a char ** via char** array2 = static_cast<char**>(userdata). This means that the pointer array2 has a different type that the pointer (&array[0]) passed by main();
Since array2 has a different type than the pointer passed by main() the code in voidPointer() which dereferences array2 (treats it as if it is an array of arrays) has undefined behaviour.
Generally speaking, there are two ways you can make the code work. The first is to do the right type of conversion.
void voidPointer(void* userdata)
{
char (*array2)[3] = static_cast<(char (*)[3]>(userdata);
// rest of your function can be used as is
}
As in your code, the array dimensions (which are both 3 in your example) must be known and fixed at compile time. There is no way that userPointer() can obtain any array dimensions from userdata, because a void * does not carry any of that sort of information from the caller.
A second option is to wrap the array in a data structure, for example
#include <iostream>
struct Carrier {char data[3][3];};
void voidPointer(void* userdata)
{
Carrier *package2 = static_cast<Carrier *>(userdata);
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
std::cout << package2->data[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main()
{
Carrier package;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
package.data[i][j] = 'a';
}
}
voidPointer(&package);
return 0;
}
This works because a Carrier * can survive a round trip via a void pointer (i.e. the value of package2 in voidPointer() has the the same type AND the same value as &package in main()) .
A second option is to use the std::array class. Although this is syntactically different, it is actually a modified version of the first option (since std::array is technically a templated data structure that contains an array of fixed dimension).
#include <iostream>
#include <array>
void voidPointer(void* userdata)
{
std::array<std::array<char, 3>, 3> *package2 = static_cast<std::array<std::array<char, 3>, 3> *>(userdata);
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
std::cout << (*package2)[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main()
{
std::array<std::array<char, 3>, 3> package;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
package[i][j] = 'a';
}
}
voidPointer(&package);
return 0;
}
Since your examples both had array dimensions fixed at compile time (3 in each dimension), my examples do the same. I'll leave extending the above to have dimensions fixed at run time (e.g. as user inputs) as a learning example.
It looks like the question is how to make this scenario work instead of why the attempt failed. For those interested in why the attempt failed, see casting void** to 2D array of int.
Note: It would be better to avoid using void*, but sometimes one has to interface with someone else's C-style API where void* is the traditional way to pass data to a callback.
There is a reasonably common trick for simulating a multi-dimensional array with a one-dimensional array. Using the trick reduces your scenario to the case that works. The trick involves how you access the elements. Instead of declaring char array[DIM1][DIM2] and accessing elements via array[i][j], declare the array to be char array[DIM1 * DIM2] and access elements via array[i*DIM2 + j].
However, remembering this formula is intellectual overhead, consuming brainpower that would be better used elsewhere. Not to mention that I get the dimensions reversed half the time. You could relieve the coder of this overhead by wrapping this array in a class, and hiding the formula in a method for accessing elements. This might look like the following.
class Array2D {
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
char data[DIM1 * DIM2];
public:
char& at(unsigned i, unsigned j) { return data[i*DIM2 + j]; }
// And perhaps other methods
};
You could then create an object of this class, then pass the address of that object to your C-style mouse handler. I.e. if your variable is Array2D array then call voidPointer(&array). This version can be adapted to the situation where the dimensions are not known at compile time.
Then again, if you are going to create a class anyway, why not try to preserve the syntax you are used to (using operator[] twice)? This does assume that the dimensions are compile-time constants.
class Array2D {
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
char data [DIM1][DIM2];
public:
auto& operator[] (unsigned i) { return data[i]; }
// And perhaps other methods
};
Of course, this approach locks you into a single size. It would probably be a good idea to make this a template. It would be even better if someone else did all that work for me.
#include <array>
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
using Array2D = std::array< std::array<char,DIM2>, DIM1 >;
// Note the order: ^^^^ ^^^^
Remember: if your variable is Array2D array then call voidPointer(&array).
Why not to use a structure instead of array. You can define everything in a structure, than pass its address to your function.
I am extremely new to C++ and pointers.
#include <iostream>
using namespace std;
int main() {
char* c = "my name jeff";
int i = 0;
while (true) {
cout << *(c + i++);
}
return 0;
}
The output is "my name jeff" followed by a lot of random characters, occasionally making sense. Am I actually accessing memory in my computer ? Why can initialize a pointer from a string ?
From https://eel.is/c++draft/expr#add-4
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
(4.1) If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
(4.2)
Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]),77 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element
i
+
j
of x if
0
≤
i
+
j
≤
n
and the expression P - J points to the (possibly-hypothetical) array element
i
−
j
of x if
0
≤
i
−
j
≤
n
.
(4.3)
Otherwise, the behavior is undefined.
So, with "my name jeff" (which is of type const char[13] (with the extra '\0')), once you do c[14] you have UB.
First, a note about this line right here:
char* c = "my name jeff";
In modern C++, this should be a const instead:
const char* c = "my name jeff";
With that out of the way, the answer to your question is yes and no.
Yes in the sense that if you have some sort of pointer, C++ doesn't care what you put in it.
char * pointer = nullptr;
char a, b, c;
pointer = &a;
pointer = &b;
pointer = &c;
The pointer doesn't care what address is stored in it. It is arbitrary in that sense. As long as it is the same type, you're fine.
You can even do pointer arithmetic like this:
*(pointer + 1) = 1;
*(pointer + 2) = 2;
*(pointer + i) = i;
In most cases, this will usually at least compile and probably run. In theory, you could use this type of arithmetic to access any given address and see what data is stored there.
However, in practice, the answer is a big no. That is because accessing unallocated memory is undefined behavior in C++. If you're unaware, undefined behavior allows anything to happen, including crashing or printing weird characters.
So, if you have some array like this:
int arr[4] = {1,2,3,4};
int * pointer = arr;
std::cout << *(pointer + 7);
This is undefined behavior because only pointer + 3 is guaranteed to have allocated memory in it.
So, in short: Yes, you can theoretically reach any address you want with pointer arithmetic, but you can only access memory that has been allocated safely. So in practice, not really.
I'm currently learning pointer. And when I create a pointer to an array with int type, I found that I can directly index the pointer without deferencing the pointer and the compiler still output exact items in my array. I do not understand why this works and why we don't need to first deference the pointer.
Code that without dereference
int arraySize = 5;
int* theArray = new int[arraySize];
for(int i = 0; i < 5; i++)
{
theArray[i] = i;
}
for (int i = 0; I < 5; i++)
{
std::cout << theArray[i] << std::endl;
}
And this gives me the output
Output without derefercing
However, when I wrote like this:
for (int i = 0; i < 5; i++)
{
(*theArray)[i] = i;
}
My compiler says that: Error: expression must have pointer-to-object type. (I'm using Visual Studio 2013.)
Any help would be appreciated.
Code that without dereference
[ code ]
That's incorrect. You are most certainly dereferencing your pointer:
theArray[i] = i;
That's a pointer dereference. The [] operator dereferences the pointer. This is equivalent to:
*(theArray+i) = i;
As you know, adding or subtracting a value to a pointer advances or decrements the pointer, producing a new pointer value, and then the pointer gets dereferenced.
Also:
*p = q;
is equivalent to
p[0] = q;
The [] operator is just a shorthand for adding an offset to a pointer, and dereferencing the resulting pointer with the * operator. The end result is exactly the same.
I do not understand why this works and why we don't need to first deference the pointer.
The first version is correct:
for(int i = 0; i < 5; i++)
{
theArray[i] = i;
}
because theArray[i] is actually *(theArray + i) - essentially pointer arithmetic is equivalent to array index.
On the other hand, the 2nd version is incorrect:
for (int i = 0; i < 5; i++)
{
(*theArray)[i] = i;
}
That's because (*theArray)[i] is actually pointer to array (not the array itself), and so it caused a type mismatch as the compiler already suggested.
A few other answers correctly say that *(theArray + i) is equivalent to theArray[i]. But the point I think you missed when learning is that unlike most objects a pointer to an array is not a pointer to the array that is then dereferenced, and then array logic, it is only a pointer to the first element of the array. That's why this:
int *myIntPointer = new int[5];
is NEARLY the same as this:
int myIntArray[5]; // "True" array on the stack
But you can also point it at something else:
int myInt = 10;
delete [] myIntPointer;
myIntPointer = &myInt;
It's also why doing the follow CAN give a compiler warning, but can also work (depends on the compiler):
myIntPointer = myIntArray; // Sometimes works, sometimes doesn't, compiler dependent
That's because allocating an array with new int[size] returns a pointer to an int not a pointer to an "array" type.
It's a weird corner case of C/C++ that arrays and pointers interact this way. You also run into it if you try and pass one of the "true" arrays into a function.
theArray[i] literally corresponds to *(theArray + i) so it already dereferences the pointer.
Indeed when you try to call operator[] on *theArray it yields you an error because it expects a pointer, not a real object.
You're actually asking the wrong question for your misunderstanding — you should be asking why you can write
int* theArray = new int[arraySize];
In c++, array types are not like other types, and have a number of special cases and rules that make them behave differently from other types. In particular, new T[N] does not return a "pointer to an N-long array of T", it returns a "pointer to T". (specifically, to the first element of the newly created array)
For a more mindboggling example of this, observe:
typedef int T[5];
T* p = new T; // this does not compile
int* q = new T; // this does compile
What does int nums[5]; do? When I pass nums to std::cout, it prints a memory address I think, but I don't understand what the code itself is actually doing when it runs.
int nums[5]; allocates memory for a static array of 5 int values.
When you then do std::cout << nums;, it is actually calling std::cout.operator<<(nums); While std::cout has many << operators defined for many different type types, it does not have an << operator that accepts an int[] array as input. What it does have is an << operator that accepts a const void* memory pointer as input. It prints the value of the memory address that the pointer is pointing at.
A static array can "decay" into a pointer, in this case to an int*.
What is array decaying?
Any type of pointer can be assigned to a void*. And any non-const variable can be assigned to a const variable of compatible type. That is why the compiler does not complain when you call std::cout << nums;. It is essentially acting similar to std::cout.operator<<((void*)(int*)nums); behind the scenes.
'nums' is an array that holds 5 int type datas.For Example:
int nums[5] = {1,2,3,4,5};
if you want to cout nums,you should write your code like this:
for(int index = 0; index < 5; index ++){
std::cout<<nums[index]<<std::endl;
}
but ,if you want cout it's memory address,you should write your code like this:
for(int index = 0; index < 5; index ++){
std::cout<<nums<<std::endl;
nums ++;
}
To fully understand how pointers, values, and references work, I am making a basic C++ program that attempts to tamper with some static and dynamic arrays and understand exactly how they should be passed in.
First I generate a static array of 3 elements. I then pass it into a function that modifies all elements. I then pass it into another function with a slightly different signature, but can also alter the array's values.
Next I generate a dynamically sized array, pass it into a function by reference so that all of the values in this dynamically sized array can be altered.
The code is as follows:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void changeIndexStaticArrayMethod1(int* stat);
void changeIndexStaticArrayMethod2(int (&stat)[3]);
void changeIndexDynamicArrayMethod1(int* dyn, int size);
int main() {
const int MAX = 3;
int arr[MAX] = { 1,2,3 };
changeIndexStaticArrayMethod1(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
cout << endl;
changeIndexStaticArrayMethod2(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
int SIZE;
cout << "Please choose a size for the array" << endl;
cin >> SIZE;
int *ne = new int[SIZE];
//Build array
for (int i = 0; i < SIZE; i++) {
ne[i] = i;
}
changeIndexDynamicArrayMethod1(ne, SIZE);
for (int i = 0; i < SIZE; i++) {
cout << "ne[" << i << "] = " << ne[i] << endl;
}
//To hang program
cin >> SIZE;
delete[] arr;
delete[] ne;
return 0;
}
void changeIndexStaticArrayMethod1(int* stat) {
stat[0] = 10;
stat[1] = 20;
stat[2] = 30;
}
void changeIndexStaticArrayMethod2(int (&stat)[3]) {
stat[0] = 40;
stat[1] = 50;
stat[2] = 60;
}
void changeIndexDynamicArrayMethod1(int* dyn, int size) {
for (int i = 0; i < size; i++) {
dyn[i] = i * 10;
}
}
All of the above code works how I want it to, I just have a few questions as to why (some of the methods of passing arrays by reference I have found on other SO questions).
In the changeIndexStaticArrayMethod1() and changeIndexDynamicArrayMethod1() functions, why are we able to use the dereference * operator for our array as reference? My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator. I know that with arrays, it is much different than using variables, but also, why will the following not work for single int variables:
void changeStaticNumber(int* num){
num = 100;
}
Obviously the above will work if we use &num and not int* num, and obviously I don't fully understand the relationship between pointers and arrays, but I cannot figure out why when we pass an array by reference, int* staticArray is ok.
Any explanation for these problems I am having would be much appreciated. Thanks.
why are we able to use the dereference * operator for our array as reference?
The * in C means many things. It can mean the unary indirection ("contents of") operator, it can mean the binary multiplication operator and it can mean a pointer declaration. The int* stat is a pointer declaration.
Since you aren't using the * to dereference the contents of the pointer inside that function, I'm not quite sure what you are asking.
When you take the array name of your array in main(), it "decays" into a pointer to the first element. So what those function do, is to take a pointer by value. If you dereference the pointer by typing *stat = something; you access the actual array in main.
Should you do something weird like changing the pointer itself, for example stat++;, then it will not affect the address used in main. You passed the pointer itself by value, so the pointer is a local copy.
My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator.
You can't really pass arrays by value in C or C++, without resorting to dirty tricks (storing them inside structs or classes). For example, had your function been written as void changeIndexStaticArrayMethod1(int stat[3]) it would still give you a pointer to the first element. It will not pass an array by value, as the syntax might trick you into believing.
why will the following not work for single int variables:
void changeStaticNumber(int* num){ num = 100; }
Because num is the pointer itself, not its contents. In order to write code like that, you could pass the variable by reference int& num. Behind the lines this is really the same thing as passing a pointer, just with simplified syntax.
To understand the relation between pointers and arrays better, start by reading this whole chapter: http://c-faq.com/aryptr/index.html (C and C++ are identical when it comes to pointers).
Let me see if I can take a stab at this.
Pointers are simply address holders. Once you do int * ptr = myarray; --- what you are in tern doing is storing the address of the pointer my array into ptr --- array names are actually pointers to the first memory location in the array. You can use pointer arithmetic to get at everything else for example myarray +1 will point you to the next location or myarray[1].
Passing by value is not very useful when you need to modify your array. Passing in by reference is essentially making a pointer to the array and passing that. Since arrays like vectors are contiguous blocks of memory you can index through them rather easily.
As far as your example goes void changeStaticNumber(int* num){ num = 100; } will not work because what you are attempting to do is store 100 into the pointer's address. If you deference num and make it void changeStaticNumber(int* num){ *num = 100; } it will work because you are actually going one step further and accessing the data that num is pointing to. When you use &num it is essentially the same thing - & just gives you the address of something.
For example if you want to point a pointer to an int what you would do is
int num = 5;
int *ptr = #
at this point in time ptr has the same address in num. To print out the data in num or that ptr is pointing to you need to dereference or go one step further as I like to tell myself and dereference to so cout << *ptr;
In both changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 you are not passing an array there is no pass by reference (which only happens if the parameter type is a reference type -- i.e. with &). The parameter has type int * (pointer to int). You are passing a pointer to int by value. There is no "dereference operator" in either function.
ne is already an int *, so passing it is nothing special. arr is an int [3], an array, not a pointer. In C, when an array-of-T is used in a context that expects a pointer-to-T, it is implicitly converted (without you needing to do anything) to a pointer to its first element. So when you do, changeIndexStaticArrayMethod1(arr), the compiler gets a pointer to the first element of arr, and passes that to the function.
The [] operator works on pointers. a[i] is always guaranteed to be the same as *(a + i). Inside both the changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 functions, [] is used to access subsequent elements using a pointer to the first element.