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.
Related
Short:
How can I calculate correctly the memory space in bytes of std::vector<bool> that store n bits?
std::vector<bool> vb(n, false);
int size_bytes = compute_space_memory_in_bytes(vb);
Detail:
In my algorithm i use vector<bool> to store n bits. In order to measure it efficiently in practice, I need to know how to calculate the space memory in bytes. (In theory it is just O(n) bits).
There are 2 points:
If we have std::vector<int>, the solution from another answer is:
sizeof(std::vector<int>) + (sizeof(int) * MyVector.size())
Since vector store each Boolean value into a single bit
One potential optimization involves coalescing vector elements such that each element occupies a single bit instead of sizeof(bool) bytes.
Hence, from 1 and 2, my attempt solution is :
std::vector<bool> vb(100, false);
auto size_bytes = sizeof(vector<bool>) + vb.size()/8;
std::cout << "Hello, size = " << size_bytes << " bytes!\n";
Is that correct ?
Edit: To be more explicit (Thanks to #PaulMcKenzie comment):
Given n bits that to be determined at execution time. My problem is what is the space occupied (exactly or approximately) to store n bits in vector of bool?
std::vector<bool> vb;
// some processing to get n ..
vb.resize(n);
auto size_bytes = compute size of vb in bytes ???;
std::cout << "Hello, size = " << size_bytes << " bytes!\n";
For your re-stated question:
How to compute the sizeof to get the answer of space occupied
As others pointed out, different implementation of vector may produce different answers to your question.
Generally speaking, the memory "occupied" by your boolean values, in bytes, is:
int s = (n + 7) / 8;
If your implementation uses 32- or 64-bit values to pack bool into a vector, you need to round up to 32 or 64:
int s = (n + 31) / 32;
or
int s = (n + 63) / 64;
There is some memory that an instance of the vector itself uses (pointer to the first element, number of elements or a pointer to the last element, capacity, etc.); as #paulsm4 stated, it is 40 bytes in his implementation of the vector.
You may also want to consider allocated but not yet occupied memory. This also depends on implementation.
In conclusion, you can definitely state only the MINIMUM size your vector will occupy.
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.
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.
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.
$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.