I can't understand some basic thing in c++ and have been wondering. Please help me.
I understand that p points to memory that would be a 2D int matrix of 3x4 size.
int(*p)[3][4];
1) Why can't I allocate memory like following?
p = new int[3][4];
2) It should be like following to work. But why?
p = new int [1][3][4]; //or new int [5][3][4]; etc
3) What does following line of code mean? It is semantically correct but what is it doing? What is significance of empty [] in following line?
p = new int [ ][3][4];
c++ is a strongly typed language. int is not the same as int*. Likewise int[3] is not the same type as int*. But just lightly poke int[3] with a stick and it will fall apart and decay to an int*. c++ does this because c does it.
Why can't I allocate memory like following?
p = new int[3][4];
Because the new is returning a pointer to int[4]:
auto p1 = new int[3][4]; // int(*p1)[4]
The array has decayed to a pointer. It has lost the type and first dimension. It would be best to avoid pointers for arrays and stick to using templates and references. Or better yet, prefer std::vector or std::array.
You could have multiple pointers to the same address, but with different types, which can be confusing.
2) It should be like following to work. But why?
p = new int [1][3][4];
In this example the array of int[3][4]s has also decayed to a pointer:
auto p2 = new int [1][3][4]; // int(*p2)[3][4]
So here the value returned by new can be assigned to p because it has the same type. Note however that the pointer type doesn't include information about the size of the array, it only has a type that points to elements which happen to be arrays of a lower dimension (that haven't decayed to pointers).
3) What does following line of code mean? It is semantically correct
but what is it doing? What is significance of empty [] in following
line?
p = new int [ ][3][4];
This might not always compile, and if it does then it is a compiler extension that will determine the value of the empty square brackets.
Because in C, "int *p" has two interpretations.
You can consider P to be a pointer to a single integer, but it can also be considered to be a pointer to an array of integer.
A common example, strings.
char *a = "hello";
"a" is a pointer to a single character, 'h', but more commonly it is treated as a pointer to an array of characters, aka a string.
So, you can do this:
char * a = new char[6];
strcpy(a, "hello");
I believe that your third example is not valid C++.
While this:
p = new int [9][3][4];
Allocates an array of 9 two dimensional arrays of 3x4.
Try this test:
int test()
{
int(* p)[3][4] = new int[1][3][4];
printf("sizeof(p)=%d, sizeof(*p)=%d\n", sizeof(p), sizeof(*p) / sizeof(int));
size_t q1 = (size_t)&p[0][0][0];
size_t q2 = (size_t)&p[1][0][0];
printf("p, diff: %d\n", (q2 - q1) / sizeof(int));
size_t r1 = (size_t)&p[0][0][0];
size_t r2 = (size_t)&p[0][1][0];
printf("p, diff: %d\n", (r2 - r1) / sizeof(int));
size_t s1 = (size_t)&p[0][0][0];
size_t s2 = (size_t)&p[0][0][1];
printf("p, diff: %d\n", (s2 - s1) / sizeof(int));
return 0;
}
Related
Why is this an error:
typedef int H[4];
H * h = new H; // error: cannot convert 'int*' to 'int (*)[4]' in initialization
?
Furthermore, why is this not an error:
H * h = new H[1];
?
Why does the compiler consider that new H returns an int *, whereas new H[1] returns an H * as expected ?
To put it another way: why is it that T * t = new T; is correct for a general type T, but is not correct when T is an array type ?
What would be the canonical way to allocate a simple array type such as this via new ?
Note that this is a simplified example, so e.g. new int[4] is not an acceptable workaround - I need to use the actual type from the preceding typedef.
Note also that I'm aware that using std::vector, std::array, et al is generally preferable over C-style arrays, but I have a "real world" use case where I need to work with types such as the above.
The C++ rule for the return type and value of new T is:
If T is not an array type, the return type is T *, and the returned value is a pointer to the dynamically allocated object of type T.
If T is an array of type U, the return type is U *, and the returned value is a pointer to the first element (whose type is U) of the dynamically allocated array of type T.
Therefore, since your H is an array of int, the return type of new H is int *, not H *.
By the same rule, new H[1] returns H *, but note that you have technicaly allocated a two-dimensional array of ints, sized 1 x 4.
The best way to get get around this in generic code is indeed to use auto:
auto h = new H;
Or, if you prefer to highlight the pointer fact:
auto *h = new H;
As for the rationale of this seeming inconsistency in the rules: pointers to arrays are quite "dangerous" in C++ since they behave rather unexpectedly (i.e. you have to be very careful with them not to produce unwanted effects). Let's look at this code:
typedef int H[4];
H *h = obtain_pointer_to_H_somehow();
h[2] = h[1] + 6;
At first (and maybe even second) glance, the code above seems to add 6 to the second int in the array and store it in the third int. But that's not what it does.
Just like for int *p, p[1] is an int (at the address sizeof(int) bytes offset from p), so for H *h, h[1] is a H, at the address 4 * sizeof(int) bytes offset from h. So the code is interpreted as: take the address in h, add 4 * sizeof(int) bytes to it, then add 6, and then store the resulting address at offset 8 * sizeof(int) from h. Of course, that will fail, since h[2] decays to an rvalue.
OK then, you fix it like this:
*h[2] = *h[1] + 6;
Even worse now. [] binds tighter than *, so this will reach into the 5th int object after h (note there are only 4 of them there!), add 6, and write that into the 9th int after h. Writing into random memory FTW.
To actually do what the code was probably intended to, it would have to be spelled like this:
(*h)[2] = (*h)[1] + 6;
In light of the above, and since what you usually do with a dynamically allocated array is access its elements, it makes more sense for new T[] to return T *.
Main Question
[What is the] Preferred method to new pointer to array
Constraint:
Note also that I'm aware that using std::vector, std::array, et al is generally preferable over C-style arrays, but I have a "real world" use case where I need to work with types such as the above.
Answer:
for the non-array case:
#include <memory>
auto h = std::make_unique<H>();
// h is now a std::unique_ptr<H> which behaves to all intents and purposes
// like an H* but will safely release resources when it goes out of
// scope
// it is pointing to a default-constructed H
// access the underlying object like this:
h.get(); // yields H*
*h; // yields H&
For the array case:
#include <memory>
auto h = std::make_unique<H[]>(4);
// h is now a std::unique_ptr<H[]> which behaves to all intents and purposes
// like an H* but will safely destruct and deallocate the array
// when it goes out of scope
// it is pointing to an array of 4 default-constructed Hs
// access the underlying object like this:
h[1]; // yields H& - a reference to the 2nd H
h.get(); //yields H* - as if &h[0]
In the C++ standard new and new[] are specifically separated because they can be be different allocators for performance and efficiency reasons; allocating an array vs. a single object has different usage patterns that allocator implementations optimise for.
The syntax is probably different because the compile-time type introspection techniques available when it was standardised wasn't nearly as reliable as it is today.
To make sensible code, the preferred way IMO would be:
struct H { int values[4]; }
H * h = new H;
That way, your H type logically "contains" your array of four int values - but the in-memory structure should still be compatible (assert(sizeof(H) == 4 * sizeof(int))); and you get to use object-style allocation of your fixed-size arrays. More... C++-ey.
You can see why if you basically do the typedef substitution manually:
H * h = new H;
Reduces to:
int[4]* h = new int[4];
while
H * h = new H[1];
reduces to:
(int*)[4] h = new int[1][4];
Because of the array to pointer decay rules, this is legal.
If you want an actual workaround, and you know the type of H, you can do something like:
typedef int* J;
typedef int H[4];
J j = new H; // This will work
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 7 years ago.
I'm trying to understand the different ways of declaring an array (of one or two dimensions) in C++ and what exactly they return (pointers, pointers to pointers, etc.)
Here are some examples:
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
int **A = new int*[2];
int *A = new int[2][2];
In each case, what exactly is A? Is it a pointer, double pointer? What happens when I do A+1? Are these all valid ways of declaring matrices?
Also, why does the first option not need the second set of curly braces to define "columns"?
Looks like you got a plethora of answers while I was writing mine, but I might as well post my answer anyway so I don't feel like it was all for nothing...
(all sizeof results taken from VC2012 - 32 bit build, pointer sizes would, of course, double with a 64 bit build)
size_t f0(int* I);
size_t f1(int I[]);
size_t f2(int I[2]);
int main(int argc, char** argv)
{
// A0, A1, and A2 are local (on the stack) two-by-two integer arrays
// (they are technically not pointers)
// nested braces not needed because the array dimensions are explicit [2][2]
int A0[2][2] = {0,1,2,3};
// nested braces needed because the array dimensions are not explicit,
//so the braces let the compiler deduce that the missing dimension is 2
int A1[][2] = {{0,1},{2,3}};
// this still works, of course. Very explicit.
int A2[2][2] = {{0,1},{2,3}};
// A3 is a pointer to an integer pointer. New constructs an array of two
// integer pointers (on the heap) and returns a pointer to the first one.
int **A3 = new int*[2];
// if you wanted to access A3 with a double subscript, you would have to
// make the 2 int pointers in the array point to something valid as well
A3[0] = new int[2];
A3[1] = new int[2];
A3[0][0] = 7;
// this one doesn't compile because new doesn't return "pointer to int"
// when it is called like this
int *A4_1 = new int[2][2];
// this edit of the above works but can be confusing
int (*A4_2)[2] = new int[2][2];
// it allocates a two-by-two array of integers and returns a pointer to
// where the first integer is, however the type of the pointer that it
// returns is "pointer to integer array"
// now it works like the 2by2 arrays from earlier,
// but A4_2 is a pointer to the **heap**
A4_2[0][0] = 6;
A4_2[0][1] = 7;
A4_2[1][0] = 8;
A4_2[1][1] = 9;
// looking at the sizes can shed some light on subtle differences here
// between pointers and arrays
A0[0][0] = sizeof(A0); // 16 // typeof(A0) is int[2][2] (2by2 int array, 4 ints total, 16 bytes)
A0[0][1] = sizeof(A0[0]); // 8 // typeof(A0[0]) is int[2] (array of 2 ints)
A1[0][0] = sizeof(A1); // 16 // typeof(A1) is int[2][2]
A1[0][1] = sizeof(A1[0]); // 8 // typeof(A1[0]) is int[2]
A2[0][0] = sizeof(A2); // 16 // typeof(A2) is int[2][2]
A2[0][1] = sizeof(A2[0]); // 8 // typeof(A1[0]) is int[2]
A3[0][0] = sizeof(A3); // 4 // typeof(A3) is int**
A3[0][1] = sizeof(A3[0]); // 4 // typeof(A3[0]) is int*
A4_2[0][0] = sizeof(A4_2); // 4 // typeof(A4_2) is int(*)[2] (pointer to array of 2 ints)
A4_2[0][1] = sizeof(A4_2[0]); // 8 // typeof(A4_2[0]) is int[2] (the first array of 2 ints)
A4_2[1][0] = sizeof(A4_2[1]); // 8 // typeof(A4_2[1]) is int[2] (the second array of 2 ints)
A4_2[1][1] = sizeof(*A4_2); // 8 // typeof(*A4_2) is int[2] (different way to reference the first array of 2 ints)
// confusion between pointers and arrays often arises from the common practice of
// allowing arrays to transparently decay (implicitly convert) to pointers
A0[1][0] = f0(A0[0]); // f0 returns 4.
// Not surprising because declaration of f0 demands int*
A0[1][1] = f1(A0[0]); // f1 returns 4.
// Still not too surprising because declaration of f1 doesn't
// explicitly specify array size
A2[1][0] = f2(A2[0]); // f2 returns 4.
// Much more surprising because declaration of f2 explicitly says
// it takes "int I[2]"
int B0[25];
B0[0] = sizeof(B0); // 100 == (sizeof(int)*25)
B0[1] = f2(B0); // also compiles and returns 4.
// Don't do this! just be aware that this kind of thing can
// happen when arrays decay.
return 0;
}
// these are always returning 4 above because, when compiled,
// all of these functions actually take int* as an argument
size_t f0(int* I)
{
return sizeof(I);
}
size_t f1(int I[])
{
return sizeof(I);
}
size_t f2(int I[2])
{
return sizeof(I);
}
// indeed, if I try to overload f0 like this, it will not compile.
// it will complain that, "function 'size_t f0(int *)' already has a body"
size_t f0(int I[2])
{
return sizeof(I);
}
yes, this sample has tons of signed/unsigned int mismatch, but that part isn't relevant to the question. Also, don't forget to delete everything created with new and delete[] everything created with new[]
EDIT:
"What happens when I do A+1?" -- I missed this earlier.
Operations like this would be called "pointer arithmetic" (even though I called out toward the top of my answer that some of these are not pointers, but they can turn into pointers).
If I have a pointer P to an array of someType, then subscript access P[n] is exactly the same as using this syntax *(P + n). The compiler will take into account the size of the type being pointed to in both cases. So, the resulting opcode will actually do something like this for you *(P + n*sizeof(someType)) or equivalently *(P + n*sizeof(*P)) because the physical cpu doesn't know or care about all our made up "types". In the end, all pointer offsets have to be a byte count. For consistency, using array names like pointers works the same here.
Turning back to the samples above: A0, A1, A2, and A4_2 all behave the same with pointer arithmetic.
A0[0] is the same as *(A0+0), which references the first int[2] of A0
similarly:
A0[1] is the same as *(A0+1) which offsets the "pointer" by sizeof(A0[0]) (i.e. 8, see above) and it ends up referencing the second int[2] of A0
A3 acts slightly differently. This is because A3 is the only one that doesn't store all 4 ints of the 2 by 2 array contiguously. In my example, A3 points to an array of 2 int pointers, each of these point to completely separate arrays of two ints. Using A3[1] or *(A3+1) would still end up directing you to the second of the two int arrays, but it would do it by offsetting only 4bytes from the beginning of A3 (using 32 bit pointers for my purposes) which gives you a pointer that tells you where to find the second two-int array. I hope that makes sense.
For the array declaration, the first specified dimension is the outermost one, an array that contains other arrays.
For the pointer declarations, each * adds another level of indirection.
The syntax was designed, for C, to let declarations mimic the use. Both the C creators and the C++ creator (Bjarne Stroustrup) have described the syntax as a failed experiment. The main problem is that it doesn't follow the usual rules of substitution in mathematics.
In C++11 you can use std::array instead of the square brackets declaration.
Also you can define a similar ptr type builder e.g.
template< class T >
using ptr = T*;
and then write
ptr<int> p;
ptr<ptr<int>> q;
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
These declare A as array of size 2 of array of size 2 of int. The declarations are absolutely identical.
int **A = new int*[2];
This declares a pointer to pointer to int initialized with an array of two pointers. You should allocate memory for these two pointers as well if you want to use it as two-dimensional array.
int *A = new int[2][2];
And this doesn't compile because the type of right part is pointer to array of size 2 of int which cannot be converted to pointer to int.
In all valid cases A + 1 is the same as &A[1], that means it points to the second element of the array, that is, in case of int A[2][2] to the second array of two ints, and in case of int **A to the second pointer in the array.
The other answers have covered the other declarations but I will explain why you don't need the braces in the first two initializations. The reason why these two initializations are identical:
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
is because it's covered by aggregate initialization. Braces are allowed to be "elided" (omitted) in this instance.
The C++ standard provides an example in § 8.5.1:
[...]
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
[...]
In the following example, braces in the initializer-list are elided;
however the initializer-list has the same effect as the
completely-braced initializer-list of the above example,
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
The initializer for y begins with a left brace, but the one for y[0]
does not, therefore three elements from the list are used. Likewise
the next three are taken successively for y[1] and y[2].
Ok I will try it to explain it to you:
This is a initialization. You create a two dimensional array with the values:
A[0][0] -> 0
A[0][1] -> 1
A[1][0] -> 2
A[1][1] -> 3
This is the exactly the same like above, but here you use braces. Do it always like this its better for reading.
int **A means you have a pointer to a pointer of ints. When you do new int*[2] you will reserve memory for 2 Pointer of integer.
This doesn't will be compiled.
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
These two are equivalent.
Both mean: "I declare a two dimentional array of integers. The array is of size 2 by 2".
Memory however is not two dimensional, it is not laid out in grids, but (conceptionaly) in one long line. In a multi-dimensional array, each row is just allocated in memory right after the previous one.
Because of this, we can go to the memory address pointed to by A and either store two lines of length 2, or one line of length 4, and the end result in memory will be the same.
int **A = new int*[2];
Declares a pointer to a pointer called A.
A stores the address of a pointer to an array of size 2 containing ints. This array is allocated on the heap.
int *A = new int[2][2];
A is a pointer to an int.
That int is the beginning of a 2x2 int array allocated in the heap.
Aparrently this is invalid:
prog.cpp:5:23: error: cannot convert ‘int (*)[2]’ to ‘int*’ in initialization
int *A = new int[2][2];
But due to what we saw with the first two, this will work (and is 100% equivalent):
int *A new int[4];
int A[2][2] = {0,1,2,3};
A is an array of 4 ints. For the coder's convenience, he has decided to declare it as a 2 dimensional array so compiler will allow coder to access it as a two dimensional array. Coder has initialized all elements linearly as they are laid in memory. As usual, since A is an array, A is itself the address of the array so A + 1 (after application of pointer math) offset A by the size of 2 int pointers. Since the address of an array points to the first element of that array, A will point to first element of the second row of the array, value 2.
Edit: Accessing a two dimensional array using a single array operator will operate along the first dimension treating the second as 0. So A[1] is equivalent to A[1][0]. A + 1 results in equivalent pointer addition.
int A[2][2] = {{0,1},{2,3}};
A is an array of 4 ints. For the coder's convenience, he has decided to declare it as a 2 dimensional array so compiler will allow coder to access it as a two dimensional array. Coder has initialized elements by rows. For the same reasons above, A + 1 points to value 2.
int **A = new int*[2];
A is pointer to int pointer that has been initialized to point to an array of 2 pointers to int pointers. Since A is a pointer, A + 1 takes the value of A, which is the address of the pointer array (and thus, first element of the array) and adds 1 (pointer math), where it will now point to the second element of the array. As the array was not initialized, actually doing something with A + 1 (like reading it or writing to it) will be dangerous (who knows what value is there and what that would actually point to, if it's even a valid address).
int *A = new int[2][2];
Edit: as Jarod42 has pointed out, this is invalid. I think this may be closer to what you meant. If not, we can clarify in the comments.
int *A = new int[4];
A is a pointer to int that has been initialized to point to an anonymous array of 4 ints. Since A is a pointer, A + 1 takes the value of A, which is the address of the pointer array (and thus, first element of the array) and adds 1 (pointer math), where it will now point to the second element of the array.
Some takeaways:
In the first two cases, A is the address of an array while in the last two, A is the value of the pointer which happened to be initialized to the address of an array.
In the first two, A cannot be changed once initialized. In the latter two, A can be changed after initialization and point to some other memory.
That said, you need to be careful with how you might use pointers with an array element. Consider the following:
int *a = new int(5);
int *b = new int(6);
int c[2] = {*a, *b};
int *d = a;
c+1 is not the same as d+1. In fact, accessing d+1 is very dangerous. Why? Because c is an array of int that has been initialized by dereferencing a and b. that means that c, is the address of a chunk of memory, where at that memory location is value which has been set to the value pointed to by tovariable a, and at the next memory location that is a value pinned to by variable b. On the other hand d is just the address of a. So you can see, c != d therefore, there is no reason that c + 1 == d + 1.
I came across this question:
In the declaration below , p is a pointer to an array of 5 int
pointers.
int *(*p)[5];
which of the following statements can be used to allocate memory for
the first dimension in order to make p an array of 3 arrays of 5
pointers to type int ?
A. p = new int [3][5]*;
B. p = new int (*)[3][5];
C. p = new int [3]*[5];
D. p = new int *[3][5];
E. p = new int (* [3] ) [5];
What is the answer ?
I am not sure I understand the question. Normally I would create a pointer to an array of 5 int as such int* p[5]; I am curious as to why they did it as int *(*p)[5];
Also what does the question want ? Is it asking to initialize (allocate memory) to the first 3 int pointers ? I would appreciate it if someone could explain this to me
F:
using IPA5 = int*[5];
IPA5 * p = new IPA5[3];
Each element p[0], p[1], p[2] is just a plain, typed array of int*. There's nothing dynamic going on beyond the initial dynamic allocation, where 3 is allowed to be a dynamic quantity.
Then p[0][i] for i in [0, 5) is an int *, which you can use in whatever way you like (which includes making it point to the first element of yet anohter dynamic array).
What you would write as:
int* p[5];
is a five element array of pointers to int.
What this declares:
int *(*p)[5];
is a pointer to a five element array of pointers to int, i.e. a pointer to the type of thing you just wrote.
In other words; you could do:
int * a[5];
int * (*p)[5] = &a;
You can mentally read this incrementally as follows:
(*p) // p is a pointer
(*p)[5] // p is a pointer to an array of size 5
int * (*p)[5] // p is a pointer to an array of size 5 of type pointer to int
You need the parentheses around *p, because otherwise:
int ** p[5];
would declare a 5 element array of type int **, or pointer to pointer to int, which is a different thing entirely.
The question is basically asking you to dynamically allocate memory equivalent to three of what a is above, so answer "D" is the correct one.
The answer is
D. p = new int *[3][5];
all the others are syntactically wrong
to realize the difference between
int * p [5];
int * (*p) [5];
consider this example
int *(*p)[5];
int pp[5];
pp[0][0] = new int [5]; //LHS is int , RHS is int ,, compilation error
p[0][0] = new int [5]; //this works because p[0][0] is a pointer not an int
try thinking about each dimension as adding you additional *
back to the question
int *(*p)[5] is giving you 3 * (***p)
so you can assign
p = int *[3][5]
because it has 3 * as well
int* p[5] has type array of size 5 of int*. It decays to int**, so p + 1 will point to the second element of that array.
int *(*p)[5] has type pointer to array of size 5 of int*. You can think of it as decayed two-dimensional array int* [][5]. So p + 1 will point to the second element of the first dimension of that array, that is to the next byte after 5 pointers to int.
Which leads us to the conclusion that the right answer is D.
(This is not to mention that other answers just don't compile regardless of type of p)
What is the answer ?
D
Normally I would create a pointer to an array of 5 int as such int* p[5]; I am curious as to why they did it as int *(*p)[5];
It is not "normally" because int* p[5] is not a pointer to an array of 5 int, it is an array of 5 pointers to int.
Also what does the question want ? Is it asking to initialize (allocate memory) to the first 3 int pointers ?
It's not clear. There is no way "to make p an array of 3 arrays of 5 pointers to type int", to begin with.
In this code:
int * p = new int(44);
p is allocated on the heap and the value it points to is 44;
but now I can also do something like this:
p[1] = 33;
without getting an error. I always thought
int * p = new int(44);
was just another way of saying "P is allocated on the heap and points to an address containing 44" but apparently it makes p a pointer to an array of ints? is the size of this new array 44? Or is this result unusual.
You were right: P is allocated on the heap and points to an address containing 44. There's no array allocated. p[1] = 33; is what they call "undefined behavior". Your program might crash, but it's not guaranteed to crash every single time you do this.
int *p_scalar = new int(5); //allocates an integer, set to 5.
If you access p_scalar[n] (n <> 0) it may crash
In your example, the C++ language gives you a default implementation for the subscript operator for pointers that looks somehow similar to this:
(*Ptr)& operator[](size_t index)
{
return *(address + index*sizeof(*Ptr));
}
This can always be overloaded and replaced for any type. Integers are not an exception, when you say:
int * pointer = alocate_int_array();
pointer[1] = 1;
You're using the compiler-augmented default implementation of that operator.
I have a question.
I created a correctly initialized integer pointer
int * p
and a correctly initialized integer array
int * array1 = new int[]
Which of the following is legal code?
p = array1;
array1 = p;
Or are both correct?
is this possible as well
p[0] since, to my pointer arithmetic knowledge, it doesn't add anything.
All in c++
If the question is trying to get at pointers versus arrays, they are not always compatible. This is hidden in the presented code because the array is immediately converted to a pointer.
int* array1 = new int[5]; // Legal, initialising pointer with heap allocated array
int array2[5] = {0}; // Declaring array directly on the stack and initalising with zeros
int *p = 0; // Declaring pointer and initialising to numm
p = array2; // Legal, assigning array to pointer
p = array1; // Legal, assigning pointer to pointer
array1 = p; // Legal, assigning pointer to pointer
array2 = p; // ILLEGAL, assigning pointer to array
Here array2 has an array type and cannot be used to store a pointer. Actually, the array cannot be reassigned at all, as it is not an l-value.
int array3[5] = {0}; // Declaring array directly on the stack and initalising with zeroes
array3 = array2; // ILLEGAL, array not an l-value
The array has a fixed address and reassiging it would be similar to trying to write:
int i = 0;
&i = p;
[Hopefully, trying to reassign the location of a variable is obvious nonsense.]
Both are legal.
The first, "p = array1", will cause your correctly initialized integer pointer to be leaked and to point p to the first occurrence of the array that array1 points to.
The second, "array1 = p", will cause the correctly initialized integer array to to be leaked and to point array1 to the single int that p points to.
So I suspect I'm missing something. Could you perhaps post complete code?
If both p and array1 are declared as "int *", as you imply here, then either assignment is legal, by definition.
both are leagal.
passing adresses to eachother. dont knw what u want to do
According to the explanation provided in this site. The first assigned in is correct but the second assignment cannot be considered valid. Please look under the title 'Pointers and arrays'.
You can assign your array variable to pointer variable. So p = array1 is correct.
You can refer this code.
#include <iostream>
using namespace std;
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
for (int n=0; n<5; n++)
cout << p[n] << ", ";
return 0;
}
If both are pointers then no need to declare pointer as array like int *array1 = new int[].
Both variables are of type pointer to int. So both assignments are legal. The fact that one of the variables is an array doesn't matter in C. Arrays and pointers are the same after initialization.
"I created a correctly initialized integer pointer int * p and a correctly initialized integer array int * array1 = new int[]"
First of all, keeping the syntactical mistakes aside, the terminology is wrong.
int *p; - Here you are just declaring a pointer to hold an integer variable's address. You are not initializing it. Declaration is different from initialization and initialization is different from assignment.
int *array1 = new int[]; - Keeping the error aside, this is not an initialized integer array. array1 is a pointer pointing to an array of integers.
And passing nothing to [] is incorrect. A value needs to be passed that decides number of memory locations to be allocated for holding integer values.
Answering the questions.
Which of the following is legal code?
p = array1;
If, array1 is properly initialized it's correct. p points to the first integer in the array1. Even if it is not properly initialized also, it is correct. In this case, both array and p points to garbage values.
int* array1 = new int[5]; // Notice **5** being passed.
array1 = p;
Infact this operation is useless. Both p and array1 were both pointing to the same location earlier. But this is legally correct.
is this possible as well p[0] ?
Yes, it's correct. p can dereference to 0 to 4 as it's index values. If you just want to p[0], in that case -
int* array1 = new int ; // Notice nothing being passed.