How to copy a string to newly allocated memory? - c++

In below code example, memory for an integer is dynamically allocated and the value is copied to the new memory location.
main() {
int* c;
int name = 809;
c = new int(name);
cout<<*c;
}
But, when I try to do the same with a char string it doesn't work.
Why is this?
int main() {
char* p;
char name[] = "HelloWorld";
p = new char(name);
cout << p;
}

Your second example doesn't work, because char arrays work differently than integer variables. While single variables can be constructed this way, this doesn't work with (raw) arrays of variables. (As you have observed.)
In C++ you should try to avoid handling pointers and raw arrays as much as you can. Instead, you'd rather use the standard library containers to take a copy of that string to an array of dynamically allocated memory. std::string and std::vector<char> are especially suitable in this case. (Which one should be preferred depends a bit on the semantics, but probably it's the std::string.)
Here's an example:
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
int main(){
char name[] = "Hello World";
// copy to a std::string
std::string s(name);
std::cout << s << '\n';
// copy to a std::vector<char>
// using strlen(name)+1 instead of sizeof(name) because of array decay
// which doesn't occur here, but might be relevant in real world code
// for further reading: https://stackoverflow.com/q/1461432
// note that strlen complexity is linear in the length of the string while
// sizeof is constant (determined at compile time)
std::vector<char> v(name, name+strlen(name)+1);
std::cout << &v[0] << '\n';
}
The output is:
$ g++ test.cc && ./a.out
Hello World
Hello World
For reference:
http://en.cppreference.com/w/cpp/string/basic_string
http://en.cppreference.com/w/cpp/container/vector

Your second code snippet does not work because new int(name) initializes an int from an int, while new char(name) tries to initialize a char from a char[11] array.
There is no array constructor taking an array in C++. In order to make a copy of an array, you must allocate an array, and then copy data into it:
p = new char[sizeof(name)];
std::memcpy(p, name, sizeof(name));

In the first case you allocate memory for a single int object, and initialize with a single int value. Great, this works.
In the second case you allocate memory for a single char object, and initialize it with an array of characters. It does not work, an array of objects does not fit in a memory of a single object. Besides, the array has a different type, so the initialization is ill-formed.
To allocate memory for an array of characters (such as a string), you can use new[]:
char* ptr = new char[11]{"HelloWorld"};
PS. The GNU compiler (until the current version 7 at least) and clang (until version 4) have a bug which breaks the above initialization. A workaround is to copy the string after allocation.
PPS. While it is useful to learn these things, don't do manual memory management in actual programs. Use RAII containers such as std::string for strings and std::unique_ptr for single dynamic objects.

Your code doesn't work as you are trying to initialize a char instead of array of characters. In order to dynamically allocate memory, you need to allocate the memory and then copy over the content.
p = new char[strlen(name) +1];
std::strcpy(p, name);

Related

c++ Create Char Array from Variable String passed as function parameter

