I'm currently learning C and I'm confused about memory layout and pointers.
In the following code, it is my understanding that the array is allocated on the stack.
#include <stdio.h>
int main () {
int x[4];
x[0] = 3; x[1] = 2; x[2] = 1;
printf("%p\n",x);
printf("%p\n", &x);
}
My question is, why do the two print calls output the same value?
I tried a similar snippet using malloc (allocate on the heap), and the values differ.
#include <stdio.h>
#include <stdlib.h>
int main () {
int *x = malloc(sizeof(int) * 4);
x[0] = 3; x[1] = 2; x[2] = 1;
printf("%p\n",x);
printf("%p\n", &x);
}
The reason is that unlike you were probably taught, arrays are not pointers. Arrays in C decay into pointers1 under some circumstances. When you pass an array to a function, it decays into a pointer to the first element. The address of that element is the same as the address of the entire array (an address is always to the first byte of an object).
What you get from malloc is not an array, but the address of a chunk of memory. You assign the address to a pointer. But the pointer and the chunk are separate entities. So printing the value of the pointer, as opposed to its address, yields different results.
(1) Decay is a fancy term for a type of implicit type conversion. When an array expression is used in most places (such as being passed as an argument to a function that expects a pointer), it automatically turns into a pointer to its first element. The "decay" is because you lose type information, i.e. the array size.
Your two print calls print the same value because one tries to print the array, which decays to a pointer to the array, and the other prints the address of the array. A pointer to the array contains the address of the array, so they're the same value.
In the second case, one prints the value of x, the other prints the address of x. Since x is a pointer to the block of memory you allocated, these must be different values.
So in the first case, all you have is an array (x). In the second case, you have an allocated block of memory (unnamed) and a pointer to that allocated block (x).
It is perhaps surprising that one can indeed take the address of a whole array, partly because one doesn't need to very often. The array in a sense is a single object, which has one address, which is the address of its first byte. Like with all objects, the address is obtained with the address operator, &.
The first element of an array (like all of its elements) has an address, too, which is the address of its first byte. A pointer to its first element is what the array type is "adjusted" to when it is passed as an argument to a function.
These two bytes are identical, and have the same address. But they have different types, which becomes obvious if you add 1 to them and print them again.
The pointer y, by contrast, is its own distinct object (probably 4 or 8 bytes in size; enough to store an address in it). Like any object it has an address which can be obtained with the & operator. Perhaps confusingly, it also contains an address, in this case the address of the first byte of the array. The two are of course not equal: The pointer object resides at a different location than the array (namely next to it on the stack, even if Olaf doesn't like that).
Minor remark: You use %p for printing pointers, which is good. If you do that, you should strictly spoken cast the pointer which you print to a void pointer: printf("%p\n", (void *)x);.
Related
I've recently been messing around with pointers and I would like to know a bit more about them, namely how they are organized in memory after using malloc for example.
So this is my understanding of it so far.
int **pointer = NULL;
Since we explicitly set the pointer to NULL it now points to the address 0x00.
Now let's say we do
pointer = malloc(4*sizeof(int*));
Now we have pointer pointing to an address in memory - let's say pointer points to the address 0x0010.
Let's say we then run a loop:
for (i = 0; i<4; i++) pointer[i] = malloc(3*sizeof(int));
Now, this is where it starts getting confusing to me. If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]? And if so, what is pointer[0]?
Continuing, now supposedly pointer[i] contains stored in it an address. And this is where it really starts confusing me and I will use images to better describe what I think is going on.
In the image you see, if it is correct, is pointer[0] referring to the box that has the address 0x0020 in it? What about pointer[1]?
If I were to print the contents of pointer would it show me 0x0010? What about pointer[0]? Would it show me 0x0020?
Thank you for taking the time to read my question and helping me understand the memory layout.
Pointer Refresher
A pointer is just a numeric value that holds the address of a value of type T. This means that T can also be a pointer type, thus creating pointers-to-pointers, pointers-to-pointers-to-pointers, and crazy things like char********** - which is simply a pointer (T*) where T is a pointer to something else (T = E*) where E is a pointer to something else (and so on...).
Something to remember here is that a pointer itself is a value and thus takes space. More specifically, it's (usually) the size of the addressable space the CPU supports.
So for example, the 6502 processor (commonly found in old gaming consoles like the NES and Atari, as well as the Apple II, etc.) could only address 16 bits of memory, and thus its "pointers" were 16-bits in size.
So regardless of the underlying type, a pointer will (usually) be as large as the addressable space.
Keep in mind that a pointer doesn't guarantee that it points to valid memory - it's simply a numeric value that happens to specify a location in memory.
Array Refresher
An array is simply a series of T elements in contiguously addressable memory. The fact it's a "double pointer" (or pointer-to-a-pointer) is innocuous - it is still a regular pointer.
For example, allocating an array of 3 T's will result in a memory block that is 3 * sizeof(T) bytes long.
When you malloc(...) that memory, the pointer returned simply points to the first element.
T *array = malloc(3 * sizeof(T));
printf("%d\n", (&array[0] == &(*array))); // 1 (true)
Keep in mind that the subscript operator (the [...]) is basically just syntactic sugar for:
(*(array + sizeof(*array) * n)) // array[n]
Arrays of Pointers
To sum all of this up, when you do
E **array = malloc(3 * sizeof(E*));
You're doing the same thing as
T *array = malloc(3 * sizeof(T));
where T is really E*.
Two things to remember about malloc(...):
It doesn't initialize the memory with any specific values (use calloc for that)
It's not guaranteed (nor really even common) for the memory to be contiguous or adjacent to the memory returned by a previous call to malloc
Therefore, when you fill the previously created array-of-pointers with subsequent calls to malloc(), they might be in arbitrarily random places in memory.
All you're doing with your first malloc() call is simply creating the block of memory required to store n pointers. That's it.
To answer your questions...
If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]?
Since pointer is just a int**, and remembering that malloc(...) returns the address of the first byte in the block of memory you allocated, *pointer will indeed evaluate to pointer[0].
And if so, what is pointer[0]?
Again, since pointer as the type int**, then pointer[0] will return a value type of int* with the numeric contents of the first sizeof(int*) bytes in the memory block pointed to by pointer.
If I were to print the contents of pointer would it show me 0x0010?
If by "printing the contents" you mean printf("%p\n", (void*) pointer), then no.
Since you malloc()'d the memory block that pointer points to, pointer itself is just a value with the size of sizeof(int**), and thus will hold the address (as a numeric value) where the block of memory you malloc()'d resides.
So the above printf() call will simply print that value out.
What about pointer[0]?
Again assuming you mean printf("%p\n", (void*) pointer[0]), then you'll get a slightly different output.
Since pointer[0] is the equivalent of *pointer, and thus causes pointer to be dereferenced, you'll get a value of int* and thus the pointer value that is stored in the first element.
You would need to further dereference that pointer to get the numeric value stored in the first integer that you allocated; for example:
printf("%d\n", **pointer);
// or
printf("%d\n", *pointer[0]);
// or even
printf("%d\n", pointer[0][0]); // though this isn't recommended
// for readability's sake since
// `pointer[0]` isn't an array but
// instead a pointer to a single `int`.
If I dereference pointer, by doing *pointer what do I get? pointer[0]?
Yes.
And if so, what is pointer[0]?
With your definitions: 0x0020.
In the image you see, if it is correct
It seems correct to me.
is pointer[0] referring to the box that has the address 0x0020 in it?
Still yes.
What about pointer[1]?
At this point, I think you can guess that it woud show: 0x002c.
To go further
If you want to check how memory is managed and what pointers look like you can use gdb. It allows running a program step by step and performing various operations such as showing the content of variables. Here is the main page for GNU gdb. A quick internet search should let you find numerous gdb tutorials.
You can also show the address of a pointer in c by using a printf line:
int *plop = NULL;
fprintf(stdout, "%p\n", (void *)pointer);
Note: don't forget to include <stdio.h>
here i am printing out an element of a multi dimensional array using a pointer.Generally we had to put an asterisk to print out pointer value.But here i can print value without asterisk .What might be the reason for this?
#include <stdio.h>
#include <string.h>
int main ()
{
int arr[1][2]={{1,2},{3,4}};
int *ptr;
ptr=arr;
printf("%d",(ptr[0]+1)); // *(ptr[0]+1) giving error
}
You declared ptr as "int *ptr" which means "ptr points to a 1-dimensional memory location that contains an int". And in C a pointer for the most part is equivalent to an array (which is also a pointer to a memory location).
Then you assign it a value "ptr = arr" which now means "ptr points to memory location which contains an int"
Now you can deference either with *ptr (which means "return the value in memory location pointed to by ptr") or with ptr[0] (which means "retrieve the first element of the array in memory location pointed to by ptr"). Both would return the same value - the value in memory location ptr
So, doing "ptr[0] +1" means "retrieve the first element in memory location pointed to by ptr, and then add 1 to that retrieved value".
The primary problem with your code is that you declared a two-dimensional array (and btw - you declared a 1x2 array but filled it with a 2x2 set of initial values), but then you declared a one-dimensional pointer to access it with. Perfectly valid in C as it provides infinite ways to shoot your own foot with, but not what you wanted.
I suggest turning on all compile warnings - you should get a number of them in your code snippet...
#include<stdio.h>
#include<stdlib.h>
int main(){
int myChr[4][8];
printf("%x\n",myChr);
printf("%x\n",&myChr);
printf("%x\n",*myChr);
return 0;
}
After executing the above program, I get the same address as output. Do they own different value or all of them have same value? How to prove that? (*Maybe need to assume values to array, I don't know)
myChr is the address on the stack of your array.
&mychr, in this case, is probably going to give you the same value as it is the address of the pointer on the stack.
*myChr is the address of 1st entry of myChr[4][8] entry, which in the case is still the original address.
**myChar would give you the value of myChr[0][0] - in this case garbage as you have not actually assigned anything to your array.
myChar is a int [4][8].
In the printf expression:
myChar is of type int (*)[8] (after application of C array to pointer conversion rule from int [4][8])
&myChar is of type int (*) [4][8]
*myChar is of type int * (after application of C array to pointer conversion rule from int [4])
All the expressions have different types but they point to the same memory address, that is:
(void *) myChar == (void *) &myChar == (void *) *myChar
Note that the valid way to print a pointer value is to use p conversion specifier and cast the pointer to void * if it is of a different type.
Arrays are simply named extents of memory. So the address of an array is the address of the extent it occupies. At the same time it is the address of the first element of the array because it occupies the initial part of the extent.
Thus you have:
this statement
printf("%x\n",myChr);
displays the address of the first element of the array because array name is implicitly converted to pointer to its first element;
this statement
printf("%x\n",&myChr);
displays the address of the array that is the same address as above because it is the address of the allocated extent;
this statement
printf("%x\n",*myChr);
displays the same address. Why? As I have already said the name of the array is implicitly converted to pointer to its first element. The element of the array is in turn a one-dimensional array. So in expression this one-dimensional array *myChr (the first element of the original two-dimensional array) in turn is converted to pointer to its first element.
So in all three cases you display this address :)
&myChr[0][0]
I have been following some examples that declare an int pointer
int *myInt;
and then turn that pointer into an array
myInt = (int*)malloc(1024);
this checks out
myInt[0] = 5;
cout << myInt[0]; // prints 5
myInt[1] = 7;
cout << myInt[1]; // prints 7
I thought an int pointer was a pointer to an int and never anything else. I know that pointers to strings just point to the first character of the string but it looks like the same sort of thing is happening here with an array of ints. But then if what we want is an array of ints why not just create an array of ints instead of a pointer to an int?
By the way I am interested in how this works in C not C++. This is in a C++ file but the relevant code is in C.
Is an int pointer an array of ints?
No.
I thought an int pointer was a pointer to an int and never anything else
That's right. Pointers are pointers, arrays are arrays.
What confuses you is that pointers can point to the first element of arrays, and arrays can decay into pointers to their first element. And what's even more confusing: pointers have the same syntax for dereferencing and pointer arithmetic that arrays utilize for indexing. Namely,
ptr[i]
is equivalent with
*(ptr + i)
if ptr is a pointer. Of course, similarly, arr[i] is the ith element of the arr array too. The similarity arises out of the common nature of pointers and arrays: they are both used to access (potentially blocks of) memory indirectly.
The consequence of this strong relation is that in some situations (and with some constraints), arrays and pointers can be used as if they were interchangeable. This still doesn't mean that they are the same, but they exhibit enough common properties so that their usage often appears to be "identical".
There is an alternative syntax for accessing items pointed by a pointer - the square brackets. This syntax lets you access data through pointers as if the pointer were an array (of course, pointers are not arrays). An expression a[i] is simply an alternative form of writing *(a+i)* .
When you allocate dynamic storage and assign it to myInt, you can use the pointer like a dynamic array that can change size at runtime:
myInt = malloc(1024*sizeof(int)); // You do not need a cast in C, only in C++
for (int i = 0 ; i != 1024 ; i++) {
myInt[i] = i; // Use square bracket syntax
}
for (int i = 0 ; i != 1024 ; i++) {
printf("%d ", *(myInt+i)); // Use the equivalent pointer syntax
}
* Incidentally, commutativity of + lets you write 4[array] instead of array[4]; don't do that!
Sort of, and technically no. An int pointer does point to the int. But an array of ints is contiguous in memory, so the next int can be referenced using *(myInt+1). The array notation myInt[1] is equivalent, in that it uses myInt pointer, adds 1 unit to it (the size of an int), and reference that new address.
So in general, this is true:
myInt[i] == *(myint + i)
So you can use an int pointer to access the array. Just be careful to look out for the '\0' character and stop.
An int pointer is not an array of ints. But your bigger question seems to be why both arrays and pointers are needed.
An array represents the actual storage in memory of data. Once that storage is allocated, it makes no significant difference whether you refer to the data stored using array notation or pointer notation.
However, this storage can also be allocated without using array notation, meaning that arrays are not necessarily needed. The main benefit of arrays is convenient allocation of small blocks of memory, i.e., int x[20] and the slightly more convenient notation array[i] rather than *(array+i). Thankfully, this more convenient notation can be used regardless of whether array came from an array declaration or is just a pointer. (Essentially, once an array has been allocated, its variable name from that point onwards is no different than a pointer that has been assigned to point to the location in memory of the first value in the array.)
Note that the compiler will complain if you try to directly allocate too big of a block of memory in an array.
Arrays:
represent the actual memory that is allocated
the variable name of the array is the same as a pointer that references the point in memory where the array begins (and the variable name + 1 is the same as a pointer that references the point in memory where the second element of the array begins (if it exists), etc.)
values in the array can be accessed using array notation like array[i]
Pointers:
are a place to store the location of something in memory
can refer to the memory that is allocated in an array
or can refer to memory that has been allocated by functions like malloc
the value stored in the memory pointed to by the pointer can be accessed by dereferencing the pointer, i.e., *pointer.
since the name of the array is also a pointer, the value of the first element in the array can be accessed by *array, the second element by *(array+1), etc.
an integer can be added or subtracted to a pointer to create a new pointer that points to other values within the same block of memory your program has allocated. For example, array+5 points to the place in memory where the value array[5] is stored.
a pointer can be incremented or decremented to point to other values with the same block of memory.
In many situations one notation will be more convenient than the other, so it is extremely beneficial that both notations are available and so easily interchanged with each other.
They are not the same. Here is the visible difference.
int array[10];
int *pointer;
printf ("Size of array = %d\nSize of pointer = %d\n",
sizeof (array), sizeof (pointer));
The result is,
Size of array = 40
Size of pointer = 4
If You do "array + 1", the resulting address will be address of array[0] + 40. If You do "pointer + 1", resulting address will be address of pointer[0] + 4.
Array declaration results in compile time memory allocation. Pointer declaration does not result in compile time memory allocation and dynamic allocation is needed using calloc() or malloc()
When you do following assignment, it is actually implicit type cast of integer array to integer pointer.
pointer = array;
First I declare an array a with 10 elements. Then I call the function bubbleSort
bubbleSort( a, 10);
where bubbleSort is a function declared as
void bubbleSort(int* const array, const int size)
My question is if "array" is a pointer- which means it stored the address of array a (array= &a [0]) then how can we understand these terms array[1], array[2], array[3]... in the function bubbleSort?
It is the bubble sort program and this part is very confusing for me.
array[1] means, by definition in the C standard, *(array+1). So, if array is a pointer, this expression adds one element to the pointer, then uses the result to access the pointed-to object.
When a is an array, you may be used to thinking of a[0], a[1], a[2], and so on as elements of the array. But they actually go through the same process as with the pointer above, with one extra step. When the compiler sees a[1] and a is an array, the compiler first converts the array into a pointer to its first element. This is a rule in the C standard. So a[1] is actually (&a[0])[1]. Then the definition above applies: (&a[0])[1] is *(&a[0] + 1), so it means “Take the address of a[0], add one element, and access the object the result points to.”
Thus, a[1] in the calling code and array[1] in the called code have the same result, even though one starts with an array and the other uses a pointer. Both use the address of the first element of the array, add one element, and access the object at the resulting address.
C defines operations of addition and subtraction of integers and pointers, collectively called pointer arithmetics. The language specification says that adding N to a pointer is equivalent to advancing the pointer by N units of memory equal to the size of an object pointed to by the pointer. For example, adding ten to an int pointer is the same as advancing it by ten sizes of int; adding ten to a double pointer is equivalent to advancing the pointer by ten sizes of double, and so on.
Next, the language defines array subscript operations in terms of pointer arithmetics: when you write array[index], the language treats it as an equivalent of *((&array[0])+index).
At this point, the language has everything necessary to pass arrays as pointers: take &array[0], pass it to the function, and let the function use array subscript operator on the pointer. The effect is the same as if the array itself has been passed, except the size of the array is no longer available. The structure of your API indirectly acknowledges that by passing the size of the array as a separate parameter.
You have an array of int, identified by the address of its first element.
array[1] Is equivalent to *(array + 1) which mean "The value of what is pointed by array + the size of one element, which is known as int because you prototyped it as int *"
When you declare a to be an array of size 10, the c program stores the address of a[0] in a and since the memory is allocated continuously therefore you can access the subsequent integers by using a[2], a[4] etc. Now when you copy a to array it is actually the address that gets copied and therefore you can access the integers using array[0], array[1] etc.