tags:

views:

339

answers:

8

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++?

A: 

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.

Thomas Padron-McCarthy
A: 

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()

rmn
+8  A: 

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.

Benoît
A: 

In c++ here arr is simply a reference to the first element of the array. In case of dynamic arrays it is not possible.

Vitaliy Liptchinsky
+6  A: 

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
therefromhere
A: 

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.

AndreyT
Nitpick: sizeof is an operator, not a method. And sizeof doesn't return the number of elements in the array, but the size in bytes (or more correctly, chars).
Thomas Padron-McCarthy
Huh? I did't call `sizeof` itself a "method". The "sizeof method" I'm talking about is a weel-known *method* of determining the element count in a given array `a` by doing `sizeof a / sizeof *a`. It is called "sizeof trick", "sizeof method" and many other different names. Please, get accustomed with the accepted parlance or at least develop an intuition, before you start voting people's answers down.
AndreyT
@Andrey: Sorry about that. I completely misread your post. In my defence, I'll just say that it is a rather common misconception that sizeof is a function, and since "method" has a specific meaning in an object-oriented context, I misunderstood what you wrote. (The downvote is too old to be changed, so I looked at some other of your answers and upvoted them.)
Thomas Padron-McCarthy
A: 

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;
}
D.Shawley
I don't see what this code is trying to accomplish?
SuperString
A: 

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.

Thomas Matthews