4

Let's say I have a macro called LengthOf(array):

sizeof array / sizeof array[0]

When I make a new array of size 23, shouldn't I get 23 back for LengthOf?

WCHAR* str = new WCHAR[23];
str[22] = '\0';
size_t len = LengthOf(str); // len == 4

Why does len == 4?

UPDATE: I made a typo, it's a WCHAR*, not a WCHAR**.

Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • 1
    Possible duplicate of [How to find the sizeof( a pointer pointing to an array )](http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array) (There might be a better match; this was the best I could find with a quick search). – James McNellis Jun 07 '10 at 22:33
  • 5
    You probably want a `std::vector >` or something. This is C++, not C. – fredoverflow Jun 07 '10 at 22:34

5 Answers5

12

Because str here is a pointer to a pointer, not an array.

This is one of the fine differences between pointers and arrays: in this case, your pointer is on the stack, pointing to the array of 23 characters that has been allocated elsewhere (presumably the heap).

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
11
WCHAR** str = new WCHAR[23];

First of all, this shouldn't even compile -- it tries to assign a pointer to WCHAR to a pointer to pointer to WCHAR. The compiler should reject the code based on this mismatch.

Second, one of the known shortcomings of the sizeof(array)/sizeof(array[0]) macro is that it can and will fail completely when applied to a pointer instead of a real array. In C++, you can use a template to get code like this rejected:

#include <iostream>

template <class T, size_t N>
size_t size(T (&x)[N]) { 
    return N;
}

int main() { 
    int a[4];
    int *b;

    b = ::new int[20];

    std::cout << size(a);      // compiles and prints '4'
//    std::cout << size(b);    // uncomment this, and the code won't compile.
    return 0;
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

As others have pointed out, the macro fails to work properly if a pointer is passed to it instead of an actual array. Unfortunately, because pointers and arrays evaluate similarly in most expressions, the compiler isn't able to let you know there's a problem unless you make you macro somewhat more complex.

For a C++ version of the macro that's typesafe (will generate an error if you pass a pointer rather than an array type), see:

It wouldn't exactly 'fix' your problem, but it would let you know that you're doing something wrong.

For a macro that works in C and is somewhat safer (many pointers will diagnose as an error, but some will pass through without error - including yours, unfortunately):

Of course, using the power of #ifdef __cplusplus you can have both in a general purpose header and have the compiler select the safer one for C++ builds and the C-compatible one when C++ isn't in effect.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

The problem is that the sizeof operator checks the size of it's argument. The argument passed in your sample code is WCHAR*. So, the sizeof(WCHAR*) is 4. If you had an array, such as WCHAR foo[23], and took sizeof(foo), the type passed is WCHAR[23], essentially, and would yield sizeof(WCHAR) * 23. Effectively at compile type WCHAR* and WCHAR[23] are different types, and while you and I can see that the result of new WCHAR[23] is functionally equivalent to WCHAR[23], in actuality, the return type is WCHAR*, with absolutely no size information.

As a corellary, since sizeof(new WCHAR[23]) equals 4 on your platform, you're obviously dealing with an architecture where a pointer is 4 bytes. If you built this on an x64 platform, you'd find that sizeof(new WCHAR[23]) will return 8.

Nathan Ernst
  • 4,540
  • 25
  • 38
0

You wrote:

WCHAR* str = new WCHAR[23];

if 23 is meant to be a static value, (not variable in the entire life of your program) it's better use #define or const than just hardcoding 23.

#define STR_LENGTH 23
WCHAR* str = new WCHAR[STR_LENGTH];
size_t len = (size_t) STR_LENGTH;

or C++ version

const int STR_LENGTH = 23;
WCHAR* str = new WCHAR[STR_LENGTH];
size_t len = static_cast<size_t>(STR_LENGTH);
user347594
  • 1,256
  • 7
  • 11