1

Okay so you have and array A[]... that is passed to you in some function say with the following function prototype:

void foo(int A[]);

Okay, as you know it's kind of hard to find the size of that array without knowing some sort of ending variable or knowing the size already...

Well here is the deal though. I have seem some people figure it out on a challenge problem, and I don't understand how they did it. I wasn't able to see their source code of course, that is why I am here asking.

Does anyone know how it would even be remotely possible to find the size of that array?? Maybe something like what the free() function does in C??

What do you think of this??

template<typename E, int size>
int ArrLength(E(&)[size]){return size;}

void main()
{
    int arr[17];
    int sizeofArray = ArrLength(arr);
}
6
  • 2
    Since you tagged C++, here is a related thread. Use templates to find array size Commented Nov 4, 2011 at 15:11
  • 3
    Can you provide a link to the actual question in the contest? The translated problem that you state cannot be solved, but the original one might be solvable. Commented Nov 4, 2011 at 15:12
  • 1
    @Mahesh: That is a solution to obtain the size from the calling point, but not inside the function. Inside the function the size of the array is already gone (the argument is not an array but a pointer) Commented Nov 4, 2011 at 15:13
  • David Rodriguez is correct: you can't do it from the function signature you've given. Commented Nov 4, 2011 at 15:18
  • I understand the pointer deal... and know that I cannot get the size when it decays in the function, but I also don't understand how other people did it... Unless they just assumed that a -'ive number or ends the array... Ya I don't understand because in this question, you need the size of the array and they don't give it to you how many variables are in there. They give you a range of the array size but that doesn't really help anyone now does it... Commented Nov 4, 2011 at 15:22

10 Answers 10

9

The signature of that function is not that of a function taking an array, but rather a pointer to int. You cannot obtain the size of the array within the function, and will have to pass it as an extra argument to the function.

If you are allowed to change the signature of the function there are different alternatives:

C/C++ (simple):

void f( int *data, int size );             // function
f( array, sizeof array/sizeof array[0] );  // caller code

C++:

template <int N>
void f( int (&array)[N] );                 // Inside f, size N embedded in type
f( array );                                // caller code

C++ (though a dispatch):

template <int N>
void f( int (&array)[N] ) {                // Dispatcher
   f( array, N );
}
void f( int *array, int size );            // Actual function, as per option 1
f( array );                                // Compiler processes the type as per 2
Sign up to request clarification or add additional context in comments.

6 Comments

If you want to avoid template code bloat caused by having one separate function for each array size, you could also write a small, inlineable template dispatch function that calls f(array, N).
okay... how about... say if you know the MAX size the array can have... can you do it somehow using say realloc and reallocating the array to the max size. The only problem is that how do to know where the array ends. In other words how do you set the reallocated data to say a set of -1's so you know the array end's...
@Edwin: you can only call realloc on memory that was allocated with malloc which means that in C/C++ if you want to use a statically allocated array you are doomed, and in C++ if you dynamically allocated the array with new you are doomed again.
@DavidRodríguez-dribeas: Neat. Also, with the separation you can call the main function on a dynamic array, too. It's a true buy-one-get-one-free situation!
@KerrekSB: I would expect you to like it, as it was your idea originally :)
|
2

You cannot do that. Either you have a convention to signal the end of the array (e.g. that it is made of non-zero integers followed by a 0), or you transmit the size of the array (usually as an additional argument).

