C++ strcpy non-constant expression as array bound - c++

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.

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];

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.

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.

Related

Sizeof is returning pointer size rather than array size. Any other way to find the size?

I am working on a coding assignment for my class and I ran into a problem!
I have this constructor here, for a String object:
String::String(char str[]) {
size = (sizeof(str)/sizeof(str[0]));
data = new char[size];
for (int i = 0; i < size; ++i) {
data[i] = str[i];
}
}
Here is part of the main I was provided:
char test[11] = "Hello world";
String two(test);
cout << "The length of String two is: " <<
two.length() << endl;
cout << "The value of String two is: ";
two.print();
So when I run this, I would get 8 for the size (should be 11). However, after some research, I figured out it is because the sizeof(str) is returning the byte size of a pointer, rather than the entire array.
So is there any way to get the size of the whole array with what I have? I am not supposed to manipulate the provided main, therefore I cannot add an int size to the parameters, which would be the obvious solution.
I've been stuck on this one for a bit, thanks for any help and suggestions,
Array decays to pointer when passed to a function.
You have to either pass the length to the function, pass a STL container e.g. std::vector or use strlen() inside function. (Note that strlen() need a terminating null-character to work properly and you have to add that to your array)
You can not get size of array at runtime in C. At runtime, array is just the address. The size is simply not stored anywhere. In source code, at compile time, in a place where compiler knows the size, you can use sizeof operator, but that gets essentially converted to a constant numeric literal, ie. same as writing the right number there yourself (VLAs are a bit more complex case, and of course using sizeof can create portable code unlike hard-coded number).
To make matters worse (for understanding C), when you have a function parameter that looks like an array, it really is a pointer. Even if you give it static size in the parameter list, sizeof still it gives you size of pointer, for example. Only non-parameter variables can actually be arrays, with sizeof working as expected.
You have to pass the size somehow (usually as extra parameter) or have some other way of telling where the data ends (such as strings' '\0' at the end).
Use a vector instead of char array. You can get size by calling size() method of vector container. If you want to use a char array, then it is a common practice in c programming to pass size as second parameter in the function.
You will only get size of array using sizeof() function on the function stack in which the array is defined and if the array size is known in compile time.

How to get size of char* x[]

How would I get the size of this:
char* stringit[4] = {"H","H","UH","i"};
I tried:
sizeof(stringit);
and it outputed 32.
I tried to make a for loop:
for (i= 0; check != 0; ++i){
check = stringit[i];
}
and that did not work either. Is there anyway to do this without having to pass in the size of the array?
make it a NULL terminated array of pointers
char* stringit[] = {"H","H","UH","i" , NULL };
Then just count the pointers until you find a null pointer.
The right way to get the number of elements of an array is to divide its actual size (in bytes) by the size of an element:
sizeof(stringit) / sizeof(stringit[0])
But unless you have extremely specific requirements, you should use a standard container like vector (and string too instead of char* C strings):
std::vector<std::string> stringit = {"H","H","UH","i"};
std::cout << stringit.size();
As #KonradRudolph mentioned, vector is nice if your number of elements is variable. If the number of elements is known at compile time and will never change you could instead use array:
std::array<std::string, 4> stringit = {"H","H","UH","i"};
std::cout << stringit.size();
As long as you have access to the array itself, i.e. as long as you have not converted it to a pointer, the number of elements can be calculated as
sizeof stringit / sizeof *stringit
which will evaluate to a compile-time constant 4 in your case.
Whether this is what you are looking for or not depends on some additional details, which you did not provide in your question. You mention "having to pass in the size of the array". Pass where?
32 is the right size. The variable stringit is an array of 4 char pointers, and each pointer is 8 bytes.
What is it that you are trying to do?
char* stringit[4] = {"H","H","UH","i"};
is an array of 4 strings, i.e. array of 4 char* (pointer holds an address, 64bit address = 8 bytes). That's why you get 32. To retrieve the number of elements, you could do:
int count = sizeof(stringit) / sizeof(stringit[0]);
which will give you 4. But note that this kind of approach isn't much flexible and I'd rather use some STL container, i.e. std::vector<char*> or yet even better, get rid of C-style strings as well and use std::vector<std::string> instead.
The sizeof works for static arrays. It's giving you the size of the construct in bytes.
If you want length, do sizeof(stringit) / sizeof(char*).
For a more flexible solution that is probably the ``Right way" to do things in C++ (which works for dynamic arrays), just use std::array, or std::vector/std::list, if you need more dynamic allocation.
http://www.cplusplus.com/reference/array/array/
http://www.cplusplus.com/reference/vector/vector/
http://www.cplusplus.com/reference/list/list/
With this construct, you can simply use a size() member.
Remember to pass by reference when necessary to avoid needless copying.

Must have const value in Visual C++

I have this code:
std::string name = "kingfisher";
char node_name[name.size()+1];
strcpy(node_name,name.c_str());
node_name[name.size()] = '\0';
It worked well in DevC++, but in Visual C++, i got a problem named "name.size() must be constant value"! How to solve the problem? I know that i have to use a const value in declaration of node_name, but sometimes (like the case above) i cant! thanks!
char node_name[name.size()+1];
As the value of name.size() is not known at compile time, in the above declaration,node_name is variable length array (VLA) which is not allowed in ISO C++.
In DevC++, it compiles and works, because it provides VLA feature as extension, which is enabled in your compilation configuration.
Use std::string, or char * along with new[]/delete[], whatever suits your need.
In your particular case, i.e if you know the string-literal already, then you could write this:
char node_name[] = "kingfisher"; //this works great!
However, if the string value isn't known and you want to copy it from somewhere, then do this:
char *node_name = new char[name.size()+1];
std::strncpy(node_name, name.c_str(), name.size()+1); //use strncpy
//work with node_name
//must deallocate the memory
delete []node_name; //not `delete node_name;`
Use std::strncpy instead of std::strcpy, as the former takes the buffer-size also as third argument, as shown above, and the latter doesn't (which is unsafe usually; not in this case though).
Variable-length arrays are not part of standard C++. You need to give the size at compile time. name.size() will occur at runtime. A comment should suffice to explain the magic number, or a constant.
char node_name[11]; //length of "kingfisher" + null
If you don't know the length of the string at compile time (but you do in your example), you can use a dynamic array, as explained quite well in Nawaz's answer.
There are many choices:
std::string name = "kingfisher";
char* node_name = alloca(name.size() + 1);
strcpy(node_name, name.c_str());
// no need to explicitly set the '\0' - strcpy copies it too
...OR...
char* node_name = new char[name.size() + 1];
strcpy(node_name, name.c_str());
...OR...
char* node_name = strdup(name.c_str()); // allocate on malloc/free/realloc "C" heap
...OR...
std::vector<char> node_name(name.data(), name.data() + name.size()); // sans '\0'
...OR...
std::vector<char> node_name(name.c_str(), name.c_str() + name.size() + 1); // with '\0'
...OR...
std::string node_name = node; // do something with node_name.c_str() / .data() etc.
Note: despite Ernest's "Don't use malloc() in C++, use new[]" comment on Stefan's deleted answer, it can be necessary - for example, when passing pointers to C code that may realloc or free the memory.
An array whose size is determined at runtime is called a variable-length array or VLA. VLAs are a feature in C99. Some C++ compilers support them as an extension, and some do not; sounds like your version of Visual C++ does not.
You could always allocate node_name dynamically with new, rather than on the stack.
My first approach would be to look at what you are using the array for and ask if there is a better way of doing it.
If you really need the array, I'd suggest a vector: which is dynamically sizeable but doesn't need to be deleted.
std::string name = "kingfisher";
std::vector<char> name_buff(name.begin(), name.end());
name_buff.push_back(0); // nul-terminate
char *node_name = &name_buff[0];
// ...

Why sizeof Variablename / sizeof * VariableName not work as desired?

class Simple {
string *data ;
//some functions and declaration of some variable,const, dest
};
When I did ;
data = new string [10] ;
cout << sizeof data / sizeof *data << endl ;
==> 1 // output
data = new string [50];
cout <<sizeof data / sizeof *data <<endl ;
==> 1 // output
**Why** do all output display the same ?
Because it simply doesn't work at all.
It only works for plain old arrays that are declared this way :
string a[10];
and it is the only case when this work.
in your case, you can't retrieve the size from the pointers you have. you have to either store the size of what you have, or just use the STL containers which all have a .size() member. The latter is preferable.
Because sizeof is a compile-time calculation, not a run-time one. And your array size is not known until run-time.
sizeof does not know anything about where the pointer points to, so it doesn't matter how big of a buffer you allocated, or even that you allocated a buffer at all. You can even do:
data = NULL;
x = sizeof(*data);
Because it's calculated at compile-time, there is no null-pointer dereferencing.
sizeof only looks at the datatype you pass in, not the data itself. In this case, string*, which is the same size no matter where it points to.
You have a few options to make this "work":
Use a statically-sized array (e.g. string data[50];) where you can use your sizeof idiom, but of course you get all the standard limitations of static arrays then.
Continue to dynamically allocate using new, but just store the array size and pass it around wherever you need it.
Preferred: Use std::vector for arrays -- this is basically the best of all worlds.
What is sizeof data? It is the size of a string*. What is sizeof *data? It is the size of what data points to, that is, size of string. Both of these are constant.
data does not have any knowledge about how many elements you allocated - it is just a stupid pointer.
You have to remember, sizeof always evaluates in compile-time. So you can never get sizeof info about things that happens in run-time, like new calls.

Determining the correct size for a C++ array

I need to be able to set the size of an array based on the number of bytes in a file.
For example, I want to do this:
// Obtain the file size.
fseek (fp, 0, SEEK_END);
size_t file_size = ftell(fp);
rewind(fp);
// Create the buffer to hold the file contents.
char buff[file_size];
However, I get a compile time error saying that the size of the buffer has to be a constant.
How can I accomplish this?
Use a vector.
std::vector<char> buff(file_size);
The entire vector is filled with '\0' first, automatically. But the performance "lost" might not be noticable. It's certainly safer and more comfortable. Then access it like a usual array. You may even pass the pointer to the data to legacy C functions
legacy(&buff[0]); // valid!
You should use a std::vector and not an array.
Real arrays require you to specify their size so that the compiler can create some space for them -- this is why the compiler complains when you don't supply a constant integer. Dynamic arrays are represented by a pointer to the base of the array -- and you have to retrieve the memory for the dynamic array yourself. You may then use the pointer with subscript notation. e.g.,
int * x;
x = (int *) malloc( sizeof(int) *
getAmountOfArrayElements() /* non-const result*/
);
x[5] = 10;
This leads to two types of problems:
Buffer over/under flows : you might subscript-index past either end of the array.
You might forget to release the memory.
Vector provides a nice little interface to hide these problems from you -- if used correctly.
Replace
char buff[file_size];
with
char *buff = new char[file_size];
and once the use of the buff is done..you can free the memory using:
delete[] buff;
There are two points in your question I'd like to cover.
The actual question, how do you create the array. Johannes answered this. You use a std::vector and create it with a size allocation.
Your error message. When you declare an array of some type, you must declare it with a constant size. So for example
const int FileSize = 1000;
// stuff
char buffer[FileSize];
is perfectly legitimate.
On the other hand, what you did, attempting to declare an array with variable size, and then not allocating with new, generates an error.
Problem is that buff needs be created on the heap (instead of stack). Compiler want s to know the exact size to create on the stack.
char* buff = new char[file_size];