There is a subtle nuance in both C and C++ with memory allocation. Neither language supports dynamic arrays. Here is what you are seeing:
int ary[17];
int arrSize = sizeof(ary) / sizeof(ary[0]);
Here ary
is a true array of 17 integers. The array size calculation works because sizeof(ary)
returns the size of the memory block allocated for the entire array. You divide this by the size of each element and violà you have the number of elements in the array.
std::string * arr;
arr = new (std::nothrow) std::string[213561];
In this case arr
is a pointer to some memory. The new
operator allocates a block of memory large enough to hold 213,561 contiguous std::string
objects and constructs each of them into the memory. The arr
variable simply points to the beginning of the block of memory. C++ does not track the number of elements that you have allocated. You didn't really create a dynamic array - instead, you have allocated enough memory for a bunch of contiguous objects.
C and C++ both allow you to apply the subscripting operator to a pointer as syntactical sugar. You will see a lot of comments about how arr[0]
translates into *(arr + 0)
. The reality is that allocating memory using the new
operator results in a block of memory that is not an array at all. The syntactical sugar makes it look like one. The next thing that you will encounter is that multi-dimensional arrays are similar sugar.
Consider the following snippet. Once you understand what is going on there, you will be a lot closer to understanding how memory works. This is the primary reason why C and C++ cannot tell you how large an array is if it is dynamically allocated - it does not know the size, all that it has is a pointer to the allocated memory.
#include <iostream>
int
main()
{
//
// The compiler translates array subscript notation into
// pointer arithmetic in simple cases so "hello"[3] is
// is translated into *("hello" + 3). Since addition is
// commutative, the order of "hello" and 3 are irrelevant.
//
std::cout
<< "\"hello\"[3] = '" << "hello"[3] << "'\n"
<< "3[\"hello\"] = " << 3["hello"] << "\n"
<< std::endl;
//
// All memory is linear in C or C++. So an 3x3 array of
// integers is a contiguous block of 9 integers in row
// major order. The following snippet prints out the 3x3
// identity matrix using row and column syntax.
//
int ary[3][3] = { { 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 } };
for (int r=0; r<3; ++r) {
for (int c=0; c<3; ++c) {
std::cout << "\t" << ary[r][c];
}
std::cout << "\n";
}
std::cout << "\n";
//
// Since memory is linear, we can also access the same
// 3x3 array linearly through a pointer. The inner loop
// is what the compiler is doing when you access ary[r][c]
// above - "ary[r][c]" becomes "*(ptr + (r * 3) + c)"
// since the compiler knows the dimensions of "ary" at
// compile time.
//
int *ptr = &ary[0][0];
for (int i=0; i<9; ++i) {
ptr[i] = i;
}
for (int r=0; r<3; ++r) {
for (int c=0; c<3; ++c) {
std::cout << "\t" << *(ptr + (r * 3) + c);
}
std::cout << "\n";
}
return 0;
}