I thought a[] and *a are the same thing because they work like pointers. Yet I encountered something unexpected in the following code:
#include <iostream>
using namespace std;
class F {
public:
bool a[];
F();
};
F::F() {
*a = new bool[5];
a[2] = true;
}
int main() {
F obj;
if(obj.a[2])
cout << '?';
return 0;
}
This code prints ?, but I don't understand how it works. When:
*a = new bool[5];
is changed into:
a = new bool[5];
compiler reports:
F:\main.cpp|11|error: incompatible types in assignment of 'bool*' to 'bool [0]'|
I found this behaviour weird, so I was playing around with this code. When I changed the type of a from bool to int compiler always reports an error
F:\main.cpp|11|error: invalid conversion from 'int*' to 'int' [-fpermissive]|
Why does this work the way it does?
I thought a[] and *a are the same thing because they work like pointers.
Let's talk about this piece of declaration:
int a[4] = { 1, 2, 3, 5 };
int *b = NULL;
This is how they land in memory in the executable:
+----+----+----+----+
a: | 1 | 2 | 3 | 5 | <-- 4 integers
+----+----+----+----+
+----------+
b: | NULL | <-- 1 pointer that points to nowhere
+----------+
As you can see, they are not the same thing.
What happens after b = new int[4];?
The new memory layout of b is something like this:
+----------+
b: | 0xacf3de | <-- 1 pointer that points to a block of 4 integers
+----------+
Somewhere else in memory (at address 0xacf3de)...
+----+----+----+----+
0xacf3de: | ? | ? | ? | ? | <-- 4 integers
+----+----+----+----+
But wait, somebody told me that arrays work like pointers...
No, that's not true. The arrays do not work like pointers.
An array name (a, f.e.) can be used as a shortcut for its address in memory (which is, in fact, the address of its first element). The following notations are equivalent:
a
&a
&a[0]
The value of all of them is the address in memory where the first element of a (the 1 in the example above) is stored.
a[0] is an int, &a[0] is an int *. This is the complete form. The other two are shortcuts that the language provides in order to make the code easier to read and understand.
The things are different for pointers.
b is the value stored in the b variable (NULL or 0xacf3de in the example above. It is a value of type int * -- the address in memory where an int is stored. &b is the address in memory where (the value of) b is stored. Its type is int ** -- a pointer to a pointer to an int; or "the address in memory where is stored the address of an int".
But wait, they can be replaced one for another in some contexts
Up to some point, yes, a pointer and an array are interchangeable. As you can see above, there is a common data type involved: int *. It is the type of b (which stores the address of an int) and also the type of &a[0] (which is also the address of an int).
This means that where b can be used, a (a short of &a[0]) can be used instead, and vice-versa.
Also, where *b can be used, *a can be used instead. It is the short for *&a[0] and it means "the value (*) stored at the address (&) of a[0]" and it is, in fact, the same as a[0].
But, where &b can be used, &a cannot be used instead; remember that &a is the same as &a[0] and its type is int * (but the type of &b is int **).
The line:
*a = new bool[5];
is equivalent to:
a[0] = new bool[5];
You are not initialiazing your array, but allocating an array of bool which is then implicitly converted into bool to be assigned to a[0]: the value should be true since the pointer returned by new should be different from 0. This implicit conversion does not apply with ints: that is why you are getting an error when changing the type of a.
Now, considering this line:
a = new bool[5];
Here you are trying to assign your dynamically allocated array to a, in other words assigning a pointer to an array bool* to a static array bool[0]: as the compiler says, the types are incompatible. A static array a[] can be used as a pointer, e.g. in the following code:
int foo(bool* a) { /* ... */ }
bool my_array[5];
foo(my_array);
But pointers can not be converted into static arrays as you are trying to do.
Type of value returned from new Type[x] is Type * i.e pointer of that type
examle:
So Right syntax is
bool a;
*a = new bool[x];
so it is wrong to do like is
a=new bool[x] wrong syntax as it is invalid to assign pointer to a normal varibale
see for more details
Related
In C, I know I can dynamically allocate a two-dimensional array on the heap using the following code:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Clearly, this actually creates a one-dimensional array of pointers to a bunch of separate one-dimensional arrays of integers, and "The System" can figure out what I mean when I ask for:
someNumbers[4][2];
But when I statically declare a 2D array, as in the following line...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
...does a similar structure get created on the stack, or is it of another form completely? (i.e. is it a 1D array of pointers? If not, what is it, and how do references to it get figured out?)
Also, when I said, "The System," what is actually responsible for figuring that out? The kernel? Or does the C compiler sort it out while compiling?
A static two-dimensional array looks like an array of arrays - it's just laid out contiguously in memory. Arrays are not the same thing as pointers, but because you can often use them pretty much interchangeably it can get confusing sometimes. The compiler keeps track properly, though, which makes everything line up nicely. You do have to be careful with static 2D arrays like you mention, since if you try to pass one to a function taking an int ** parameter, bad things are going to happen. Here's a quick example:
int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};
In memory looks like this:
0 1 2 3 4 5
exactly the same as:
int array2[6] = { 0, 1, 2, 3, 4, 5 };
But if you try to pass array1 to this function:
void function1(int **a);
you'll get a warning (and the app will fail to access the array correctly):
warning: passing argument 1 of ‘function1’ from incompatible pointer type
Because a 2D array is not the same as int **. The automatic decaying of an array into a pointer only goes "one level deep" so to speak. You need to declare the function as:
void function2(int a[][2]);
or
void function2(int a[3][2]);
To make everything happy.
This same concept extends to n-dimensional arrays. Taking advantage of this kind of funny business in your application generally only makes it harder to understand, though. So be careful out there.
The answer is based on the idea that C doesn't really have 2D arrays - it has arrays-of-arrays. When you declare this:
int someNumbers[4][2];
You are asking for someNumbers to be an array of 4 elements, where each element of that array is of type int [2] (which is itself an array of 2 ints).
The other part of the puzzle is that arrays are always laid out contiguously in memory. If you ask for:
sometype_t array[4];
then that will always look like this:
| sometype_t | sometype_t | sometype_t | sometype_t |
(4 sometype_t objects laid out next to each other, with no spaces in between). So in your someNumbers array-of-arrays, it'll look like this:
| int [2] | int [2] | int [2] | int [2] |
And each int [2] element is itself an array, that looks like this:
| int | int |
So overall, you get this:
| int | int | int | int | int | int | int | int |
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};
in memory is equal to:
unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};
In answer to your also: Both, though the compiler is doing most of the heavy lifting.
In the case of statically allocated arrays, "The System" will be the compiler. It will reserve the memory like it would for any stack variable.
In the case of the malloc'd array, "The System" will be the implementer of malloc (the kernel usually). All the compiler will allocate is the base pointer.
The compiler is always going to handle the type as what they are declared to be except in the example Carl gave where it can figure out interchangeable usage. This is why if you pass in a [][] to a function it must assume that it is a statically allocated flat, where ** is assumed to be pointer to pointer.
Suppose, we have a1 and a2 defined and initialized like below (c99):
int a1[2][2] = {{142,143}, {144,145}};
int **a2 = (int* []){ (int []){242,243}, (int []){244,245} };
a1 is a homogeneous 2D array with plain continuous layout in memory and expression (int*)a1 is evaluated to a pointer to its first element:
a1 --> 142 143 144 145
a2 is initialized from a heterogeneous 2D array and is a pointer to a value of type int*, i.e. dereference expression *a2 evaluates into a value of type int*, memory layout does not have to be continuous:
a2 --> p1 p2
...
p1 --> 242 243
...
p2 --> 244 245
Despite totally different memory layout and access semantics, C-language grammar for array-access expressions looks exactly the same for both homogeneous and heterogeneous 2D array:
expression a1[1][0] will fetch value 144 out of a1 array
expression a2[1][0] will fetch value 244 out of a2 array
Compiler knows that the access-expression for a1 operates on type int[2][2], when the access-expression for a2 operates on type int**. The generated assembly code will follow the homogeneous or heterogeneous access semantics.
The code usually crashes at run-time when array of type int[N][M] is type-casted and then accessed as type int**, for example:
((int**)a1)[1][0] //crash on dereference of a value of type 'int'
To access a particular 2D array consider the memory map for an array declaration as shown in code below:
0 1
a[0]0 1
a[1]2 3
To access each element, its sufficient to just pass which array you are interested in as parameters to the function. Then use offset for column to access each element individually.
int a[2][2] ={{0,1},{2,3}};
void f1(int *ptr);
void f1(int *ptr)
{
int a=0;
int b=0;
a=ptr[0];
b=ptr[1];
printf("%d\n",a);
printf("%d\n",b);
}
int main()
{
f1(a[0]);
f1(a[1]);
return 0;
}
Please explain to me how the b pointer shows the last element.
Every time, it prints out the last element, no matter how long the array is. If you use *b alone in cout, it shows a number out of array.
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int a[] = {1,2,3,4,5,6,7,8,9,10,11};
int *b =(int*) (&a+1);
cout << *(b-1) << endl;
return 0;
}
This expression
&a+1
has the type int ( * )[11] and points to the memory after the last element of the array a.
In this declaration
int *b =(int*) (&a+1);
you interpreted the expression as having the pointer type int * that points to after the last element of the array a. Instead you could write
int *b = a + 11;
So the expression
b - 1
points to the last element of the array a.
Thus you may imagine the expression *( b - 1 ) the following way
*( a + 11 - 1 ) => *( a + 10 ) => a[10]
Per pointer arithmetic rules, incrementing/decrementing a pointer by N elements will adjust the value of the pointer by N * sizeof(T) bytes, where T is the dereferenced type of the pointer.
&a is a pointer to the array itself, which has a type of int[11], so you have a pointer of type int(*)[11] to the beginning of the array. Lets call this A1 in the diagram below.
Adding +1 to that pointer will advance it by sizeof(int[11]) (aka sizeof(int)*11) bytes, thus producing a new int(*)[11] pointer to the memory address immediately following the entire array. Let's call this A2 in the diagram.
You are then type-casting that new pointer, so now you have a pointer of type int* to the end of the array. This is the memory address you are assigning to your int *b pointer variable. Lets call this B1 in the diagram below.
Subtracting -1 from that pointer will reduce it by sizeof(int) bytes, thus producing a new int* pointer to the memory address of the last int element in the array. Lets call this B2 in the diagram below.
So, when you dereference b to print the int that it is pointing at, you are printing the value of the last int in the array. If you don't decrement b, it is pointing past the end of the array, and you have undefined behavior. You might just print out random garbage, or you might crash your app. Anything could happen.
---------------------------------------------------------------------
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---------------------------------------------------------------------
^ ^ ^
| | |
|_A1 --------------------------------------------------------|----->|_A2
+1 | |
|_B2 <-|_B1
-1
Hello guys can someone explain why while declaring pointers to pointer we need to use ** why cant we use only single * to point a pointer to another pointer or is it just a syntax related issue E.g
int main()
{
int a=5,*b,*c;
b=&a;
c=&b //Why cant this simply doesn't make c point to memory location of b with the above pointer declaration why is there a need to declare c as **c
}
With the following codes:
int a=5,*b,**c;
b=&a;
c=&b;
We have:
+---+
a | 5 | <-- value
+---+
|100| <-- address
+---+
+---+
*b |100| <-- value
+---+
|200| <-- address
+---+
+---+
**c |200| <-- value
+---+
|300| <-- address
+---+
When you store a's address in b, b's value is a's address. But b has it's own address (200).
c can store b's address as it's value. But c has it's own address too (300).
printf("%x", &c); will give you: 300
Deferencing *c will get you down "1 level" and give you 100 (get value of address 200)
Deferencing **c will get you down 1 more level and give you 5 (get value of address 100)
If you try to use *c instead of **c to hold *b, how are you able to deference all the way down to reach value 5?
Testing the codes on a compiler:
printf("Address of a: %x\n", &a);
printf("Address of b: %x\n", &b);
printf("Address of c: %x\n", &c);
printf("Value of a: %d\n", a);
printf("Value of b: %x\n", b);
printf("Value of c: %x\n", c);
Output:
Address of a: 28ff44
Address of b: 28ff40
Address of c: 28ff3c
Value of a: 5
Value of b: 28ff44
Value of c: 28ff40
In this case
int main()
{
int a=5,*b,*c;
b=&a;
c=&b;
}
Here b points to a and c points to b. It is what you have commented in the commented.
c still points to the memory location of b.
The catch is : When you de-reference b i.e *b = a = 5.
But When you de-reference c i.e *c = b = &a. So When you dereference c the output would be address of a instead of the value of the variable a
PS : you will face this warning when compiling the code warning: assignment from incompatible pointer type
Every level of indirection needs a level of dereferencing. So for:
T*** x = ...;
you would need:
***x
to get to T&.
If you had a pointer to pointer and you saved it in:
T* x = ...;
T* y = &x;
it would mean that *ptr leads to T&, while it really leads to another T*.
You have your answer in your question only.
pointer to variable , use of *
pointers to pointer of a variable , use **
Details:
** is not a new operator. it's a combination of * and *. In case 2. as per your terminology, you can think of
only single * to point a pointer to another pointer
as in
int * to an inother int * ==> int **
EDIT:
as per your code
int main()
{
int a=5,*b,*c;
b=&a;
c=&b;
}
b is a pointer to int. You can store the address of int there, and a is an int. Perfect.
c is a pointer to int. You can store the address of int there, and b is a pointer to int. Not accepted.
To make point 2 work, you need to declare c as a pointer to int *, right? The notation for the same is int **.
Here's another way to think of pointers-to-pointers: imagine how it works in memory. Here's a little snippet that shows what I mean:
int TheInteger = 123;
int *p = &TheInteger;
int **pp = &p;
printf("The value at memory location &pp (0x%x) is 0x%x (pp). This value (which we assigned as &p (0x%x) is 0x%x (p). This value, in turn, we assign as &TheInegeter (0x%x) points to the 'instance' of TheInteger, which is %d", &pp, pp, &p, p, &TheInteger, TheInteger);
The output of this would be:
The value at memory location &pp (0x657e588) is 0x657e594 (pp). This value (which we assigned as &p (0x657e594) is 0x657e5a0 (p). This value, in turn, we assign as &TheInegeter (0x657e5a0) points to the 'instance' of TheInteger, which is 123
Now, to go back to your original question, you cannot declare a variable as being a pointer when the value you're setting it to is a pointer-to-a-pointer. In other words, in your example, you set 'b' as a pointer to a -- so, you can't tell the compiler that 'c' is just a pointer and then try to set it to a value that the compiler knows is a pointer-to-a-pointer.
I thought array and pointer are basically the same thing, until I run this program:
int main() {
int* a = new int(19);
int b[1];
b[0] = 19;
printf("*a: %d\n a: %p\n &a:%p\n", *a, a, &a);
printf("*b: %d\n b: %p\n &b:%p\n", *b, b, &b);
delete a;
}
output is:
*a: 19
a: 0x7f94524000e0
&a:0x7fff51b71ab8
*b: 19
b: 0x7fff51b71ab4
&b:0x7fff51b71ab4
can someone please explain why the output of &b is the same as b?
Thanks!
-Erben
Well, b is an array. Under the slightest excuse it will decay into a pointer to the first element of b. Note, however, that the expression b and &b are not equivalent: b decays into a pointer the first element, i.e., it is of type int* while &b is a pointer to the array, i.e., it is of type int(*)[1].
Arrays and pointers are not the same. A pointer can behave like an array (e.g. accessing by index).
&b is a pointer to the whole array and b is a pointer to the first element. They may point to a same address in memory but they are totally different things.
+-------------------------------+
|+-----+-----+-----+-----+-----+|
|| | | | | ||
&b---->|| 0 | 1 | 2 | ... | N ||
|| | | | | ||
|+-----+-----+-----+-----+-----+|
+---^---------------------------+
|
b
a is a variable. You are allocating memory using new and assigning the result to this pointer. You might decide to store something else in a later in your program.
b is different. It's not a variable in the sense that it cannot store different addresses. It's an array, having a fixed start location.
Thus, b and &b are same. But the contents of a and the actual address of a are different.
This is basically just to help me understand pointers better, so if you guys can confirm/deny/explain anything it looks like I don't understand properly I would be most appreciative. The examples of using mailboxes, and aunts, and streets, and all that crap is just confusing.
int a = 5;
int b = &a; // b will be the memory address of 'a'
int *c = a; // c will be the value of 'a' which is 5
int *d = &a; // d will be a pointer to the memory address of 'a'
int &e = a; // what would this be?
void FunctionA()
{
int a = 20;
FunctionB(&a);
// a is now 15?
}
void FunctionB(int *a)
{
a = 15;
}
Thank you guys for any help, I am just trying to improve my understanding beyond all of the crappy metaphor explanations im reading.
I'll take things one by one:
int b = &a; // b will be the memory address of 'a'
No. The compiler (probably) won't allow this. You've defined b to be an int, but &a is the address of an int, so the initialization won't work.
int *c = a;
No -- same problem, but in reverse. You've defined c to be a pointer to an int, but you're trying to initialize it with the value of an int.
int *d = &a;
Yes -- you've defined d to be a pointer to an int, and you're assigning the address of an int to it -- that's fine. The address of an int (or an array of ints) is what a pointer to int holds.
int &e = a;
This defines e to be a reference to an int and initializes it as a reference to a. It's perfectly legitimate, but probably not very useful. Just for Reference, the most common use of a reference is as a function parameter (though there are other purposes, of course).
void FunctionA() { int a = 20; FunctionB(&a); }
void FunctionB(int *a) { a = 15; }
To make this work, you need to change the assignment in FunctionB:
void FunctionB(int *a) { *a = 15; }
As it was, you were trying to assign an int to a pointer, which won't work. You need to assign the int to the int that the pointer points at to change the value in the calling function.
int &e = a; // what would this be?
e is a reference to a. In this case the ampersand is not the 'address of' operator. You treat e as you would a normal (not a pointer) variable, but the value of e and of a will be the same no matter what you do to either (as long as both remain in scope) as essentially e is just an alias.
int a = 5;
So far so good.
int b = &a; // b will be the memory address of 'a'
That's actually a compilation error. You probably mean int *b=&a;. b is a POINTER to an integer.
edit: If you mean to get the address in numerical form, you need to force the cast to an integer: int b=(int)&a;
int *c = a; // c will be the value of 'a' which is 5
This one is more confusing. At its core, a pointer is just a number, sure, but this kind of assignement is inherently not safe (as you can see, you're assigning 5 to a pointer, and trying to dereference that will most likely crash your program). If you really do want c to point at the memory location 5, you have to explicitly tell the compiler you know what you're doing: int *c=(int *)a.
int *d = &a; // d will be a pointer to the memory address of 'a'
This one is right, same as what you probably mean by the second one.
int &e = a; // what would this be?
e is a "reference" to a. Basically internally it's just a pointer to a, but you don't have to manually dereference it, the compiler handles it for you.
void FunctionA() { int a = 20; FunctionB(&a); // a is now 15? }
Yes.
void FunctionB(int *a) { a = 15; }
...assuming you write this as *a=15;. You're overwriting the VALUE pointed to by a, not the pointer itself.
You seem pretty confused by this overall, I recommend reading the book "Thinking in C++", it's really well written!
You've got plenty of good answers here for your specific example, so I'd like to share a general technique that I used to learn how pointers work when I was starting out.
Get a big sheet of graph paper and lay it lengthwise on the table in front of you. This is your computer's memory. Each box represents one byte. Pick a row, and place the number '100' below the box at far left. This is "the lowest address" of memory. (I chose 100 as an arbitrary number that isn't 0, you can choose another.) Number the boxes in ascending order from left to right.
+---+---+---+---+---+--
| | | | | | ...
+---+---+---+---+---+--
100 101 102 103 104 ...
Now, just for the moment, pretend an int is one byte in size. You are an eight-bit computer. Write your int a into one of the boxes. The number below the box is its address. Now choose another box to contain int *b = &a. int *b is also a variable stored somewhere in memory, and it is a pointer that contains &a, which is pronounced "a's address".
int a = 5;
int *b = &a;
a b
+---+---+---+---+---+--
| 5 | |100| | | ...
+---+---+---+---+---+--
100 101 102 103 104 ...
Now you can use this model to visually work through any other combinations of values and pointers that you see. It is a simplification (because as language pedants will say, a pointer isn't necessarily an address, and memory isn't necessarily sequential, and there's stack and heap and registers and so on), but it's a pretty good analogy for 99% of computers and microcontrollers.
You can extend the model for real four-byte ints too...
int a = 5;
char b = 2;
a a a a b
+---+---+---+---+---+--
| 0 | 0 | 0 | 5 | 2 | ...
+---+---+---+---+---+--
100 101 102 103 104 ...
int &e=a; is a reference to "a".
and these are bugs:
int b = &a;
int *c = a;
I think you mean:
int *b = &a;, which makes a pointer called b that points to the value of a (b is a pointer which is the address of a)
int c = *b;, (or just int c = a if you only want c to have a's value) In this case, * dereferences the pointer b
FunctionA() See below, then a will be 15 (you're passing the address of a to FunctionB)
void FunctionB(int *a) {*a = 15;} sets the value to 15 (* dereferences)