views:

234

answers:

3

Hi I turned back to C++ after a long time in C#, PHP and other stuff and I found something strange:

temp.name = new char[strlen(name) + strlen(r.name) + 1];

this compiles

temp.name = (char *)malloc(sizeof(char[strlen(name) 
     + strlen(r.name) + 1]));

this doesn't (temp.name is a char *)

The compiler error is

error C2540: non-constant expression as array bound

Does anyone know what the problem might be and how it might be remedied? Thank you.

+6  A: 

sizeof(...) expects a constant compile-time expression. strlen is not a compile-time expression, it is a function which needs to be executed to get a result. Therefore, the compiler is not able to reserve sufficient storage for an array declared like this:

char c[strlen("Hello")];

Although the length of the string is clearly 5, the compiler does not know.

To avoid this pitfall, do not use sizeof here. Instead:

char* c = (char*)malloc(strlen(name)+strlen(rname)+1);

This gives you a pointer to n bytes in return. sizeof(char)==1 is always true, so the number of bytes in the buffer equals the number of chars you can store in it. To malloc arrays of a different type, multiply with the static size of one array element:

int* c = (int*) malloc(sizeof(int)*100);

This is Ok, because sizeof is applied to a compile-time expression. Of course, the C++ way is much cleaner:

int* c = new int[100];
Alexander Gessler
A: 

malloc needs a size_t as its input, meaning you need to calculate the actual size and pass that in instead of specifying the type:

temp.name = (char *) malloc( (strlen(name) + strlen(r.name) + 1)) * sizeof(char));

You should probably be using new anyway, so I don't see any real issues.

Platinum Azure
1 == sizeof(char) is always true, so you don't need to multiply by it.
Todd Gardner
I know, but I do it habitually in case I ever want to change types later (to the wide character type maybe?). Then I can do something like ":s/char/wchar_t/g" in vim and everything's fixed automatically. :-)
Platinum Azure
If that's the intent, then it's probably better to use `sizeof *temp.name`
Johannes Schaub - litb
Hmmm... that's a good point, actually. In my case I've habitually used the types for clarity (i.e., so you don't have to check the type of the variable again to get an actual size, if you're trying to do a back-of-the-envelope memory estimate), but that would work just as well and I don't have any really good reason not to do that.
Platinum Azure
+1  A: 

The problem is char[...] which is an array type and in C++ (and C89) array sizes need to be compile-time constants. You should probably use std::string instead of allocating the memory manually by new[] or malloc(), but if you prefer to use manual allocation, calculate the size directly as the number of characters instead of using arrays and sizeof to do it.

Tronic