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]
Related
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.
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.
I have a question about pointers, and memory addresses:
Supposing I have the following code:
int * array = (int *) malloc(sizeof(int) * 4);
Now in array im storing a memory address, I know that c++ takes already care when adding +1 to this pointer it will add 4 bytes, but what If I want to add manually 4 bytes?
array + 0x004
If im correct this will lead to add 4*4 (16) bytes, but my Idea is to add manually those 4 bytes.
Why? Just playing around, i've tried this and I got a totally different result from what I expected, then i've researched and i've seen that c++ takes already care when you add +1 to a pointer (it sums 4 bytes in this case).
Any idea?
For a pointer p to a type T with value v, the expression p+n will (on most systems anyway) result in a pointer to the address v+n*sizeof(T). To get a fixed-byte offset to the pointer, you can first cast it to a character pointer, like this:
reinterpret_cast<T*>(reinterpret_cast<char*>(p) + n)
In c++, sizeof(char) is defined to be equal to 1.
Do note that accessing improperly aligned values can have large performance penalties.
Another thing to note is that, in general, casting pointers to different types is not allowed (called the strict aliasing rule), but an exception is explicitly made for casting any pointer type to char* and back.
The trick is convert the type of array into any pointer-type with a size of 1 Byte, or store the pointer value in an integer.
#include <stdint.h>
int* increment_1(int* ptr) {
//C-Style
return (int*)(((char*)ptr) + 4);
}
int* increment_2(int* ptr) {
//C++-Style
char* result = reinterpret_cast<char*>(ptr);
result += 4;
return reinterpret_cast<int*>(result);
}
int* increment_3(int* ptr) {
//Store in integer
intptr_t result = reinterpret_cast<intptr_t>(ptr);
result += 4;
return reinterpret_cast<int*>(result);
}
Consider that if you add an arbitrary number of bytes to an address of an object of type T, it no longer makes sense to use a pointer of type T, since there might not be an object of type T at the incremented memory address.
If you want to access a particular byte of an object, you can do so using a pointer to a char, unsigned char or std::byte. Such objects are the size of a byte, so incrementing behaves just as you would like. Furthermore, while rules of C++ disallow accessing objects using incompatible pointers, these three types are excempt of that rule and are allowed to access objects of any type.
So, given
int * array = ....
You can access the byte at index 4 like this:
auto ptr = reinterpret_cast<unsigned char*>(array);
auto byte_at_index_4 = ptr + 4;
array + 0x004
If im correct this will lead to add 4*4 (16) bytes
Assuming sizeof(int) happens to be 4, then yes. But size of int is not guaranteed to be 4.
If I declare
int x = 5 ;
int* p = &x;
unsigned int y = 10 ;
cout << p+y ;
Is this a valid thing to do in C++, and if not, why?
It has no practical use, but is it possible?
The math is valid; the resulting pointer isn't.
When you say ptr + i (where ptr is an int*), that evaluates to the address of an int that's i * sizeof(int) bytes past ptr. In this case, since your pointer points to a single int rather than an array of them, you have no idea (and C++ doesn't say) what's at p+10.
If, however, you had something like
int ii[20] = { 0 };
int *p = ii;
unsigned int y = 10;
cout << p + y;
Then you'd have a pointer you could actually use, because it still points to some location within the array it originally pointed into.
What you are doing in your code snippet is not converting unsigned int to pointer. Instead you are incrementing a pointer by an integer offset, which is a perfectly valid thing to do. When you access the index of an array, you basically take the pointer to the first element and increase it by the integer index value. The result of this operation is another pointer.
If p is a pointer/array, the following two lines are equivalent and valid (supposing the pointed-to-array is large enough)
p[5] = 1;
*(p + 5) = 1;
To convert unsigned int to pointer, you must use a cast
unsigned int i = 5;
char *p = reinterpret_cast<char *>(i);
However this is dangerous. How do you know 5 is a valid address?
A pointer is represented in memory as an unsigned integer type, the address. You CAN store a pointer in an integer. However you must be careful that the integer data type is large enough to hold all the bits in a pointer. If unsigned int is 32-bits and pointers are 64-bits, some of the address information will be lost.
C++11 introduces a new type uintptr_t which is guaranteed to be big enough to hold a pointer. Thus it is safe to cast a pointer to uintptr_t and back again.
It is very rare (should be never in run-of-the-mill programming) that you need to store pointers in integers.
However, modifying pointers by integer offsets is totally valid and common.
Is this a valid thing to do in c++, and if not why?
Yes. cout << p+y; is valid as you can see trying to compile it. Actually p+y is so valid that *(p+y) can be translated to p[y] which is used in C-style arrays (not that I'm suggesting its use in C++).
Valid doesn't mean it actually make sense or that the resulting pointer is valid. Since p points to an int the resulting pointer will be an offset of sizeof(int) * 10 from the location of x. And you are not certain about what's in there.
A variable of type int is a variable capable of containing an integer value. A variable of type int* is a pointer to a variable copable of containing an integer value.
Every pointer type has the same size and contains the same stuff: A memory address, which the size is 4 bytes for 32-bit arquitectures and 8 bytes for 64-bit arquitectures. What distinguish them is the type of the variable they are poiting to.
Pointers are useful to address buffers and structures allocated dynamically at run time or any sort of variable that is to be used but is stored somewhere else and you have to tell where.
Arithmetic operations with pointers are possible, but they won't do what you think. For instance, summing + 1 to a pointer of type int will increase its value by sizeof(int), not by literally 1, because its a pointer, and the logic here is that you want the next object of this array.
For instance:
int a[] = { 10, 20, 30, 40 };
int *b = a;
printf("%d\n", *b);
b = b + 1;
printf("%d\n", *b);
It will output:
10
20
Because b is pointing to the integer value 10, and when you sum 1 to it, or any variable containing an integer, its then poiting to the next value, 20.
If you want to perform operations with the variable stored at b, you can use:
*b = *b + 3;
Now b is the same pointer, the address has not changed. But the array 10, 20, 30, 40 now contains the values 13, 20, 30, 40, because you increased the element b was poiting to by 3.
so I have:
char inBuf[80]
and then there's another line
inBuf+9
what does it mean when I add that +9 to the array's name?
It is same as referencing element number 9(0 based).
An equivalent notation would be:
&inBuf[9]
If you want to get the value, you could use *(inBuf+9)
This would point to the 10th element of the array. So for example:
*(inBuf + 9) = 10
would assign 10 to the 10th element.
Answer has been given already. I may only be repeating it.
This is called pointer arithmetic, because pointers are involved in the arithmetic operation. there are certain things only you can do with pointers. like you can add an integer to it, but you can subtract an integer only if pointer points to some array in the memory. also you can not subtract the pointers, because that may lead to some crucial memory location (for the OS).
addition in pointer arithmetic is special in a way that it takes care of the data type of the array elements, so when you say
char inBuf[80]
inBuf + 9
it advances 9 memory location sufficient enough to hold the 9 character (9*1 bytes typically)
int inBuf[80]
inBuf + 9
this will add 9 memory location sufficient enough to hold the 9 integers (9*4 bytes typically).
array and pointers are not always same, refer to "expert C programming" for that Also never use pointer arithmetic polymorphic-ally, refer "scott meyers book" for that
Using inBuf with no qualifier for an array index to use will be the same as seeing char *inBuf. inBuf + 9 would be the same as inBuf[9].
inBuf+9 means increasing the address of inBuf by 9.
inBuf refer the base address. but inBuf+ 9 locates the 10th element from the base address.
*(inBuf + 9) = 34;
This would assign the value 34 to the 10th element in the inBuf array.
When you perform addition with it, an array identifier such as your inBuf decays to a pointer to the first element in the array, and the number added is multiplied by the size of the array element (in this case char, which has size 1) to produce a new address.
So, inBuf + 9 is the address of the 10th element in the array, which could also be expressed as &inBuf[9]. You can use it as in:
*(inBuf + 9) = '\0'; // overwrite the 10th element in inBuf with a NUL
const char* p = strchr(inBuf + 9, ' '); // find space at or beyond 10th char
inBuf is like to write &inBuf[0].
So inBuf +9 means address of inBuf added with 9 chars length (&inBuf[9]).