Apologies i got frustrated and posted question through mobile without proper details
Consider the following C++ code:
int arr[2];
arr[0] = 10;
arr[1] = 20;
// cout << &arr;
for (int i = 0; i < 2; i++)
{
cout << &arr + i << "\t\t"<<endl;
}
cout << sizeof (arr);
cout in for loop prints following
0x7ffeefbff580 0x7ffeefbff588
which is 8 bytes farther than the first element
My question is why it is 8 bytes further and not 4 bytes if on my machine sizeof(int) is 4?
Now that you gave us the code we can answer your question.
So the confusing piece is this: &arr + i. This does not do what you think it does. Remember that & takes precedence over +. And so you take address of arr and move it forward i times.
Pointer arithmetic works in such a way that &x + 1 moves the pointer forward by size(x). So in your case what is size(arr)? It is 8 because it is 2-element array of integers (I'm assuming ints are of size 4). And so &arr + 1 actually moves the pointer 8 bytes forward. The exact thing you experience. You don't ask for next int, you ask for next array. I encourage you to play around, for example define arr as int[3] (which is of size 12) and see how the pointer moves 12 bytes forward.
So first solution is to do arr + i without &. We can apply pointer arithmetic to an array in which case it decays to a pointer type int*. Now since int is of size 4 then arr + 1 points correctly to a memory segment 4 bytes forward.
But what I suggest is to stay away from pointer arithmetic and do &arr[i] instead. This does the same thing but IMO is less error prone, less confusing and tells us more about the intent.
Related
Value of a pointer is address of a variable. Why value of an int pointer increased by 4-bytes after the int pointer increased by 1.
In my opinion, I think value of pointer(address of variable) only increase by 1-byte after pointer increment.
Test code:
int a = 1, *ptr;
ptr = &a;
printf("%p\n", ptr);
ptr++;
printf("%p\n", ptr);
Expected output:
0xBF8D63B8
0xBF8D63B9
Actually output:
0xBF8D63B8
0xBF8D63BC
EDIT:
Another question - How to visit the 4 bytes an int occupies one by one?
When you increment a T*, it moves sizeof(T) bytes.† This is because it doesn't make sense to move any other value: if I'm pointing at an int that's 4 bytes in size, for example, what would incrementing less than 4 leave me with? A partial int mixed with some other data: nonsensical.
Consider this in memory:
[↓ ]
[...|0 1 2 3|0 1 2 3|...]
[...|int |int |...]
Which makes more sense when I increment that pointer? This:
[↓ ]
[...|0 1 2 3|0 1 2 3|...]
[...|int |int |...]
Or this:
[↓ ]
[...|0 1 2 3|0 1 2 3|...]
[...|int |int |...]
The last doesn't actually point an any sort of int. (Technically, then, using that pointer is UB.)
If you really want to move one byte, increment a char*: the size of of char is always one:
int i = 0;
int* p = &i;
char* c = (char*)p;
char x = c[1]; // one byte into an int
†A corollary of this is that you cannot increment void*, because void is an incomplete type.
Pointers are increased by the size of the type they point to, if the pointer points to char, pointer++ will increment pointer by 1, if it points to a 1234 bytes struct, pointer++ will increment the pointer by 1234.
This may be confusing first time you meet it, but actually it make a lot of sense, this is not a special processor feature, but the compiler calculates it during compilation, so when you write pointer+1 the compiler compiles it as pointer + sizeof(*pointer)
As you said, an int pointer points to an int. An int usually takes up 4 bytes and therefore, when you increment the pointer, it points to the "next" int in the memory - i.e., increased by 4 bytes. It acts this way for any size of type. If you have a pointer to type A, then incrementing a A* it will increment by sizeof(A).
Think about it - if you only increment the pointer by 1 byte, than it will point to a middle of an int and I can't think of an opportunity where this is desired.
This behavior is very comfortable when iterating over an array, for example.
The idea is that after incrementing, the pointer points to the next int in memory. Since ints are 4 bytes wide, it is incremented by 4 bytes. In general, a pointer to type T will increment by sizeof(T)
A pointer points at the BEGINNING of something in memory. An INT occupies 4 bytes (32bit) and a DOUBLE occupies 8 bytes (64bit) in memory. So if you have a DOUBLE number stored, and you wish at a very low level pointing to the next available memory location, the pointer wooud be increased by 8 bytes. If for some reason you pointed at +4bytes from the start of a DOUBLE value, you would corrupt it's value. Memory is a very large flat field that has no conscience of itself, so it's up to the software to divides it properly and to "respect the borders" of items located in that field.
I am learning C++, and read that when an array is passed into a function it decays into a pointer. I wanted to play around with this and wrote the following function:
void size_print(int a[]){
cout << sizeof(a)/sizeof(a[0]) << endl;
cout << "a ->: " << sizeof(a) << endl;
cout << "a[0] ->" << sizeof(a[0]) << endl;
}
I tried inputting an array with three elements, let's say
int test_array[3] = {1, 2, 3};
With this input, I was expecting this function to print 1, as I thought a would be an integer pointer (4 bytes) and a[0] would also be 4 bytes. However, to my surprise the result is 2 and sizeof(a) = 8.
I cannot figure out why a takes up 8 bytes, but a[0] takes up 4. Shouldn't they be the same?
Shouldn't they be the same?
No. a is (meant to be) an array (but because it's a function argument, has been adjusted to a pointer to the 1st element), and as such, has the size of a pointer. Your machine seems to have 64 bit addresses, and thus, each address (and hence, each pointer) is 64 bits (8 bytes) long.
a[0], on the other hand, is of the type that an element of that array has (an int), and that type has 32 bits (4 bytes) on your machine.
A pointer is just an address of memory where the start of the variable is located. That address is 8 bytes.
a[0] is a variable in the first place of the array. It technically could be anything of whatever size. When you take a pointer to it, the pointer just contains an address of memory (integer) without knowing or caring what this address contains. (This is just to illustrate the concept, in the example in the question, a[] is an integer array but the same logic works with anything).
Note, the size of the pointer is actually different on different architectures. This is where the 32-bit, 64-bit, etc. comes in. It can also depend on the compiler but this is beyond the question.
The size of the pointer depends on the system and implementation. Your uses 64 bits (8 bytes).
a[0] is an integer and the standard only gives an indication of the minimum max value it has to store. It can be anything from 2 bytes up. Most modern implementations use 32 bits (4 bytes) integers.
sizeof(a)/sizeof(a[0]) will not work on the function parameters. Arrays are passed by the reference and this division will only give you information how many times size of the pointer is larger than the size of an integer, but not the size of the object referenced by the pointer.
When I declared an integer array of size 10 and check the size it gives 40 but when I declared integer pointer variable with an array of size 10 and I try to check the size it always gives 8. Why?
int A[10];
cout<<sizeof(A)<<endl; // it gives 40;
int *p;
p = new int[10];
cout<<sizeof(*p)<<endl; // but it gives always 8;
sizeof(p) is always going to be sizeof(int*), which is 8 on your platform.
That does not change regardless of the number of objects you allocate using new [].
A is of type int [10] (an array of 10 ints). Its size is 10 * sizeof(int).
It makes sense that sizeof(A) is 40.
Pointers and arrays are different types. They can be used interchangeably in many use cases but it's also important to know how they are different and where they behave differently. sizeof operator is one of the use cases where they are different.
On a typical 64-bit machine, sizeof(*p) should be 4, while sizeof(p) should be 8.
Hopefully this example clears things up:
int p1[10];
cout<<sizeof(*p1)<<endl; // 4 size of the first element (int)
cout<<sizeof(p1)<<endl; // 40 size of array (int size * 10)
int *p2;
p2 = new int[10];
cout<<sizeof(*p2)<<endl; // 4 size of the first element (int)
cout<<sizeof(p2)<<endl; // 8 size of the pointer on 64-bit system
// shows how you're getting the first value by dereferencing
cout<<*p2<<endl; // 0
p2[0] = 100;
cout<<*p2<<endl; // 100
Always pointer holds the starting address of an array. Since it's an int pointer, and the size of the int in ur system is 8 bytes, it shows 8 bytes.
In attempt to explain that arrays are just pointers (in C++) to our class, my professor showed us this:
array[5] // cout'ing this
*(array + 5) // would return the same value as this
I'm having a little trouble completely understanding it. Here's my thinking:
array is the address of the first location and so if we add 5 to that address, we move 5 addresses in memory. The pointer operator pulls the data from the memory location.
Is this the correct idea? The idea still feels foggy with me and just feel like I don't understand it completely. I think hearing someone else explain it might help me understand it more. Thanks in advance!
You've got the right idea.
Arrays implicitly cast to pointers. Interestingly, [] works on pointers, not arrays.
a[b] Subscript operator is defined as *(a + (b)). [] is used as syntactic sugar - it's much more pleasant to write array[5] instead of *(array + 5)
Pointer arithmetic with a pointer and an integer p + i increases the address at p by i * sizeof(*p) bytes.
char* p;
p + 5; // address increased by 5
int* p;
p + 5; // address increased by 20 as sizeof(*p) is 4
The * operator performs indirection. It will give you what the pointer is pointing to.
int x[2];
int* p = &x[0]; // could also be int* p = x;
*p = 5; // x[0] is now 5
*(p + 1) = 10; // x[1] is now 10
Your professor is correct that the two expressions will produce the same results. Your explanation of it leads me to believe you have a good grasp of the mechanics.
It is not quite correct to say an array is the same as a pointer. An array is very easily converted to a pointer, which leads to some confusion.
For example consider this code:
int array[5];
int * pointer = new int[5];
cout << sizeof(array); // outputs 5*sizeof(int), most probably 20
cout << sizeof(pointer); // outputs sizeof(int*), most probably 4 on a 32 bit OS
array[4] = 906;
pointer[4] = 906;
cout << *(array + 4) << *(pointer + 4); // outputs "906 906"
from memory arrays in c++ are sections of continuous memory the program. thats why you can go *(array + 5) as it is 5 from the front of the array.
Also keep in mind that arrays in C++ start # 0 so thus the 6th element in an array is array[5]
example
[0] [1] [2] [3] [4] [5] Array index
1 2 3 4 5 6 Item number
To access item 2 u would either
array[1]
*(array+1)
but please keep in mind array[index_number] is standard syntax for looking up an item in an array so make sure u use array[index_num] instead of *(array + index_num)
Yes, what your proffessor said is correct.
to explain it in detail
Consider your array,
int array[5]
here it takes 5 location in the memory say 0x00 0x04 0x08 0x0C and 0x10 0x14
Assuming integer takes 4 bytes, the locations are 4 bytes apart.
it this case 'array' represents the base address (pointer) to the array, that is 0x00. And the type of a would be int *. (since the type of the array elements is integer)
If you do array+1, it will be 0x04, since the increment of the pointer depends on the type of the pointer. If the pointer is integer, it will increment by 4 bytes. If the type of the integer is character, the pointer would increment by one bytes.
so if you do (array+5) it would point to the address 0x14 and
*(array+5)
returns the value of the location 0x14 which is the value at 5th location of array.
so in practical, array[5] is equal to *(array+5)
The compiler internally converts array[5] to *(array+5)
so even if we write 5[array], it will get converted it to *(5+array)
Though it seems strange, this is the reason why 5[array] works same as array[5]
Value of a pointer is address of a variable. Why value of an int pointer increased by 4-bytes after the int pointer increased by 1.
In my opinion, I think value of pointer(address of variable) only increase by 1-byte after pointer increment.
Test code:
int a = 1, *ptr;
ptr = &a;
printf("%p\n", ptr);
ptr++;
printf("%p\n", ptr);
Expected output:
0xBF8D63B8
0xBF8D63B9
Actually output:
0xBF8D63B8
0xBF8D63BC
EDIT:
Another question - How to visit the 4 bytes an int occupies one by one?
When you increment a T*, it moves sizeof(T) bytes.† This is because it doesn't make sense to move any other value: if I'm pointing at an int that's 4 bytes in size, for example, what would incrementing less than 4 leave me with? A partial int mixed with some other data: nonsensical.
Consider this in memory:
[↓ ]
[...|0 1 2 3|0 1 2 3|...]
[...|int |int |...]
Which makes more sense when I increment that pointer? This:
[↓ ]
[...|0 1 2 3|0 1 2 3|...]
[...|int |int |...]
Or this:
[↓ ]
[...|0 1 2 3|0 1 2 3|...]
[...|int |int |...]
The last doesn't actually point an any sort of int. (Technically, then, using that pointer is UB.)
If you really want to move one byte, increment a char*: the size of of char is always one:
int i = 0;
int* p = &i;
char* c = (char*)p;
char x = c[1]; // one byte into an int
†A corollary of this is that you cannot increment void*, because void is an incomplete type.
Pointers are increased by the size of the type they point to, if the pointer points to char, pointer++ will increment pointer by 1, if it points to a 1234 bytes struct, pointer++ will increment the pointer by 1234.
This may be confusing first time you meet it, but actually it make a lot of sense, this is not a special processor feature, but the compiler calculates it during compilation, so when you write pointer+1 the compiler compiles it as pointer + sizeof(*pointer)
As you said, an int pointer points to an int. An int usually takes up 4 bytes and therefore, when you increment the pointer, it points to the "next" int in the memory - i.e., increased by 4 bytes. It acts this way for any size of type. If you have a pointer to type A, then incrementing a A* it will increment by sizeof(A).
Think about it - if you only increment the pointer by 1 byte, than it will point to a middle of an int and I can't think of an opportunity where this is desired.
This behavior is very comfortable when iterating over an array, for example.
The idea is that after incrementing, the pointer points to the next int in memory. Since ints are 4 bytes wide, it is incremented by 4 bytes. In general, a pointer to type T will increment by sizeof(T)
A pointer points at the BEGINNING of something in memory. An INT occupies 4 bytes (32bit) and a DOUBLE occupies 8 bytes (64bit) in memory. So if you have a DOUBLE number stored, and you wish at a very low level pointing to the next available memory location, the pointer wooud be increased by 8 bytes. If for some reason you pointed at +4bytes from the start of a DOUBLE value, you would corrupt it's value. Memory is a very large flat field that has no conscience of itself, so it's up to the software to divides it properly and to "respect the borders" of items located in that field.