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);
}
Edwin
  • 797
  • 2
  • 14
  • 23
  • 2
    Since you tagged C++, here is a related thread. [Use templates to find array size](http://stackoverflow.com/questions/4073276/use-templates-to-get-an-arrays-size-and-end-address) – Mahesh Nov 04 '11 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. – David Rodríguez - dribeas Nov 04 '11 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*) – David Rodríguez - dribeas Nov 04 '11 at 15:13
  • David Rodriguez is correct: you can't do it from the function signature you've given. – moswald Nov 04 '11 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... – Edwin Nov 04 '11 at 15:22
  • @DavidRodríguez-dribeas: Neat. The advantage of this separation is that you can still use the main function for dynamic arrays by passing the size directly. A true buy-one-get-one-free! – Kerrek SB Nov 04 '11 at 16:20

10 Answers10

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
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    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)`. – Kerrek SB Nov 04 '11 at 15:29
  • 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 Nov 04 '11 at 15:45
  • @KerrekSB: I had not thought of that, and it is quite a good approach for those cases where the function might be large and called with different sizes, where different instantiations of the dispatcher template will be created, but *inlined* and removed. The advantage over 1 is that the user is not responsible for producing the correct size, the compiler will do it. – David Rodríguez - dribeas Nov 04 '11 at 16:13
  • 1
    @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. – David Rodríguez - dribeas Nov 04 '11 at 16:14
  • 1
    @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! – Kerrek SB Nov 04 '11 at 16:57
  • 1
    @KerrekSB: I would expect you to like it, as it was your idea originally :) – David Rodríguez - dribeas Nov 04 '11 at 17:14
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.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • What if the array is sitting on the stack? – bitmask Nov 04 '11 at 15:38
  • 1
    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. – bitmask Nov 04 '11 at 16:58
  • 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. – Basile Starynkevitch Nov 04 '11 at 17:03
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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
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.

Mark B
  • 95,107
  • 10
  • 109
  • 188
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);
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
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.

rogerlsmith
  • 6,670
  • 2
  • 20
  • 25
  • 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. – Dennis Zickefoose Nov 04 '11 at 16:11
  • 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... – rogerlsmith Nov 04 '11 at 16:16
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.

Paolo
  • 2,461
  • 5
  • 31
  • 45
  • Non-dynamically allocated arrays don't have their size stored at runtime, anywhere. It's purely a compile-time thing. – fredoverflow Nov 04 '11 at 19:19
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.

Vlad
  • 18,195
  • 4
  • 41
  • 71
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.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • +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. – Dennis Zickefoose Nov 04 '11 at 16:05
  • +-1 from me also. Casting `void*` to `long`, argh. – Jens Gustedt Nov 04 '11 at 16:40
  • 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. – Jens Gustedt Nov 04 '11 at 16:44
  • @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 :) – Luchian Grigore Nov 04 '11 at 21:23
-1

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

Vaibhav Garg
  • 3,630
  • 3
  • 33
  • 55
  • 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. – Basile Starynkevitch Nov 04 '11 at 17:06