I want to create an array of chars (char path[size] = "") while getting "size" from user.
When I try something like this:
int size = getSizeFromUser();
char path[size] = "";
I get a warning says "expression must have a constant value".
How can I do it right?
Thanks a lot!
How can I do it right?
Variable length arrays aren't standard c++. The correct way to do it is to use a std::vector or a std::string instead of a raw array:
int size = getSizeFromUser();
std::string path(size,'\0');
In order to create a table with the users size you have to allocate your memory on the heap
int size = 4;
char *path = new char[size];
after using your array you have to manually delete it from the heap
delete path;
If you declare char path[size]; then size has to be known at compile time. You read it at runtime so you need to use dynamic memory allocation, like char* path = new char[size]; and when you are finished call delete []path;.
If you want this to be a string with size visible characters, please consider that C-strings are null-terminated, meaning that you would have to reserve one extra char at the end of the array and set it to 0.
A better solution for a C++ program would probably be to use a std::string instead of a char*.
When creating an array, its size must be constant.
If you want a dynamically sized array, you will have to allocate memory for it and you'll also need to free it when you're done with it.
To simply all these its always nice to use std::string
Related
In C++, what's the difference between this:
char example[10];
and this:
char* example = new char[10];
in both cases, I'm not initializing the content of the arrays, but just wanting to get 10-bytes in memory allocated to the character array. In both cases, I intend to then use sprintf() to assign a string value to them with no intermediate step.
This:
char example[10];
Declares example as an array of char containing 10 elements. If declared at file scope, this array will typically reside in the data segment, while if it is declared at block scope it will typically reside on the stack.
In contrast, this:
char* example = new char[10];
Declares example as a pointer to char, and initializes it with a pointer to dynamically allocated memory which points to the first member of a 10 member array of char. This dynamically allocated memory typically resides on the heap.
Note also that new is specific to C++.
char example[10];
example is an array of 10 chars. Depending on context, it has automatic or static storage. The size can only be compile time constant. The array is destroyed and deallocated automatically.
char* example = new char[10];
example is a pointer. It is not an array. It points to first element of an array in dynamic storage. The size of dynamic array can be determined at runtime. The array is not destroyed and deallocated automatically. If not deallocated, the memory will leak.
Dynamic allocation is generally slower than static or automatic. On the other hand, the amount of memory available for automatic storage is typically very limited.
Bare owning pointers should be avoided. Best practice is to use a smart pointer or a RAII container such as std::vector when dynamic array is needed.
The main difference is that, in your first example you are have to already know at declare this char array his size, but in your second example, you are declare char array with pointer, which points on some value. That means you can only declare some char pointer without knowing the size of the char array. It is very usefull for programs, where the user has to write his nickname as input, maximal lenght of nickname can be 10 characters, but it can be less then 10 characters, that means you have to use pointers for dynamic allocating memory so as not to use too much unused memory.
For example:
int main()
{
char nm[10]; //Create char array, where you will save an input
char* nickname; //Declare pointer
std::cout << "Nickname: " << std::endl;
fflush(stdin);
gets(nm); //Save input
// Here we go find the size of used memory in char array nm
int size_of_nm = 0;
for (char i : nnnn)
{
if (i == '\0') //If char i is equal to zero character, we find the size of used
{ //memory in char array nm
break;
}
else //If i is not equal to zero character, we do not find the size of used
{ //memory in char array nm and loop will continue
size_of_nm++; //Size counter plus one
}
}
nickname = new char[size_of_nm + 1]; //Create new pointer on char array and set the
//size of used memory in char array
//plus one, because the char array is always
//ending with zero character
}
But I recommend using a strings. It is more safer, because you dont have to know the size of used memory, memory of string is allocated automatically.
I need an array to store char arrays of variable size. I could use vectors or anything else, but unfortunately this is for a MPI project and I am forced to use an array so I can send it using MPI::COMM_WORLD.Send(...) function.
My idea comes from this link.
This is a simplified example of the problem I have:
char* arrayStorage[3]; //I want to store 3 char arrays of variable size!
int index = 0;
char array_1[RANDOM_SIZE] = {.....};
char array_2[RANDOM_SIZE] = {.....};
char array_3[RANDOM_SIZE] = {.....};
arraySorage[index] = array_1;
index++;
arraySorage[index] = array_2;
index++;
arraySorage[index] = array_3;
index++;
I have also seen people talking about malloc and stuff like that, but I don't know much about pointers. I do malloc, I have to call free and I don't know where, so I am avoiding that for now.
This code obviously doesn't work, array_1, array_2, array_3 are all OK, but when I try to access them I get garbage. The problem seems to be inside the index variable. Maybe I shouldn't be doing index++, perhaps I should be doing index += RANDOM_SIZE, but that also fails.
How can I store variable size char arrays in an array?
Use malloc and free (or new and delete in C++). You can do it with vectors too - as vectors can be treated as arrays.
char *str = "hello world";
// need the +1 for null character
arraySorage[0] = (char *)malloc (strlen(str) + 1);
strcpy(arraySorage[0], str);
...
free(arraySorage[0]);
with new/delete
arraySorage[0] = new char[strlen(str)+1];
strcpy(arraySorage[0], str);
...
delete arraySorage[0];
Using vector and std::string is the correct C++ way, for lots of reasons, including not leaking memory and proper handling of exceptions.
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];
// ...
Can you please tell me how to change the size of the buf vector into a dynamic length?
long five = 555;
char buf[256];
snprintf(buf, sizeof(buf), "%d", five);
THX!
How to change my code with std::vector<std::string>buf; in order to work correctly?
I have error:
vector is not a member of std;
buf was not declared in this scope and error: expected primary-expression before ">" token
In C++, you can't. You will have to allocate it dynamically somehow, or better still use a dynamic data structure like a std::vector.
Try:
#include <vector>
#include <string>
long five = 555;
// using vector
std::vector<char> buf1(256);
snprintf(&buf1[0], buf1.size(), "%d", five);
// Or using string
std::string buf2(256);
snprintf(&buf2[0], buf2.size(), "%d", five);
Though rather than using snprintf() I would look up how to use stringstream.
if you're really opposed to using the vector class, you could implement the dynamic memory yourself. Create a function for adding to the array when theres not enough memory to store the new values. It would malloc new memory, copy the contents over, append new values, delete the old memory, then return a pointer to the new array. They amount new memory that you would use would depend on your application.(ie. just enough memory to store new values to conserve memory, or a lot more(eg double) than the old size so you wouldn't have to call this function as often.
You probably want to make a vector of characters, not a vector of strings.
The second error I suspect is a missing space character before the variable name.
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];