If you use the Boehm garbage collector (which has a lot of benefit, in particular you allocate with GC_malloc and friends but you don't care about free-ing memory explicitly), you could use the GC_size function to give you the size of a GC_malloc-ed memory zone, but standard malloc don't have this feature.

3 Comments

What if the array is sitting on the stack?
My point was, that you don't have to malloc or in your case GC_malloc the memory region. Hence, even if you do use your garbage collector it's not going to help you determine the length of the array.
Yes. According to comments in gc/gc.h the GC_size function : Given a pointer to the base of an object (i.e. a memory zone returned by GC_malloc...), return its size in bytes. The returned size may be slightly larger than what was originally requested. But as I said initially, it cannot be done, because A C pointer is a raw address and does not know the size of the allocated zone.
2

You're asking what we think of the following code:

template<typename E, int size>
int ArrLength(E(&)[size]){return size;}

void main()
{
    int arr[17];
    int sizeofArray = ArrLength(arr);
}

Well, void main has never been standard, neither in C nor in C++.

It's int main.

Regarding the ArrLength function, a proper implementation does not work for local types in C++98. It does work for local types by C++11 rules. But in C++11 you can write just end(a) - begin(a).

The implementation you show is not proper: it should absolutely not have int template argument. Make that a ptrdiff_t. For example, in 64-bit Windows the type int is still 32-bit.

Finally, as general advice:

  • Use std::vector and std::array.

One relevant benefit of this approach is that it avoid throwing away the size information, i.e. it avoids creating the problem you're asking about. There are also many other advantages. So, try it.

1 Comment

How is int[17] a local type?
1

The first element could be a count, or the last element could be a sentinel. That's about all I can think of that could work portably.

In new code, for container-agnostic code prefer passing two iterators (or pointers in C) as a much better solution than just passing a raw array. For container-specific code use the C++ containers like vector.

Comments

1

No you can't. Your prototype is equivalent to

void foo(int * A);

there is obviously no size information. Also implementation dependent tricks can't help:

  • the array variable can be allocated on the stack or be static, so there is no information provided by malloc or friends
  • if allocated on the heap, a user of that function is not forced to call it with the first element of an allocation.

e.g the following are valid

int B[22];
foo(B);
int * A = new int[33];
foo(A + 25);

2 Comments

Actually there are non-portable ways around this, see my answer.
@Luchian, no your answer doesn't help for the +25 case at all.
0

This is something that I would not suggest doing, however if you know the address of the beginning of the array and the address of the next variable/structure defined, you could subtract the address. Probably not a good idea though.

2 Comments

The language offers absolutely no guarentees about where in memory objects are laid out, except some minimal instructions about subobjects within structures. int a, b; assert(&a == &b+1); can easily fail. With heap allocations it is even worse.
I know there are no guarantees, that's why I wouldn't suggest implementing my idea. However, more times than not, while using a debugger I've seen large chunks of contiguous data allocated in the same manner as defined in the source code. just my $0.02...
0

Probably an array allocated at compile time has information on its size in the debug information of the executable. Moreover one could search in the code for all the address corresponding to compile time allocated variables and assume the size of the array is minus the difference between its starting address and the next closest starting address of any variable.

For a dinamically allocated variable it should be possible to get its size from the heap data structures.

It is hacky and system dependant, but it is still a possible solution.

1 Comment

Non-dynamically allocated arrays don't have their size stored at runtime, anywhere. It's purely a compile-time thing.
0

One estimate is as follows: if you have for instance an array of ints but know that they are between (stupid example) 0..80000, the first array element that's either negative or larger than 80000 is potentially right past the end of the array.

This can sometimes work because the memory right past the end of the array (I'm assuming it was dynamically allocated) won't have been initialized by the program (and thus might contain garbage values), but might still be part of the allocated pages, depending on the size of the array. In other cases it will crash or fail to provide meaningful output.

Comments

0

All of the other answers are probably better, i.e. you either have to pass the length of the array or terminate it with a special byte sequence.

The following method is not portable, but it works for me in VS2005:

int getSizeOfArray( int* ptr )
{
   int size = 0;
   void* ptrToStruct = ptr;
   long adr = (long)ptrToStruct;
   adr = adr - 0x10;
   void* ptrToSize = (void*)adr;
   size = *(int*)ptrToSize;
   size /= sizeof(int);
   return size;
}

This is entirely dependent of the memory model of your compiler and system so, again, it is not portable. I bet there are equivalent methods for other platforms. I would never use this in a production environment, merely stating this as an alternative.

4 Comments

+1 for making it clear this is highly non-portable. -1 for only working with pointers to the beginning of heap-allocated arrays. Pointers to the middle of a heap-allocated array, or to any part of a stack-allocated array, will fail.
+-1 from me also. Casting void* to long, argh.
Also you should somehow document for which cases of invocation this works. auto, static arrays, allocation with malloc or new... Can't imagine that this works for all of them.
@JensGustedt I didn't bother with this because I know no one will ever use it... me included. I just thought it was a nice little hack, spent a couple of minutes in dissasembly, had a little fun, that's about it :)
-1

You can use this: int n = sizeof(A) / sizeof(A[0]);

1 Comment

This only works when A is declared as an array, not as a pointer. Remember that sizeof is a compiler thing. It is not a function executed at runtime.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.