I want to say first - I'm as interested in what's happening "behind the scenes" to cause this problem as I am in a blind fix for the code. Perhaps the C++ standard or something I'm unfamiliar with dictates what's causing it :-)
Anyways...
I am trying to pass 3 arrays, A, B, C into a function, which will merge A and B, storing the result in C.
Function declaration: void merge(int* a, int* b, int* c)
Passed from main() by:
int A[] = {1,2,3,4};
int B[] = {6,7,8,9};
int* C; //this could be wrong, btw!
merge(A, B, C);
Issue 1.
What's strange is that in main(), if I print the result of sizeof(A)/sizeof(A[0]), it gives me the proper result for the "length" of the array - 4 - and the same thing for B. But when I pass the arrays to the function, I try to calculate the size again, by the same method, but I get the result 2 for both arrays. The first lines of merge():
void merge(int* a, int* b, int* c)
{
int sizeA = sizeof(a)/sizeof(a[0]);
int sizeB = sizeof(b)/sizeof(b[0]);
int totalsize = sizeA + sizeB;
std::cout << "size A = " << sizeA << std::endl; //prints 2
std::cout << "size B = " << sizeB << std::endl; //prints 2
std::cout << "total = " << totalsize << std::endl;
...
Issue 2.
Just for fun, I tried iterating through a and b passed to merge() (within the merge function):
for (int i = 0; i < 4; ++i)
std::cout << a[i]; //prints "1234" as expected
All cool. But when I increase the index limit to 8...
for (int i = 0; i < 8; ++i)
std::cout << a[i]; //prints "12346789" - A and B concatenated!
Raising the max index a couple more times because why not:
for (int i = 0; i < 10; ++i)
std::cout << a[i]; //prints "1234678900"
...
for (int i = 0; i < 11; ++i)
std::cout << a[i]; //prints "1234678900-444896443"
Undefined behavior from out of bounds indexing and accessing other memory, I guess.
Printing b in the same manner does similar:
looping to i = 4 prints the array - 6789
to 6 adds two zeroes - 678900
to 8 adds the other stuff - 678900-126926969126613
Printing C, of course, results in nothing.
Are these oddities the result of
the fact I'm using C++ Shell (with options -std=c++14 -Wpedantic -O2) ?
incorrect passing of arrays to merge() ?
incorrect initializations in main() ?
the arrays needing to have a terminator, like char arrays?
all of the above?
In the first case, you have an array, which is not the same as a pointer. So the sizeof is correctly computed. Whereas int* is a pointer, and an array passed to a function always decays to a pointer (except when passing by reference). Also sizeof(int*)/sizeof(int) is the size of the pointer on your machine divided by the size of the int, so if your system is a 64 bit (8 bytes) and the int has a typical size of 4, you get 8/4=2.
Typical undefined behaviour by indexing out of bounds.
Advice: use std::vector<int> instead and you'll avoid allocating memory for C and using sizeof. You can simply use the std::vector::size() member function to obtain the size of the vector.
When you are passing your array to void merge(int* a, int* b, int* c)
The a and b here are no longer arrays, but are pointers. So when you are calculating it's size using
int sizeA = sizeof(a)/sizeof(a[0]);here sizeof(a)will give you the size of pointer, and sizeof(a[0]is giving you the size of int. Hence the result.
And for your second issue, when you are increasing the indexes, and getting both arrays connected, it is just because both arrays have been allocated continuous memory block, it is not necessary though that they will always be assigned continuous memory blocks, and other outputs are because of Undefined behavior only.
you need to remember that sizeof is a keyword that expands in compile time to the relevant size. sizeof(T) will expand to the byte size of (T).
inside the main function, sizeof(a) will give you the number of bytes of int[4], inside different function, the array decays into a pointer. sizeof(T*) is not sizeof(T[4])! you are calculating the size of the pointer (after the decay) and not the size of the real array. now let say my object weight 1 MB, does sizeof(OBJ) == sizeof(OBJ*)? of course not.
you are having Undefined beaviour. in this specific example, A and B sit right after the another on the stack. so in this super specific case when iterating over the stack you actually print both of the arrays because they sit one after the another. but again , this is Undefined beaviour. different compilers can padd the area between the array, or other OS may even kill your program.
You cannot compute a size of an array with a simple pointer passed to a function.
sizeof(integers) / sizeof(integers[0])
will be simply replaced by
sizeof(pointer on integer) / sizeof(integer).
But you can compute it earlier and then pass the size to a function like below.
#include <iostream>
using namespace std;
void doSomeWork(int* integers, const size_t size)
{
for (size_t i = 0; i < size; ++i)
{
std::cout << integers[i] << std::endl;
}
}
int main()
{
int integers[] { 0, 1, 2, 3 };
const size_t size = sizeof(integers) / sizeof(integers[0]);
doSomeWork(integers, size);
return 0;
}
As said below, std::vector<int> is much better than playing with C arrays.
There are already plenty of good answers here. In short, C++ arrays are of fixed size. If you want to change it, you have to use pointers and dynamic allocation. That can be tedious. the reason for most people here to advise you to use vectors instead.
Vectors are build for being of dynamic and adjustable size. You can use them almost like arrays. Here your code adapted:
void merge(vector<int> &a, vector<int>& b, vector<int> &c) // pass by reference
{
int sizeA = a.size();
int sizeB = b.size();
int totalsize = sizeA + sizeB;
c.resize(totalsize); // easy !
// ...
}
int main() {
vector<int> A{1,2,3,4};
vector<int> B {6,7,8,9};
vector<int> C;
cout <<A[2]<<endl; // access elements exacly like arrays
merge(A, B, C);
}
Related
This question already has answers here:
How do I define variable of type int[][26]?
(2 answers)
Closed 2 years ago.
I have written a small program that passes a 2D array to 2 separate functions that store and display the pattern of a chessboard. While the program works perfectly fine, I would like to ask a more technical question that I have not been able to answer myself through my searches.
I am wondering how it is possible that my program compiles and runs when passing the 2D array with ONLY the columns variable specified, but not the rows. For instance void setBoard(char chessboard[][cols]);
Here is the link to the program: https://codecatch.net/post/54969994-76d7-414b-aab6-997d3fef895c
Here is the same code for those of you that don't want to click the link:
#include<iostream>
using namespace std;
const int rows = 8;
const int cols = 8;
char chessboard[rows][cols];
void setBoard(char chessboard[][cols]);
void printBoard(char chessboard[][cols]);
void setBoard(char chessboard[][cols]) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
if(i % 2 == 0 && j % 2 == 0) {
chessboard[i][j] = 'x';
} else {
if(i % 2 != 0 && j % 2 == 1) {
chessboard[i][j] = 'x';
} else {
chessboard[i][j] = '-';
}
}
}
}
return;
}
void printBoard(char chessboard[][cols]) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
cout << chessboard[i][j] << " ";
}
cout << endl;
}
return;
}
int main(int argc, char const *argv[])
{
setBoard(chessboard);
printBoard(chessboard);
return 0;
}
To answer the question directly: in C and C++ passing static array as an argument needs all dimensions except the outermost. So, if you have N-dimensional array, you need to specify the sizes of N-1 dimensions, except the leftmost one: int array[][4][7][2]...[3].
Now, to the gory details.
So, let's say you have int a[3];. What is the type of a? It is int [3]. Now, you want to pass it into function. How do you do this? There are two ways: you can either pass the array by pointer to the first element (works in C and C++), or you can pass the array by reference (references are a C++ thing). Let's consider these examples:
#include <iostream>
void foo(int* array, std::size_t len) { // same as foo(int array[],...)
for (std::size_t i = 0; i < len; i++)
std::cout << array[i] << ' ';
std::cout << '\n';
}
void bar(int (&array)[3]) {
for (int n : array)
std::cout << n << ' ';
std::cout << '\n';
}
template <std::size_t N>
void baz(int (&array)[N]) {
for (int n : array)
std::cout << n << ' ';
std::cout << '\n';
}
int main () {
int a[3] = {1, 2, 3};
int b[4] = {1, 2, 3, 4};
foo(a, 3); // BAD: works, but have to specify size manually
foo(b, 4); // BAD: works, but have to specify size manually
bar(a); // BAD: works, but bar() only accepts arrays of size 3
bar(b); // DOESN'T COMPILE: bar() only accepts arrays of size 3
baz(a); // OK: size is part of type, baz() accepts any size
baz(b); // OK: size is part of type, baz() accepts any size
}
Let's consider foo().
foo()'s signature could also be written as void foo(int array[], ...). This is purely syntactic sugar and int array[] means the same as int* array. Note, however, that this only applies to function signatures, everywhere else these syntaxes are not equivalent.
When you call it as foo(a, 3), it's signature is set to accept a pointer to int as first parameter: int* array. But you know that a is of type int [3], so how does it work? What happens is, the pointer to the first element of the array is passed by value. Which means, it is the same as writing foo(&a[0],...). We take the address of the first element, which is then copied into int* array. As you might notice, having a pointer to the first array doesn't tell us anything about the size of the array, we lost this information during conversion from array type int [3] to int *. Which is why we have to supply the second argument that specifies the length of a. We call this implicit conversion an "array to pointer decay". Decay specifically because we were forced to lose important information -- we had it right there in the type, but now we have to have another argument that describes how many elements the array has. A bit stupid and inconvenient, isn't it?
Now consider bar().
In bar() we pass the array type by reference. This is something that C++ has improved upon C. I will not explain what references are, but in general, you can think of them as something that allows you to get the object the way it is defined, without using any convertions to pointers. In this case, the type of array remains int [3], so we have passed in an array and haven't lost any type information. Great! This means, we can use idiomatic C++ syntax to further improve our code. I have replaced the normal for loop, as found in foo(), with a for-each loop, where we just need to supply a variable to store the element (n) and the array (array). Note that this is possible only because array preserves type information! Trying to do this in foo() would result in a compilation error.
However, there is still a problem with this. bar() has to have the array size as part of its signature! This means that if a was any different size, let's say 4 elements, trying to use bar() would result in a compilation error because int [3] and int [4] are incompatible types.
Consider baz(), which solves the above problem.
Just a little bit of templates will make baz() usable on arrays of any size, while the usage stays the same as in bar().
Now, let's take it to multiple dimensions:
#include <iostream>
void foo2d(int (*array)[3], std::size_t rows, std::size_t cols) {
for (std::size_t i = 0; i < rows; i++)
for (std::size_t j = 0; j < cols; j++)
std::cout << array[i][j] << ' ';
std::cout << '\n';
}
void bar2d(int (&array)[2][3]) {
for (std::size_t i = 0; i < 2; i++)
for (std::size_t j = 0; j < 3; j++)
std::cout << array[i][j] << ' ';
std::cout << '\n';
}
template <std::size_t N, std::size_t M>
void baz2d(int (&array)[N][M]) {
for (std::size_t i = 0; i < N; i++)
for (std::size_t j = 0; j < M; j++)
std::cout << array[i][j] << ' ';
std::cout << '\n';
}
int main () {
int c[2][3] = { {1, 2, 3}, {4, 5, 6} };
foo2d(c, 2, 3);
bar2d(c);
baz2d(c);
}
And again, only baz2d() doesn't require hardcoded size information.
One more example, of foo3d(), just to demonstrate what I mean when I say only the outermost dimension doesn't need to be specified:
void foo3d(int (*array)[2][1], std::size_t rows, std::size_t cols, std::size_t K) {
for (std::size_t i = 0; i < rows; i++)
for (std::size_t j = 0; j < cols; j++)
for (std::size_t k = 0; k < K; k++)
std::cout << array[i][j][k] << ' ';
std::cout << '\n';
}
int main () {
int d[3][2][1] = { {{1}, {2}}, {{3}, {4}}, {{5}, {6}} };
foo3d(d, 3, 2, 1);
}
Pay attention to how it's called vs. how it's declared in the signature. So, why do you not need to declare the outermost size? Because only the first pointer decays, due to passing it to the function. d[0][0][0] stores element of type int, d[0][0] stores element of type int [1], d[0] stores element of type int [2][1]. Which are all themselves are arrays! Well, except d[0][0][0], obviously. So, what is the type of the array in foo3d()? It's int (*)[2][1]: pointer to array of size 2, each element of which is an array of size 1.
Parameter of a function is never an array type in C++ (nor in C).
You can declare a function that has an array parameter (as is done in the example program), but that declaration is adjusted so that the parameter is not an array as was written, but it is instead a pointer to element of such array. Example:
void f(int[]); // will be adjusted
void f(int[42]); // will be adjusted
void f(int*); // declarations above are adjusted to this
All of the above three declarations declare the same function. If the type of parameter is "array of int", then the type of the element of such array is "int" and pointer to such element is "pointer to int". Notice that the size of the array has no effect on the type of the element. As such, the size has no effect on the declaration in any way, and indeed arrays of unknown bound are allowed in parameter declaration.
Note that this adjustment occurs only in function parameters, and nowhere else. An array is not a pointer.
So, when you declare a function void setBoard(char chessboard[][cols], the parameter chessboard is not an array, because a parameter is never an array. It has been adjusted to be a pointer to element of char [][cols]. Element of such array is char[cols] i.e. array of cols number of char, therefore the adjustead parameter type is pointer to array of cols number of char i.e. char(*)[cols].
You cannot have pointer type to an array of unknown bound, so you cannot leave out cols. But you can leave out rows because as noted above, the size of the declared array parameter is ignored when the type is adjusted to be a pointer to the element of that array.
You may be wondering "if the parameter is actually not an array, then why can an array be passed as argument?". The answer is that there is another rule complementing the parameter adjustment (in simple words): Arrays implicitly convert to the pointer to element type. The result of the conversion is pointer to the first element of that array. Such conversion is called "decaying". This conversion happens automatically whenever the value of an array is used. Example:
printBoard(&chessboard[0]);
printBoard(chessboard);
The above function calls do exactly the same thing. The former explicitly passes pointer to first element, while the latter does the same thing by implicit "decay".
I have this function:
void reverse(int* nums, unsigned int size)
This function is supposed to reverse the values in the array it is getting.
Now for reversing I thought to create another array with the size of the array passed in. Assigning this new one from the end of the original array to the start.
But I am a kind of new in C++, So I don't know how to create dynamic array in the size of the parameter of the function.
It's actually not necessary to allocate a new array here. See if you can find a way to solve this problem just by rearranging the existing elements in-place.
Given that this seems like it's an exercise with pointers, you can allocate space by using the new[] operator:
int* auxiliaryArray = new int[size];
You'd then free it by writing
delete[] auxiliaryArray;
However, this isn't the preferred way of doing this in C++. The better route is to use std::vector, which does all its own memory management. That would look like this:
std::vector<int> auxSpace(size);
You can then access elements using the square brackets as you could in a real array. To do this, you'll need to #include <vector> at the top of your program.
In C++, the recommended way to create an array of variable size would be to use an std::vector
#include <vector>
void reverse(int* nums, unsigned int size)
{
std::vector<int> V(size);
...
}
But that approach isn't the best here for performance because it requires additional memory to be allocated of the size of the array, which could be big. It would be better to start from the outside of the array and swap members one by one that are at mirroring positions (so if the size is 5, swap 0 and 4, then swap 1 and 3 and leave 2 alone). This only requires temporary storage of a single int.
You can do it without the need to create another array:
void reverse(int* array, const int size){
for(int i = 0; i < size / 2; i++){
int tmp = array[i];
array[i] = array[size - 1 - i];
array[size - 1 - i] = tmp;
}
}
int main(){
int array[] = {1, 3, 5, 7, 9, 11};
const int size = sizeof(array) / sizeof(array[0]);
reverse(array, size);
for(int i(0); i < size; i++)
std::cout << array[i] << ", ";
}
As you can see above in the loop you only need to swap the first element (element 0) with the n-1 element and the second one with n-1-1 and son on...
Remember arrays are indexed from 0 through n-1.
If you want to allocate new array which is not practical:
int* reverse2(int* array, const int size){
int* tmp = new int[size];
for(int i(size - 1), j(0); j < size; j++, i--)
tmp[j] = array[i];
return tmp;
}
int main(){
int array[] = {1, 3, 5, 7, 9, 11};
for(int i(0); i < size; i++)
std::cout << array[i] << ", ";
std::cout << std::endl;
int* newArray = reverse2(array, size);
for(int i(0) ; i < size; i++)
std::cout << newArray[i] << ", ";
std::cout << std::endl;
delete[] newArray;
return 0;
}
If you want to use a new array you can, but I think is to kill flies with a cannon.
Looks like you are using plain C code and not C++. I say that because of the signature of the function. The signature of the function in a common C++ code could be something like this other:
void reverse(std::vector& items);
You can reverse the current array without a new array, using the current one. You are passing the pointer to the first item of the array, and the content is not constant so that you can modify it. A better signature for the function could be:
void reverse(int* const nums, const unsigned int size);
Looks like a pointer problem. Think about the boundaries to iterate the positions of the array. Would you need to iterate the whole array? Maybe only half array? ;)
As bonus track, what about to exchange the values without an auxiliar variable? (this is true into this case that we are using the fundamental type int... remember the binary arithmetic).
array[pos_head] ^= array[pos_tail];
array[pos_tail] ^= array[pos_head];
array[pos_head] ^= array[pos_tail];
I've read some of my friend's code and seen functions like this:
int foo(int* arr, int n)
{
// ...
}
which he then calls like this:
int myArr [] = {69, 69, 69, 69, 69};
int f = foo(myArr, sizeof(myArr)/sizeof(int));
Now, I understand that sizeof(myArr)/sizeof(int) is dividing the size of myArr in bytes by the size of an int in bytes, thus returning the length of myArray. However, I don't understand how sizeof(myArr) is implemented unless there's some sort of generic null element that terminates arrays and then sizeof(...) works similar to how strlen(...) works:
size_t strlen(char* c)
{
size_t k = 0;
while (*c != '\0')
{
++k;
++c;
}
return k;
}
Now, if sizeof(...) does work similar to that, then I don't see why, when passing an array to a function, you can't simply do
int foo(int* arr)
{
int n = sizeof(arr)/sizeof(int);
// ....
}
which is simpler way of writing functions because the array is essentially being passed in as a single unit that gets unpacked.
My guess is that arrays of non-character type don't have the null-termination property that character arrays do. In that case, how does sizeof(...) work? And what is the point of null-termination in character arrays anyhow? Why are they created differently than any other array?
Anyways, I was wondering whether someone could clear up all the obvious confusion that I have.
sizeof works on arrays because the compiler knows the length at compile time. If you pass that array to a function, it turns into a pointer, at which point the compiler doesn't know the full size of the array anymore.
For example:
#include <iostream>
void printPointerSize(int* a) {
// a is a pointer, and all pointers are 8 bytes (64 bits) on my machine
std::cout << "int* pointer argument has size: " << sizeof a << std::endl;
}
int main() {
// the compiler determines from the initializer that this is an int[5]
int a[] = {1, 2, 3, 4, 5};
// since the compiler knows that a is an int[5],
// then sizeof a is 5 * sizeof int
std::cout << "int[5] has size: " << sizeof a << std::endl;
printPointerSize(a);
}
Output (on a platform with 64-bit pointers and 32-bit integers):
int[5] has size: 20
int* pointer argument has size: 8
Note that if you try to create a function that takes an array as an argument, the compiler will just turn it into a pointer anyway:
void printPointerSize(int a[5]) {
// this will print the size of a pointer,
// not the size of a 5-element int array
std::cout << "int[5] argument has size: " << sizeof a << std::endl;
}
In addition to Brandon's answer, you need to distinguish between array capacity and array size.
Array Capacity
Array Capacity is the maximum number items the array can hold. There can be from 0 to capacity number of items in the array. Which brings up the question, "how many items are in the array?"
Array Size
Array Size is the number of valid items in the array. An array that has a capacity of 20 items, may only have 3 valid items in it.
Example:
char array[20];
array[0] = 'M';
array[1] = 'e';
array[2] = 'a';
array[3] = 't';
The above array has a capacity of 20, but only 4 valid items.
Repeating the question, "How many items are in the array?"
The C++ language does not maintain the number of items in an array. The sizeof operator returns the capacity of an array, but not the size.
The size of an array must be maintained in a separate variable. Some crafty programmers can use an array slot to maintain this value. So when passing an array, you will have to pass: the array (or pointer to it), the capacity and the size. Most starting programmers forget about the size parameter, which leads to many difficult defects that are hard to find.
my aim is to reverse an array 3,12,2,1 to 1,2,12,3. when i run this code i get garbage before my actually result. i can't seem to see where the problem is please assit
#include<iostream>
using namespace std;
int rev (int arr[], int a){
//int r;
for(int i =a-1; i>=0; i--){
cout<<arr[i]<<" ";
}
return 0;
}
int main(){
int arr[] = {6,41,12,5,2};
cout<<"The rev of {6,41,12,5,2}"<<endl;
cout<<rev(arr, sizeof(arr))<<endl;
system("pause");
return 0;
}
Use sizeof(arr)/sizeof(arr[0]) instead of sizeof(arr).
sizeof(arr) gives the total size of the array. sizeof(arr[0]) is the size of one array element (all elements have the same size). So sizeof(arr)/sizeof(arr[0]) is the number of elements.
An optimized answer to the question would be using reverse () from STL if you are allowed to use it:
std::reverse
http://www.sgi.com/tech/stl/reverse.html
int main()
{
int arr[] = {6,41,12,5,2};
cout<<"The rev of {6,41,12,5,2}"<<endl;
reverse(arr, arr + 5);
copy(arr, arr + 5, ostream_iterator<int>(cout, ", "));
}
sizeof return the size in bytes. In your example, if sizeof(int) = 4, it returns 20.
Because you're using an array, you have to keep the size of the array handy as well. sizeof computes the size of a value in memory, in this case the size of all the memory used to represent arr. You can do sizeof(arr)/sizeof(int) to get the number of elements in an array. This makes sense because it's taking the total size of the array and dividing it by the size of an element in the array. Beware however that this only works for arrays (int arr[4] = {6,41,12,5,2};). If it's a pointer to a heap-allocated array via something like int* i = new int[4]; you'll need to keep the size of the array hanging around.
Also, you're calling your reverse function from within a cout<< call, which will print the function's return value (in this case it's hard-coded to 0).
It also turns out there is a function in the C++ standard library (std::reverse) that can do this.
If I may speak subjectively and in an off-topic manner about your approach, it is very un-C-like. My personal favorite way to reverse an array goes like this:
void reverse(int *a, int n)
{
int *p = a, *q = a + n - 1;
while (p < q)
{
int swap = *p;
*p++ = *q;
*q-- = swap;
}
}
// Usage:
int a [] = { /* ... */ };
reverse(a, sizeof(a)/sizeof(*a));
Of course, since your question is tagged c++, there's always std::reverse().
Sizeof operator return the one extra (arrayLength + 1) here 6 will return when passs 6 it store in a when a-1 you get 5 but array index start from 0 length-1 that from 0 to 4 here i pointing to index 5 that is not last element last+1 that why you got garbage value
I read to get the length of array in C++, you do this:
int arr[17];
int arrSize = sizeof(arr) / sizeof(int);
I tried to do the same for a string:
where I have
string * arr;
arr = new (nothrow) string [213561];
And then I do
arr[k] = "stuff";
where I loop through each index and put "stuff" in it.
Now I want the size of the array which should be 213561, what's the correct way to do it and why is it so complex in C++?
What you are trying to do cannot work because sizeof works on types at compile-time (and pointer types never hold the size of the array they may be pointing to).
In your case, computing sizeof(arr) returns the size taken in memory by the pointer, not
size of the array * size of a std::string
I suggest you use one of these two options
either use fixed-size arrays (sizeof works)
or vectors (myVector.size() returns what you need)
... unless you have a good reason not to.
The correct way of doing this in C++ is to use a vector. That way you can either specify a size up-front, or resize it as you go.
Specifying size up-front:
using namespace std;
vector<string> arr(213561);
for (vector<string>::iterator p = arr.begin(); p != arr.end(); ++p)
{
*p = "abc";
}
Expanding the vector as you go:
using namespace std;
vector<string> arr; // <-- note, default constructor
for (int i = 0; i < 213561; ++i)
{
// add elements to the end of the array, automatically reallocating memory if necessary
arr.push_back("abc");
}
Either way, the size of the array is found with:
size_t elements = arr.size(); // = 213561
The sizeof method only works as long as your array is really an array, i.e. an object that has the array type. In your first example object arr has type int[17]. It is an array type, which means that you can use the sizeof method and get 17 as the result.
Once you convert your array type T[N] to a pointer type T *, you basically lose your array type. The sizeof method applied to a pointer will not evaluate to the size of the original array.
When you allocate array of type T[N] with new[], the result is a pointer of type T * right away. It is not an array type from the very beginning. The information about array size is lost right away and trying to use the sizeof method with such a pointer will not work. In order to preserve the size information about a dynamically allocated run-time sized array, you have to store it in a separate variable yourself.
Here is how you find the size of an array:
const size_t ARRAY_SIZE = 17;
int array[ARRAY_SIZE];
//...
std::cout << "My array size is: " << ARRAY_SIZE << "\n";
You can put ARRAY_SIZE into a header so that other translation units can access the array size.
If you want a dynamic array, that will grow as needed, try std::vector.
You need to keep track of the length using a separate variable. There is no way of getting the length of an area that you only have a pointer to, unless you store that length somewhere.
You cannot get the length of the allocated array.
What you can do is save it seperately at the time of allocation..
Also, you could check the length of the string (which isn't what you're asking, but still..) using strlen()
In c++ here arr is simply a reference to the first element of the array. In case of dynamic arrays it is not possible.
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;
}