int a[2][3];
cout << a+1 << " " << a << " " << (a+1) - a << endl;
Output:
0029FAC0 0029FAB4 1
Shouldn't (a+1)-a be 0029FAC0-0029FAB4=12 ?
No, because pointer arithmetic is scaled depending on the thing you're pointing to. In this case, you're pointing to a three-element array of integers, each four bytes long, for a total of twelve bytes. But that's scaled back to one "element" in your arithmetic.
It's the same reason that you get 0029FAC0 rather than 0029FAB5 (0029FAB4 + 1 when it's not scaled) when printing out a+1.
If you change your output line to:
cout << a+1 << " "
<< a << " "
<< (a+1) - a << " "
<< (int)(a+1)-(int)(a) << endl;
you'll see the scaling disappear in the final term because it's no longer a subtraction of pointers:
0xbfaa0ad4 0xbfaa0ac8 1 12
Keep in mind that the a+1 in (int)(a+1) is still scaled since a is still a pointer there. It's only the subtraction that's not scaled because, at that point, both values have been converted to integers (and the usual caveats apply to converting between pointers and integers, it's safe for my particular implementation but C99 doesn't mandate that).
Just as (pointer + N) points to the Nth data element after the pointer argument, going the other way with (pointerA - pointerB) gives you the number of data elements betweeen the pointers. In this case, the data element is int[3] (which you apparently already know since you are expecting 12...).
You shouldn't expect the difference in raw address value (which is machine-dependent in general anyway). C/C++ is converting for you.
Pointer arithmetic is still valid arithmetic ;-)
And as in valid arithmetic, it holds that (x+1)-x = x - x + 1 = 1.
So in your case (a+1) means not pointer to second element of an array, but pointer to the byte after the end of the array.
I would think that the compiler is changing that to a constant.
Try b = a + 1 and then cout << b << b - a << endl;
When you print out a pointer, it's basically implicitly cast to an integer for display, using the byte address.
When you subtract pointers, the result is a ptrdiff_t, which is already an integral type. You can only subtract pointers of the same type, and the sizeof the type is factored into the calculation. The result is the number of elements between the two pointers, not the number of bytes. (Keep in mind that if the two pointers are not pointing into the same array, the subtraction is undefined behaviour.)
In your case, the pointer type is "pointer to array of 3 ints", and your two pointers are to two adjacent elements in an array of 2 of those (array of 3 ints). They are 1 element apart, but 12 bytes apart.
Why would it be 12?
x+1-x=y
y can't possibly be 12, be this pointer arithmetic or integer.
Related
This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 2 years ago.
Someone gave this code as a method to find the length of an array called a:
std::cout << "Length of array = " << (sizeof(a)/sizeof(*a)) << std::endl;
The only thing I don't understand is
sizeof(*a)
I don't know what the * is doing here. I also assume it's a fraction. What's it doing in the denominator?
In C++, an int is 4 bytes. sizeof(*a) is getting the byte size of the type stored by your array. What (sizeof(a)/sizeof(*a)) is doing is dividing the total bytes stored by your array by the byte size of the array type, thus giving you the length.
Ex: you have an array [1, 2, 3, 4] which is 16 bytes, and the size of an int is 4 bytes. 16 bytes / 4 bytes = 4, the length of your array.
sizeof(a)
is the size of the full array
sizeof(*a)
is the size of one element of the array, *a being the first element of the array, equivalent of a[0]
this is why you need to divide sizeof(a) by sizeof(*a) to have the number of elements
If you have an array of char because by definition sizeof(char) is 1 you do not need to divide by the size of an element, else you need.
For instance having an array of 10 int and supposing sizeof(int) is 4 the size of the array is 10*4=40, which is not the number of elements => you need to divide by the size of an element
int a[10];
std::cout << sizeof(a) << std::endl; // print 40 supposing sizeof(int) is 4
std::cout << sizeof(*a) << std::endl; // print 4 supposing sizeof(int) is 4
std::cout << (sizeof(a)/sizeof(*a)) << std::endl; // print 10 expected
Note to use sizeof(*a) is better than to use sizeof(int) because in case you change the type of the array sizeof(*a) will be still valid
*a is the first element in your array.
The asterisk * is used to dereference the pointer, i.e. we're getting the value stored at that address.
The reason is that size(a) is going to return the size of the entire array in bytes.
This may not be the size of the array, as there are often multiple bytes in an element.
Therefore, we must divide by the size of an individual element, hence (sizeof(a)/sizeof(*a)).
Implying a is the name of the array, sizeof(a) gives the size of the full array, and the (*a) is simply a pointer to the first element of the array i.e. a[0] hence holding one element (all of which are equal sizes), hence the size will divide the full array size/size of one element, equalling the number of slots or elements.
One way to do it if you know the data type is:
int size = sizeof(a)/sizeof(int)
*a is a reference to the first element of the array.
sizeof(*a) gives the amount of memory used by the first element of the array. For example, a standard int element on a 32-bit computer would use 4 bits.
sizeof(a) is the size of the whole array.
I have newed a 2 dim array, but the size of array got 0:
auto **p = new string*[7];
for (int i = 0; i < 7; ++i) {
p[i] = new string[4];
}
cout << sizeof(p) / sizeof(string)<< endl;
Anyone could give me a specialized answer about this question:
Why the result output is 0, but the result of sizeof(p) is 8, if the Denominator and molecular is not zero how could be the result be 0? (if denominator is 0 then is not math.)
How to achieve that new a 2 dim array contains string correctly?
When you allocate memory using new for arrays, it attempts to allocate storage and on success returns a pointer to the initial element of the array. Because here the allocated array decayed to a pointer, you lost the information about the array size in bytes, so you cannot calculate the number of elements as:
auto numberOfElements = sizeof(array) / sizeof(element);
In your example the sizeof(p) returns the same as sizeof(std::string**) which is based on your architecture. The sizeof(string) may be bigger, than sizeof(std::string**), therefore from integer division you got 0.
In c++ is it strongly recommended to use the Standard containers instead manual allocation and deallocation. As comments under your question mention, std::vector is what you should use in your example, as follows:
vector<vector<string>> p(7, vector<string>(4));
cout << p.size() << endl;
Note: when you allocated memory for string*[7], you've clearly specified the number of elements, which is 7.
sizeof(p) is the size of the pointer, which in your system, might be 8.
sizeof(string) is the size of the class, which is something greater than 8.
As a result you print:
8 / greaterThan8
which gives you 0, since it's an integer division. If you cast it to float, it won't print 0.
sizeof(string) is greater than sizeof(p)
For such integer division the result will be 0.
For example 1/4 is not 0.25, it's 0.
im watching this tutorial on youtube https://www.youtube.com/watch?v=8XAQzcJvOHk Dynamically Allocating Arrays Depending on User Input in C++
this is his code
1 int main()
2 {
3 int *pointer = nullptr;
4
5 cout << "how many items u are gonna enter" << endl;
6 int input;
7 cin >> input;
8
9 pointer = new int[input];
10
11 int temp;
12
13 for (int counter = 0; counter < input; counter++) {
14 cout << "enter the item " << counter + 1 << endl;
15 cin >> temp;
16 *(pointer + counter) = temp;
17 }
18
19 cout << "the items you have entered are" << endl;
20 for (int counter = 0; counter < input; counter++) {
21 cout << counter + 1 << " item is " << *(pointer + counter) << endl;
22 }
23
24 delete[]pointer;
25
26 return 0;
27}
im stuck in line 16, i dont understand why is that, inside the (), the pointer variable and counter are added to each other
Pointer Arithmetic is a good point where to start.
I'm going to try to explain you briefly how it works, but I strongly suggest you to integrate those concepts with a good book or internet references because they are very important for proper handling pointers.
A pointer (as you can imagine from the name) points a memory cell:
int* ptr = /*an address to the memory cell*/
Your memory is composed by sequentially cells, graphically:
Address| Value
-------|------------
0x00 | [#some value] 8 bit
0x01 | [#some value] 8 bit
... | ...
0xN | [#some value] 8 bit
Just to make this example not so long, we can assume each cell contains 8 bits and a integer value is represented with exactly 32 bit (usually that is not true, and it depends on the machine architecture and compiler).
Then a int value is stored exactly in 4 cells. (We explicitly don't consider memory alignment).
So your pointer contains a memory location, the address in the memory which contains the value you've allocated (with the usage of dynamic memory).
For example:
int* ptr = 0x01
That means the variable ptr, stored somewhere in the memory, contains the address 0x01. In the memory cell 0x01 there will be the integer value allocated dynamically.
But, since the value is an integer type, the data will take 4 cell in order to store the complete information. So the data will be "split" among the cell 0x01, 0x02, 0x03, 0x04.
The pointer will points the first memory location of the data, and the number of cell occupied is given by the type of pointer (in that case pointer int so the compiler knows the information starts from cell 0x01 and ends 0x04).
A variable pointer can be evaluated in an arithmetic expression, such sums and differences.
Fo example:
ptr + 10
ptr - 10
Simply, the meaning of that expression is to access to memory address starting from the address stored in ptr and jumping 10 int cells forward or backward.
Attention Note: the expression does not mean to simply add the value to the address obtaining a new address.
Indeed, assuming ptr = 0x01, then the expression:
ptr + 10;
does not mean 0x01 + 10 = 0xa!
Instead that means to jump 10 "block" of size equal to the type's size
pointed by the pointer itself.
That is, 0x01 + 10 * 4bytes.
Since ptr is a pointer to int, then +10 means "plus 10 block of integers", and, in this example, each int occupies 4 bytes (32 bit).
To conclude, the expression:
*(pointer + counter) = temp;
means to access to the address start from pointer and adding #counter block of int, then deference that address with the operator* and write in that address the value temp.
That notation can be easily simplify with the operator[]:
pointer[counter] = temp;
where the meaning is exactly the same, but the notation is more readable, especially when you have to do with array.
This part:
*(pointer + counter)
is just simple pointer arithmetic: we are adding counter (of type int) to the pointer address and then dereferencing it using *. It is the same as pointer[counter]. After that, we are savig value of temp into that particular (dereferenced) location in memory.
*(pointer + counter) is equivalent to pointer[counter] as has been pointed out, the reason it's equivalent is because pointer holds a memory address, when you add say 1 to the that memory address you are infact adding the size of whatever the data type that pointer is pointing to is, multiplied by 1.
If you have a primitive array
int arr[2] = {1,55};
*arr would give you 1 and *(arr + 1) would give you 55
*(pointer + counter) = temp;
is same as
pointer[counter] = temp;
The variable pointer contain the address of the first element of the array.
Adding counter means selecting the address of counter away from starting address.
counter is simply an offset from pointer.
This question already has an answer here:
When I subtract memory addresses, why is the result smaller than I expected?
(1 answer)
Closed 8 years ago.
I am just confused with the output which I got for the following code :
int arr[] = {10,20,30};
cout<<&arr[1]<<"\t"<<&arr[0]<<"\t"<<&arr[1] - &arr[0];
the output which I got was like
0046F7A0 0046F79C 1
I want to know why the difference between the address gave 1 ( I expected 4)...?
Is it something to do with pointer subtraction..?
Yes, this is the result of pointer arithmetic. This is the same reason why arr + 1 would point to arr[1]. Pointer arithmetic is only well-defined when both pointers point to elements in the same array. If two such pointers, P and Q, point to array locations i and j, then P-Q = i-j.
Also, if you look at the differences of the actual addresses printed, they match your expectations - the difference is 4.
You are correct, this has to do with pointer arithmetic. Subtracting two int pointers gives you the difference between them measured in sizeof (int) units. You can get the difference in plain bytes by casting your pointers to char pointers, as chars are guaranteed to be of size 1.
uint arr[] = {10,20,30};
cout << &arr[1] << "\t" << &arr[0] << "\t" << (char*)&arr[1] - (char*)&arr[0];
Output:
0x23fe44 0x23fe40 4
0046F7A0 - 0046F79C is actually 4 but &arr[0]-&arr[1] = (0046F7A0 - 0046F79C)/sizeof(int= 4 bytes) because subtracting two pointers gives you the number of elements between them.
$5.7 -
"[..]For addition, either both operands shall have arithmetic or enumeration type, or one operand shall be a pointer to a completely defined object type and the other shall have integral or enumeration type.
2 For subtraction, one of the following shall hold:
— both operands have arithmetic or enumeration type; or
— both operands are pointers to cv-qualified or cv-unqualified versions of the same completely defined object type; or
— the left operand is a pointer to a completely defined object type and the right operand has integral or enumeration type.
int main(){
int buf[10];
int *p1 = &buf[0];
int *p2 = 0;
p1 + p2; // Error
p1 - p2; // OK
}
So, my question is why 'pointer addition' is not supported in C++ but 'pointer subtraction' is?
The difference between two pointers means the number of elements of the type that would fit between the targets of the two pointers. The sum of two pointers means...er...nothing, which is why it isn't supported.
The result of subtraction is distance (useful).
The result of adding a pointer and a distance is another meaningful pointer.
The result of adding 2 pointers is another pointer, this time meaningless though.
It's the same reason there are distinct TimeSpan and DateTime objects in most libraries.
The first thing that comes to mind is that it doesn't make sense to do pointer addition, so it's not supported. If you have 2 pointers 0x45ff23dd, 0x45ff23ed. What does it mean to add them?? Some memory out-of-bounds. And people in standard comittee have not found good enough reasons to support stuff like that, and rather warn you at compile time about possible problem. While pointer subtraction is fine because it indicates memory distance, which is often useful.
Because adding two pointers doesn't make sense.
Consider I have two ints in memory at 0x1234 and 0x1240. The difference between these addresses is 0xc and is a distance in memory. The sum is 0x2474 and doesn't correspond to anything meaningful.
You can however, add a pointer to an integer to get another pointer. This is what you do when you index into an array: p[4] means *(p + 4) which means "the thing stored at the address 4 units past this address."
In general, you can determine the "pointerness" of an arithmetic operation by assigning each pointer a value 1 and each integer a value zero. If the result is 1, you've got a pointer; if it's 0, you've got an integer; if it's any other value, you have something that doesn't make sense. Examples:
/* here p,q,r are pointers, i,j,k are integers */
p + i; /* 1 + 0 == 1 => p+i is a pointer */
p - q; /* 1 - 1 == 0 => p-q is an integer */
p + (q-r); /* 1 + (1-1) == 1 => pointer */
Result of pointer subtraction is number of objects between two memory addresses. Pointer addition doesn't mean anything, this is why it is not allowed.
subtraction of pointers is only defined if they point into the same array of objects. The resulting subtraction is scaled by the size of object they point to. ie, pointer subtraction gives the number of elements between the two pointers.
N.B. No claims on C standards here.
As a quick addendum to #Brian Hooper's answer, "[t]he sum of two pointers means...er...nothing" however the sum of a pointer and an integer allows you to offset from the initial pointer.
Subtracting a higher value pointer from a lower value pointer gives you the offset between the two. Note that I am not accounting for memory paging here; I'm assuming the memory values are both within the accessible scope of the process.
So if you have a pointer to a series of consecutive memory locations on the heap, or an array of memory locations on the stack (whose variable name decays to a pointer), these pointers (the real pointer and the one that decays to a pointer) will point to the fist memory location question (i.e. element [0]). Adding an integer value to the pointer is equivalent to incrementing the index in brackets by the same number.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// This first declaration does several things (this is conceptual and not an exact list of steps the computer takes):
// 1) allots space on the stack for a variable of type pointer
// 2) allocates number of bytes on the heap necessary to fit number of chars in initialisation string
// plus the NULL termination '\0' (i.e. sizeof(char) * <characters in string> + 1 for '\0')
// 3) changes the value of the variable from step 1 to the memory address of the beginning of the memory
// allocated in step 2
// The variable iPointToAMemoryLocationOnTheHeap points to the first address location of the memory that was allocated.
char *iPointToAMemoryLocationOnTheHeap = "ABCDE";
// This second declaration does the following:
// 1) allots space on the stack for a variable that is not a pointer but is said to decay to a pointer allowing
// us to so the following iJustPointToMemoryLocationsYouTellMeToPointTo = iPointToAMemoryLocationOnTheHeap;
// 2) allots number of bytes on the stack necessary to fit number of chars in initialisation string
// plus the NULL termination '\0' (i.e. sizeof(char) * <characters in string> + 1 for '\0')
// The variable iPointToACharOnTheHeap just points to first address location.
// It just so happens that others follow which is why null termination is important in a series of chars you treat
char iAmASeriesOfConsecutiveCharsOnTheStack[] = "ABCDE";
// In both these cases it just so happens that other chars follow which is why null termination is important in a series
// of chars you treat as though they are a string (which they are not).
char *iJustPointToMemoryLocationsYouTellMeToPointTo = NULL;
iJustPointToMemoryLocationsYouTellMeToPointTo = iPointToAMemoryLocationOnTheHeap;
// If you increment iPointToAMemoryLocationOnTheHeap, you'll lose track of where you started
for( ; *(++iJustPointToMemoryLocationsYouTellMeToPointTo) != '\0' ; ) {
printf("Offset of: %ld\n", iJustPointToMemoryLocationsYouTellMeToPointTo - iPointToAMemoryLocationOnTheHeap);
printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo);
printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo);
}
printf("\n");
iJustPointToMemoryLocationsYouTellMeToPointTo = iPointToAMemoryLocationOnTheHeap;
for(int i = 0 ; *(iJustPointToMemoryLocationsYouTellMeToPointTo + i) != '\0' ; i++) {
printf("Offset of: %ld\n", (iJustPointToMemoryLocationsYouTellMeToPointTo + i) - iPointToAMemoryLocationOnTheHeap);
printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo + i);
printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo + i);
}
printf("\n");
iJustPointToMemoryLocationsYouTellMeToPointTo = iAmASeriesOfConsecutiveCharsOnTheStack;
// If you increment iAmASeriesOfConsecutiveCharsOnTheStack, you'll lose track of where you started
for( ; *(++iJustPointToMemoryLocationsYouTellMeToPointTo) != '\0' ; ) {
printf("Offset of: %ld\n", iJustPointToMemoryLocationsYouTellMeToPointTo - iAmASeriesOfConsecutiveCharsOnTheStack);
printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo);
printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo);
}
printf("\n");
iJustPointToMemoryLocationsYouTellMeToPointTo = iAmASeriesOfConsecutiveCharsOnTheStack;
for(int i = 0 ; *(iJustPointToMemoryLocationsYouTellMeToPointTo + i) != '\0' ; i++) {
printf("Offset of: %ld\n", (iJustPointToMemoryLocationsYouTellMeToPointTo + i) - iAmASeriesOfConsecutiveCharsOnTheStack);
printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo + i);
printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo + i);
}
return 1;
}
The first notable thing we do in this program is copy the value of the pointer iPointToAMemoryLocationOnTheHeap to iJustPointToMemoryLocationsYouTellMeToPointTo. So now both of these point to the same memory location on the heap. We do this so we don't lose track of the beginning of it.
In the first for loop we increment the value we just copied into iJustPointToMemoryLocationsYouTellMeToPointTo (increasing it by 1 means it points to one memory location further away from iPointToAMemoryLocationOnTheHeap).
The second loop is similar but I wanted to more clearly show how incrementing the value is related to the offset, and how the arithmetic works.
The third and fourth loops repeat the process but work on an array on the stack as opposed to allocated memory on the heap.
Note the asterisk * when printing the individual char. This tells printf to output whatever is pointed to by the variable, and not the contents of the variable itself. This is in contrast to the line above where the balance of the string is printed and there is no asterisk before the variable because printf() is looking at the series of memory locations in its entirety until NULL is reached.
Here is the output on ubuntu 15.10 running on an i7 (the first and third loops output starting at an offset of 1 because my loop choice of for increments at the beginning of the loop as opposed to a do{}while(); I just wanted to keep it simple):
Offset of: 1
BCDE
B
Offset of: 2
CDE
C
Offset of: 3
DE
D
Offset of: 4
E
E
Offset of: 0
ABCDE
A
Offset of: 1
BCDE
B
Offset of: 2
CDE
C
Offset of: 3
DE
D
Offset of: 4
E
E
Offset of: 1
BCDE
B
Offset of: 2
CDE
C
Offset of: 3
DE
D
Offset of: 4
E
E
Offset of: 0
ABCDE
A
Offset of: 1
BCDE
B
Offset of: 2
CDE
C
Offset of: 3
DE
D
Offset of: 4
E
E
Because the result of that operation is undefined. Where does p1 + p2 point to? How can you make sure it points to a properly initialized memory so that it could be dereferenced later?
p1 - p2 gives the offset between those 2 pointers and that result could be used further on.