0

So I have a C++ struct, which has a static array as a member, and I want to ask for it's size in the constructor. As I understood from this article http://msdn.microsoft.com/en-us/library/4s7x1k91(VS.71).aspx, sizeof can be applied to a static array to find the size (in bytes) of the entire array, not just it's type. However, when I do sizeof() on the member, it gives me 4 (the size of the pointer) instead of the size of the array. Here's the context (trivialized):

struct A
{
    char descirption[128];
    int value;

    A(const char desc[], int val)
    {
        size_t charsToCopy = std::min(sizeof(description), sizeof(desc));
        memcpy(description, desc, charsToCopy);
        value = val;
    }
}

int main()
{
    A instance("A description string", 1);
    //now instance has a description string that says "A des" followed by garbage characters
}

So how do I get the size of a member char array?

Edit

When I put a breakpoint in the compiler and inspect the two values sizeof(description) and sizeof(desc) I see sizeof(description) == 4, and sizeof(desc) == 21. Hence my confusion. Because I'm passing a string literal into the constructor, the compiler seems perfectly happy to tell me the real size of the string passed in. Maybe that wouldn't be the case if I assigned it to a variable somewhere, but right now I'm trying to track down the fundamental problem: sizeof( some-member-static-array ) gives me something (relatively) meaningless.

Is it possible that sizeof is doing some sort of string length measurement because it's an array of chars?

xaviersjs
  • 1,579
  • 1
  • 15
  • 25
  • 1
    Do you know that `sizeof(desc)` is always the size of a pointer, as the parameter `const char desc[]` decays into `const char* desc`? – dyp Feb 03 '14 at 12:06
  • 1
    `sizeof(description)` is fine, `sizeof(desc)` is the size of a char pointer. Why use `memcpy` to copy a null terminated string anyway? – Retired Ninja Feb 03 '14 at 12:07
  • `sizeof(description) == 128`, `sizeof(desc) == sizeof(void*)`, what else did you expect? – David Heffernan Feb 03 '14 at 12:07
  • @SteveJessop I'm sure you know the answer to the question you ask me. I certainly don't! – David Heffernan Feb 03 '14 at 12:11
  • You can make it type and pass variable in this type as parameter and than you can use as sizeof(TDesc) : typedef struct { unsigned char Description[128]; } TDesc; – Mehmet Fide Feb 03 '14 at 12:20

3 Answers3

5

Despite the syntax, you can't pass an array by value to a function. It decays to a pointer, leaving no way to find the size; your function is equivalent to

A(const char * desc, int val)

so that sizeof(desc) is the size of a pointer.

You could pass the array by reference, templating the function by the array's size:

template <size_t desc_size>
A(const char (&desc)[desc_size], int val)

The size argument will be inferred automatically from the function argument, so your code passing a string literal will work as it is.

However, this only works when the argument really is an array of known size; if you want to deal with more general strings, then you'll need something more complicated. Usually, it's more convenient to use std::string to manage strings - it handles memory automatically, and keeps track of the size for you.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
2

It's not the member that's giving you a size of 4, it's the argument. Array type parameters in C++ are transformed to pointers, so your constructor is equivalent to:

A(const char *desc, int val)

That's why you're getting the size of a pointer. If you really want to use memcpy, you'll have to pass the length of your array to the constructor. The alternative is to use strncpy with a maximum number of characters set to 128.

Of course, if you were using std::string, you wouldn't have this problem.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
0

In this constructor

A(const char desc[], int val)
{
    size_t charsToCopy = std::min(sizeof(description), sizeof(desc));
    memcpy(description, desc, charsToCopy);
    value = val;
}

parameter desc is implicitly converted by the compiler to the pointer to its first character. As you are using function std::min then it is obvious that sizeof( const char * ) is less than sizeof( description ) and the function will always return 4 provided that the size of pointer is equal to 4.

Moreover it can occur that the resulted string will not contain the terminating zero after the call of memcpy. I would define the constructor the following way

A(const char desc[], int val)
{
    strncpy(description, desc, 128);
    description[127] = '\0';
    value = val;
}

Also it is a good idea to define a name for the magic number 128 either using an enymerator or static constant.

Or at least you can write the following way

A(const char desc[], int val)
{
    const size_t N = sizeof( description );
    strncpy(description, desc, N);
    description[N-1] = '\0';
    value = val;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335