I want to create a char array in a function from a string I have passed in.
bool foo(string s1, string s2) {
char s1_char_array[] = s1;
char s2_char_array[] = s2;
}
But I am met with
"Initialization with '{...}' expected for aggregate object."
For both declarations.
I've tried a lot of work arounds but they all have errors of their own. Learning C++ and every tutorial I find has the value hardcoded. How to make this work?
You can dynamically allocate arrays and copy data from the strings there.
#include <string>
#include <cstring> // for strcpy()
#include <algorithm> // for std::copy()
using std::string;
bool foo(string s1, string s2) {
// allocate arrays (+1 for terminating null-characters)
char* s1_char_array = new char[s1.size() + 1];
char* s2_char_array = new char[s2.size() + 1];
// copy data to arrays
#if 0
// if the strings are guaranteed not to contain '\0'
strcpy(s1_char_array, s1.c_str());
strcpy(s2_char_array, s2.c_str());
#else
// if the strings may contain '\0'
std::copy(s1.begin(), s1.end(), s1_char_array);
std::copy(s2.begin(), s2.end(), s2_char_array);
s1_char_array[s1.size()] = '\0';
s2_char_array[s2.size()] = '\0';
#endif
// do things with the arrays
// deallocate the arrays
delete[] s1_char_array;
delete[] s2_char_array;
// return something
return false;
}
The bad news is that there is no way to create an array variable from a std::string in general because std::string can represent strings of any size (very large practial limits exist but you'll run out of memory first on 64 bit systems) and that size is dynamic i.e. determined at run time. By contrast, the size of an array must be known at compile time at which time the size of the string is still unknown.
Another problem is that your arrays have automatic storage and the memory available for automatic storage is very limited - usually one to few megabytes on desktops / servers; potentially much less on embedded - while the dynamic memory owned by the string doesn't have such restriction and thus attempting to fit a large string into automatic storage could easily cause a "stack overflow".
Another issue is that arrays cannot be copy-constructed nor converted from other types so char s1_char_array[] = some_variable; can never work.
The good news is that you don't ever need to do that either. std::string already contains an array of chars internally, so there is no need to create a new array. Just keep using the array that is in the string.
this is what I come up with.
you have to declare the char array size same as strings by using string.lenght() function and
then use loops to copy the strings elements to char array index by index
bool foo(string s1, string s2) {
char s1_char_array[s1.length()] ;
char s2_char_array[s2.length()] ;
for(int i=0; i<s1.length(); i++){
s1_char_array[i]=s1[i];
}
for(int i=0; i<s2.length(); i++){
s2_char_array[i]=s1[i];
}
}

Declaring C++ array with or without the "new" keyword

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.

Needing to use char** in C++ instead of std::string*

I am working on an assignment for my operating systems class. We have the option of using C or C++, so I decided to use C++ since I practised it on the job a bit more recently than C.
I will need to call (from "
$ man execvp " on Linux)
int execvp(const char *file, char *const argv[]);
which (unless I am mistaken) means I need a C-style char* array (a string array in C), and will not be able to use std::string from C++.
My question is: what is the proper way to make/use char* arrays instead of string arrays in C++? Most people tend to say malloc is not used any more in C++ (which I tried now with some complications)
char** cmdList = (char**)malloc(128 * sizeof(char*));
but I don't know how to make a char* array without. Is it still appropriate to solve this how I would in C even though I'm using C++? I haven't ever run into a circumstance where I couldn't use string in C++.
Thanks for everyone's time.
If you put your arguments into a std::vector<std::string>, as you should in C++, then you need a small conversion to get to the char** that execvp wants. Luckily, both std::vector and std::string are continuous in memory. However, a std::vector<std::string> isn't an array of pointers, so you need to create one. But you can just use a vector for that too.
// given:
std::vector<std::string> args = the_args();
// Create the array with enough space.
// One additional entry will be NULL to signal the end of the arguments.
std::vector<char*> argv(args.size() + 1);
// Fill the array. The const_cast is necessary because execvp's
// signature doesn't actually promise that it won't modify the args,
// but the sister function execlp does, so this should be safe.
// There's a data() function that returns a non-const char*, but that
// one isn't guaranteed to be 0-terminated.
std::transform(args.begin(), args.end(), argv.begin(),
[](std::string& s) { return const_cast<char*>(s.c_str()); });
// You can now call the function. The last entry of argv is automatically
// NULL, as the function requires.
int error = execvp(path, argv.data());
// All memory is freed automatically in case of error. In case of
// success, your process has disappeared.
Instead of malloc use new[]:
char ** cmdlist = new char*[128];
There is no need for sizeof, since new knows the size of the type it creates. For classes this also calls the default constructor if it exists. But be careful: If there is no (public) default constructor for a type you can not use new[].
Instead of free use delete[] to release your memory when you are done:
delete[] cmdlist;
Of course, you could also use a vector. This has the advantage that the memory used to store the vector's content is automatically released when the vector is destroyed.
#include <vector>
...
std::vector<char*> cmdlist(128, nullptr); // initialize with nullpointers
// access to entries works like with arrays
char * firstCmd = cmdList[0];
cmdlist[42] = "some command";
// you can query the size of the vector
size_t numCmd = cmdlist.size();
// and you can add new elements to it
cmdlist.push_back("a new command");
...
// the vector's internal array is automatically released
// but you might have to destroy the memory of the char*s it contains, depending on how they were created
for (size_t i = 0; i < cmdlist.size(); ++i)
// Free cmdlist[i] depending on how it was created.
// For example if it was created using new char[], use delete[].
Assuming you have an std::vector<std::string> args variable that represents the argument list, you could do the following to get a C-style array of strings:
auto argvToPass = std::make_unique<const char*[]>(args.size() + 1);
int i = 0;
for (const auto& arg : args)
{
argvToPass[i++] = arg.c_str();
}
// make we have a "guard" element at the end
argvToPass[args.size()] = nullptr;
execvp(yourFile, argvToPass.get());
You can create an array of const char* and still use strings by using string.c_str() the code will look like this
const char ** argv = new const char*[128];
string arg1 = "arg";
argv[0] = arg1.c_str();
If you want to get fancy (and safe) about it you can use std::unique_ptr to good effect to ensure everything gets properly deleted/freed in the event of an error or an exception:
// Deleter to delete a std::vector and all its
// malloc allocated contents
struct malloc_vector_deleter
{
void operator()(std::vector<char*>* vp) const
{
if(!vp)
return;
for(auto p: *vp)
free(p);
delete vp;
}
};
// self deleting pointer (using the above deleter) to store the vector of char*
std::unique_ptr<std::vector<char*>, malloc_vector_deleter> cmds(new std::vector<char*>());
// fill the vector full of malloc'd data
cmds->push_back(strdup("arg0"));
cmds->push_back(strdup("arg1"));
cmds->push_back(strdup("arg2"));
// did any of the allocations fail?
if(std::find(cmds->begin(), cmds->end(), nullptr) != cmds->end())
{
// report error and return
}
cmds->push_back(nullptr); // needs to be null terminated
execvp("progname", cmds->data());
// all memory deallocated when cmds goes out of scope
which (unless I am mistaken) means I need a C-style char* array (a string array in C), and will not be able to use std::string from C++.
No you can still use string from C++. The string class has a constructor that takes C-string:
char str[] = "a string";
string cppStr(str);
Now you can manipulate your string using the string class in C++.

What is the right way to handle char* strings?

I have a third party library that is using char* (non-const) as placeholder for string values. What is the right and safe way to assign values to those datatypes? I have the following test benchmark that uses my own timer class to measure execution times:
#include "string.h"
#include <iostream>
#include <sj/timer_chrono.hpp>
using namespace std;
int main()
{
sj::timer_chrono sw;
int iterations = 1e7;
// first method gives compiler warning:
// conversion from string literal to 'char *' is deprecated [-Wdeprecated-writable-strings]
cout << "creating c-strings unsafe(?) way..." << endl;
sw.start();
for (int i = 0; i < iterations; ++i)
{
char* str = "teststring";
}
sw.stop();
cout << sw.elapsed_ns() / (double)iterations << " ns" << endl;
cout << "creating c-strings safe(?) way..." << endl;
sw.start();
for (int i = 0; i < iterations; ++i)
{
char* str = new char[strlen("teststr")];
strcpy(str, "teststring");
}
sw.stop();
cout << sw.elapsed_ns() / (double)iterations << " ns" << endl;
return 0;
}
Output:
creating c-strings unsafe(?) way...
1.9164 ns
creating c-strings safe(?) way...
31.7406 ns
While the "safe" way get's rid of the compiler warning it makes the code about 15-20 times slower according to this benchmark (1.9 nanoseconds per iteration vs 31.7 nanoseconds per iteration). What is the correct way and what are is so dangerous about that "deprecated" way?
The C++ standard is clear:
An ordinary string literal has type “array of n const char” (section 2.14.5.8 in C++11).
and
The effect of attempting to modify a string literal is undefined (section 2.14.5.12 in C++11).
For a string known at compile time, the safe way of obtaining a non-const char* is this
char literal[] = "teststring";
you can then safely
char* ptr = literal;
If at compile time you don't know the string but know its length you can use an array:
char str[STR_LENGTH + 1];
If you don't know the length then you will need to use dynamic allocation. Make sure you deallocate the memory when the strings are no longer needed.
This will work only if the API doesn't take ownership of the char* you pass.
If it tries to deallocate the strings internally then it should say so in the documentation and inform you on the proper way to allocate the strings. You will need to match your allocation method with the one used internally by the API.
The
char literal[] = "test";
will create a local, 5 character array with automatinc storage (meaning the variable will be destroyed when the execution leaves the scope in which the variable is declared) and initialize each character in the array with the characters 't', 'e', 's', 't' and '\0'.
You can later edit these characters: literal[2] = 'x';
If you write this:
char* str1 = "test";
char* str2 = "test";
then, depending on the compiler, str1 and str2 may be the same value (i.e., point to the same string).
("Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementation- defined." in Section 2.14.5.12 of the C++ standard)
It may also be true that they are stored in a read-only section of memory and therefore any attempt to modify the string will result in an exception/crash.
They are also, in reality of the type const char* so this line:
char* str = "test";
actually casts away the const-ness on the string, which is why the compiler will issue the warning.
The unsafe way is the way to go for all strings that are known at compile-time.
Your "safe" way leaks memory and is rather horrific.
Normally you'd have a sane C API which accepts const char *, so you could use a proper safe way in C++, i.e. std::string and its c_str() method.
If your C API assumes ownership of the string, your "safe way" has another flaw: you can't mix new[] and free(), passing memory allocated using the C++ new[] operator to a C API which expects to call free() on it is not allowed. If the C API doesn't want to call free() later on the string, it should be fine to use new[] on the C++ side.
Also, this is a strange mixture of C++ and C.
You seem to have a fundamental misunderstanding about C strings here.
cout << "creating c-strings unsafe(?) way..." << endl;
sw.start();
for (int i = 0; i < iterations; ++i)
{
char* str = "teststring";
}
Here, you're just assigning a pointer to a string literal constant. In C and C++, string literals are of type char[N], and you can assign a pointer to a string literal array because of array "decay". (However, it's deprecated to assign a non-const pointer to a string literal.)
But assigning a pointer to a string literal can't be what you want to do. Your API expects a non-const string. String literals are const.
What is the right and safe way to assign values to those [char* strings]?
There's no general answer to this question. Whenever you work with C strings (or pointers in general), you need to deal with the concept of ownership. C++ takes care of this for you automatically with std::string. Internally, std::string owns a pointer to a char* array, but it manages the memory for you so you don't need to care about it. But when you use raw C-strings, you DO need to put thought into managing the memory.
How you manage the memory depends on what you're doing with your program. If you allocate a C-string with new[], then you need to deallocate it with delete[]. If you allocate it with malloc, then you must deallocate it with free(). A good solution for working with C-strings in C++ is to use a smart pointer which takes ownership of the allocated C string. (But you'll need to use a deleter that deallocates the memory with delete[]). Or you can just use std::vector<char>. As always, don't forget to allocate room for the terminating null char.
Also, the reason your 2nd loop is so much slower is because it allocates memory in each iteration, whereas the 1st loop simply assigns a pointer to a statically-allocated string literal.

Quick new operator issue

I know this is really easy and I'm looking over something but this is what I have...:
typedef struct
{
char s1[81];
char s2[81];
char s3[81];
}Rec;
int main()
{
Rec *a[10];
a[0] = (Rec*)new unsigned char(sizeof(Rec));
a[0]->s1= "hello";
printf("a[0] = %s\n",a[0]->s1);
delete(a[0]);
getchar();
return 0;
}
Now, the line
a[0]->s1= "hello";
is complaining about the expression must be a modifiable lvalue. I am pretty sure it's how I'm casting it in my new operator line and has it needs to be a long value or something but I'm not sure of the code to do this... easy i know but yeah. Any help would be much appreciated
You cannot assign to char arrays like that. Either use strcpy, or change your char arrays to std::string.
strcpy(a[0]->s1, "hello");
Why are you doing this:
a[0] = (Rec*)new unsigned char(sizeof(Rec));
instead of this:
a[0] = new Rec;
Two things. The line
a[0] = (Rec*)new unsigned char(sizeof(Rec));
allocates a single unsigned char that gets initialized to the value sizeof(Rec). You probably meant
a[0] = (Rec*)new unsigned char[sizeof(Rec)];
or better yet
a[0] = new Rec;
Second, you cannot assign a string literal to an array of chars, you need to copy the characters one by one, e.g.
char s[80];
s = "hello"; // won't work
strcpy(s, "hello"); // correct
You should however use std::string in this case.
I guess that you've done a lot of C in your life. Keep in mind that C++ is different language, which happen to share with C most of its syntax and some of its standard library. That means something that is perfectly fine in C might be quite ugly (or even dangerous) in C++.
With that said, let's rewrite your code in a more "C++-ish" way:
#include <iostream> // std::cout, std::endl
#include <string> // std::string
struct Rec // typedef is implicit for structs in C++
{
std::string s1; // use std::string instead of char arrays
std::string s2;
std::string s3;
}; // don't forget the semicolon!
int main()
{
Rec * a[10];
a[0] = new Rec; // allocates the right amount of memory, no need to cast
a[0]->s1 = "hello"; // std::sring handles the assignment for you
std::cout << "a[0] = " << a[0]->s1 << std::endl; // use iostreams
delete a[0]; // delete is an operator, not a function, no need for parentheses
getchar(); // warning, this is not portable
return 0;
}
As you see, new is not an "improved malloc". It's typesafe (no cast needed), it's safer to use (it allocates the exact amount of memory required, no need for sizeof), and it also does something that malloc cannot do: it invokes the class' constructor (just as delete invokes a destructor).
In C++, as in C, allocation is distinct from initialization. While in C you could just memset the block to zero, in C++ object construction can be a bit more complex. As such, you should never use malloc to create objects of classes that have non-trivial constructors (or have fields that don't have non trivial constructors - Rec is such a case). Because new always works, and has additional features, you should use it anyway.
The problem is not with your casting. Your new expression allocates a single unsigned char and initializes it to the sizeof(Rec) instead of allocating enough space as new unsigned char[sizeof(Rec)]; would do. That said, the types of s1 and "hello" are different and you can't assign one with the other. You should be using something like strcpy, but since you tagged this C++ then you would be better off using std::string. Also, why don't you just call new Rec;?
a[0] is a pointer to an array of chars that can't be modified -- a[0] will always point to the same address.
you need to use strcpy to copy from your "hello" string to a[0]