I have a char pointer:
char* s = new char[150];
Now how do i fill it? This:
s="abcdef";
Gives warning about deprecation of conversion between string literal and char*, but generally works.
This:
char* s = new[150]("abcdef");
Does not work, gives an error.
How to do this properly? Note that I want the memory allocation to have 150*sizeof(char) bytes and contain "abcdef". I know about malloc, but is it possible to do with new?
Its for an assignment where i cant use the standard library.
This sequence of statements
char* s = new char[150];
s="abcdef";
results in a memory leak because at first a memory was allocated and its address was assigned to the pointer s and then the pointer was reassigned with the address of the string literal "abcdef". And moreover string literals in C++ (opposite to C) have types of constant character arrays.
If you allocated a memory for a string then you should copy a string in the memory either by using the C standard function strcpy or C standard function strncpy.
For example
char* s = new char[150];
std::strcpy( s, "abcdef" );
Or
const size_t N = 150;
char* s = new char[N];
std::strncpy( s, "abcdef", N );
s[N-1] = '\0';
Or even the following way
#include <iostream>
#include <cstring>
int main()
{
const size_t N = 150;
char *s = new char[N]{ '\0' };
std::strncpy( s, "abcdef", N - 1 );
std::cout << s << '\n';
delete []s;
}
In any case it is better just to use the standard class std::string.
std::string s( "abcdef" );
or for example
std::string s;
s.assign( "abcdef" );
The basic procedure for creating a memory area for a string and then filling it without using the Standard Library in C++ is as follows:
create the appropriate sized memory area with new
use a loop to copy characters from a string into the new area
So the source code would look like:
// function to copy a zero terminated char string to a new char string.
// loop requires a zero terminated char string as the source.
char *strcpyX (char *dest, const char *source)
{
char *destSave = dest; // save copy of the destination address to return
while (*dest++ = *source++); // copy characters up to and including zero terminator.
return destSave; // return destination pointer per standard library strcpy()
}
// somewhere in your code
char *s1 = new char [150];
strcpyX (s1, "abcdef");
Given a character array:
char * s = new char [256];
Here's how to fill the pointer:
std::fill(&s, &s + sizeof(s), 0);
Here's how to fill the array:
std::fill(s, s+256, '\0');
Here's how to assign or copy text into the array:
std::strcpy(s, "Hello");
You could also use std::copy:
static const char text[] = "World";
std::copy(text, text + sizeof(text), s);
Remember that a pointer, array and C-Style string are different concepts and objects.
Edit 1: Prefer std::string
In C++, prefer to use std::string for text rather than character arrays.
std::string s;
s = "abcdef";
std::cout << s << "\n";
Once you've allocated the memory for this string, you could use strcpy to populate it:
strcpy(s, "abcdef");
Related
I'm very new to C++ (coming from C#) and it's giving me puzzles :S
I have a very basic question about arrays and it's pointers.
So if I have the following code:
char * test1 = "com";
char * test2 = "ment";
I found similar code in some files already. I don't exactly understand how a string can fit in one character.. but ok...
However, how could I connect these arrays so that I get "comment" ?
I'm pretty sure this char * result = test1 + test2; would only increase the pointer which would then point to something in the memory, which I dont intend to use.
So is it possible to get an array like char array[] = {'c', 'o', 'm', 'm', 'e', 'n', 't'}; back from this?
or can I at least get a pointer which points to something like comment\NUL in the memory?
As you pointed out, pointer arithmetic can't solve this.
If you want to have a C-string as the result, allocating space for the whole new string is required, then copying over the characters, typically using strcat / strncat, but they are C-style string operations.
// Your C-strings
const char *test1 = "com";
const char *test2 = "ment";
// Dynamic allocation of memory for result string
char *result = new char[strlen(test1) + strlen(test2) + 1];
// Start with the empty string
*result = '\0';
// Concatenate both input strings (use strncat if you don't know
// for sure that they will fit into the result array!)
strcat(result, test1);
strcat(result, test2);
// (use result pointer)
// Free the memory after last usage
delete[] result;
In C++, you typically try to avoid them and use std::string instead. Even if you want a C-string as the result, you can use a temporary std::string for allocation and management of the required memory as well as for performing the concatenation:
// Your C-strings
const char *test1 = "com";
const char *test2 = "ment";
// Wrap in temporary C++ strings and concatenate:
std::string result = std::string(test1) + std::string(test2);
// Get the pointer (only valid as long as result is in scope!)
const char *ptr = result.c_str();
Furthermore, please note that you should not assign a string literal to a non-const char * pointer, use a const char* pointer instead. And try to avoid dealing with raw C-strings as long as possible; of course when you use C libraries you have to use them a lot.
Note also that above mentioned methods are performed at runtime; you can't get a compile-time solution for concatenating two string literals, even though the compiler could know what you want to have. I don't know your context, but maybe you only want to have a multi-line string literal, then simply drop the + and write "com" "ment".
A c style solution can be found in the following link:
http://www.cplusplus.com/forum/beginner/5681/:
int len = strlen(test1)+strlen(test2);
char* result = new char[len +1]; // +1 for null terminated string
snprintf(result,len +1, "%s%s",test1,test2);
result[len] = NULL;
// use result
delete(result);
You can utilize std::string:
#include <iostream>
int main() {
// Note: the character literals are const (non const is deprecated)!
const char * test1 = "com";
const char * test2 = "ment";
// This gives a compiler error (there is no way to add pointers)
// const char * concat = test1 + test2;
// A std::string has an overload for the operator +:
std::string comment = std::string(test1) + test2;
// The dynamically allocated string.
// Note: as soon as the comment string gets altered or destroyed the
// pointer s to the internal string data (may) become invalid.
const char* s = comment.c_str();
std::cout << s << '\n';
}
So in attempting to learn how to use C-Strings in C++, I'm running into issues with memory allocation.
The idea here is that a new string is created of the format (s1 + sep + s2)
The text I'm using provided the header, so I can't change that, but I'm running into issues trying to set the size of char str[]. I am getting an error saying that sLength is not constant, and therefore cannot be used to set the size of an array. I'm relatively new to C++ so this is a two part question.
Is this strategy actually allocating memory for the new array?
How do I set the array size correctly if I can't get a constant value using strlen(char*)?
char* concatStrings(char* s1, char* s2, char sep){
int sLength = strlen(s1) + strlen(s2) + 3;
//+1 for char sep +2 for \0 at end of string
char *str = new char[sLength];
strcpy (str, s1);
str [sLength(s1)] = sep;
strcat (str, s2);
return str;
}
Edits made, so now I'm getting no compiler errors but...
The call to the function is here:
char* str = concatStrings("Here is String one", "Here is String two" , c);
cout<< str;
My output becomes:
Here is String onec==================22221/21/21/21/2 /(etc.)/ Here is String two
Error is returning address of local array variable str. Its scope is within function concatStrings() where you declared, and can't be accessed once control returns from the function.
To access it outside, you need to dynamically allocate memory for the string from the heap using the new operator.
char* concatStrings(char* s1, char* s2, char sep){
int s1Length = strlen(s1);
int sLength = s1Length + strlen(s2) + 2;
// +1 for sep and +1 \0 at end of string
char* str = new char[sLength];
strcpy (str, s1);
// Use strlen here instead of sizeof()
str [s1Length] = sep;
str [s1Length + 1] = '\0';
strcat (str, s2);
return str;
}
And after the program is done using the string returned from concatStrings it should ensure to free up the memory by invoking delete
char* str = concatStrings(s1, s2, sep);
// Do something
// Free up memory used by str
delete[] str;
Must use delete[] here instead of delete, or it results in undefined behaviour
I've also edited the concatStrings() function to use strlen instead of sizeof
UPDATE: Thanks for pointing out that we only need to do +2 and not +3 and for making sure a '\0' needs to be appended after str1 and sep before invoking strcat
You can allocate the resulting string memory dynamically (at run-time, on the heap), using new[] in C++ (or malloc for a more C-like style):
char* concatStrings(const char* s1, const char* s2, char sep) // enforced const correctness
{
const size_t totalLength = strlen(s1) + strlen(s2)
+ 2; // +1 for sep char, +1 for '\0'
// Dynamically allocate room for the new string (on the heap)
char* str = new char[totalLength];
strcpy(str, s1);
str[strlen(s1)] = sep; // note that you had a typo with sizeof(s1) here
strcat(str, s2);
return str;
}
Note that this memory must be released somewhere in your code, using delete[] if it was allocated with new[], or free() if it was allocated using malloc().
This is quite complicated.
You will simplify your code a lot if you use a robust C++ string class like std::string, with its convenient constructors to allocate memory, destructor to automatically free it, and operator+ and operator+= overloads to concatenate strings. See how your code is simplified using std::string:
#include <string> // for std::string
std::string str = s1;
str += sep;
str += s2;
(Note that using raw C strings can also make your code more vulnerable to safety problems, since you must pay lot of attention to proper sizing destination strings, avoid buffer overruns, etc. This is another reason to prefer a RAII robust string class like std::string.)
sizeof(s1) returns the size of a pointer variable, not the length of the array which it points to. Since you know that s1 points to a C-string, you should use the strlen() function instead.
I want to convert a std::string into a char* or char[] data type.
std::string str = "string";
char* chr = str;
Results in: “error: cannot convert ‘std::string’ to ‘char’ ...”.
What methods are there available to do this?
It won't automatically convert (thank god). You'll have to use the method c_str() to get the C string version.
std::string str = "string";
const char *cstr = str.c_str();
Note that it returns a const char *; you aren't allowed to change the C-style string returned by c_str(). If you want to process it you'll have to copy it first:
std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;
Or in modern C++:
std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
More details here, and here but you can use
string str = "some string" ;
char *cstr = &str[0];
As of C++11, you can also use the str.data() member function, which returns char *
string str = "some string" ;
char *cstr = str.data();
If I'd need a mutable raw copy of a c++'s string contents, then I'd do this:
std::string str = "string";
char* chr = strdup(str.c_str());
and later:
free(chr);
So why don't I fiddle with std::vector or new[] like anyone else? Because when I need a mutable C-style raw char* string, then because I want to call C code which changes the string and C code deallocates stuff with free() and allocates with malloc() (strdup uses malloc). So if I pass my raw string to some function X written in C it might have a constraint on it's argument that it has to allocated on the heap (for example if the function might want to call realloc on the parameter). But it is highly unlikely that it would expect an argument allocated with (some user-redefined) new[]!
(This answer applies to C++98 only.)
Please, don't use a raw char*.
std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
If you just want a C-style string representing the same content:
char const* ca = str.c_str();
If you want a C-style string with new contents, one way (given that you don't know the string size at compile-time) is dynamic allocation:
char* ca = new char[str.size()+1];
std::copy(str.begin(), str.end(), ca);
ca[str.size()] = '\0';
Don't forget to delete[] it later.
If you want a statically-allocated, limited-length array instead:
size_t const MAX = 80; // maximum number of chars
char ca[MAX] = {};
std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);
std::string doesn't implicitly convert to these types for the simple reason that needing to do this is usually a design smell. Make sure that you really need it.
If you definitely need a char*, the best way is probably:
vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
This would be better as a comment on bobobobo's answer, but I don't have the rep for that. It accomplishes the same thing but with better practices.
Although the other answers are useful, if you ever need to convert std::string to char* explicitly without const, const_cast is your friend.
std::string str = "string";
char* chr = const_cast<char*>(str.c_str());
Note that this will not give you a copy of the data; it will give you a pointer to the string. Thus, if you modify an element of chr, you'll modify str.
Assuming you just need a C-style string to pass as input:
std::string str = "string";
const char* chr = str.c_str();
To obtain a const char * from an std::string use the c_str() member function :
std::string str = "string";
const char* chr = str.c_str();
To obtain a non-const char * from an std::string you can use the data() member function which returns a non-const pointer since C++17 :
std::string str = "string";
char* chr = str.data();
For older versions of the language, you can use range construction to copy the string into a vector from which a non-const pointer can be obtained :
std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();
But beware that this won't let you modify the string contained in str, only the copy's data can be changed this way. Note that it's specially important in older versions of the language to use c_str() here because back then std::string wasn't guaranteed to be null terminated until c_str() was called.
To be strictly pedantic, you cannot "convert a std::string into a char* or char[] data type."
As the other answers have shown, you can copy the content of the std::string to a char array, or make a const char* to the content of the std::string so that you can access it in a "C style".
If you're trying to change the content of the std::string, the std::string type has all of the methods to do anything you could possibly need to do to it.
If you're trying to pass it to some function which takes a char*, there's std::string::c_str().
Here is one more robust version from Protocol Buffer
char* string_as_array(string* str)
{
return str->empty() ? NULL : &*str->begin();
}
// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
Conversion in OOP style
converter.hpp
class StringConverter {
public: static char * strToChar(std::string str);
};
converter.cpp
char * StringConverter::strToChar(std::string str)
{
return (char*)str.c_str();
}
usage
StringConverter::strToChar("converted string")
For completeness' sake, don't forget std::string::copy().
std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];
str.copy(chrs, MAX);
std::string::copy() doesn't NUL terminate. If you need to ensure a NUL terminator for use in C string functions:
std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];
memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
You can make it using iterator.
std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);
Good luck.
A safe version of orlp's char* answer using unique_ptr:
std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Alternatively , you can use vectors to get a writable char* as demonstrated below;
//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0');
char* cstring = &writable[0] //or &*writable.begin ()
//Goodluck
This will also work
std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;
No body ever mentioned sprintf?
std::string s;
char * c;
sprintf(c, "%s", s.c_str());
When I create something like
char* t = new char[44];
t = strcpy(s,t);
then strlen(t); return some wrong results. how I can change this?
Both strcpy and strlen expect to find the special character NUL or '\0' in the array. An uninitialized array, as the one you've created, may contain anything at all, which means the behavior of your program is undefined when it is passed to strcpy as the source argument.
Assuming the goal was to copy s into t, to make the program behave as expected, try this:
#include <iostream>
#include <cstring>
int main()
{
const char* s = "test string";
char* t = new char[44];
// std::strcpy(t, s); // t is the destination, s is the source!
std::strncpy(t, s, 44); // you know the size of the target, use it
std::cout << "length of the C-string in t is " << std::strlen(t) << '\n';
delete[] t;
}
But keep in mind that in C++, strings are handled as objects of type std::string.
#include <iostream>
#include <string>
int main()
{
const std::string s = "test string";
std::string t = s;
std::cout << "length of the string in t is " << t.size() << '\n';
}
What are you trying to do? Do you want to copy from s to t? If so, the arguments to strcpy are reversed.
char* t = new char[44]; // allocate a buffer
strcpy(t,s); // populate it
Such C-style string processing is a red flag, but that's all I can say given this little information.
This code might be helpful:
char * strcpy (char * destination, const char * source);
t = strcpy(t, s);
You have to initialize the variable t
Do something like this:
char *t = new char[44];
memset(t, 0, 44);
// strlen(t) = 0
The strcpy function is described thus:
#include <string.h>
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src (including the terminating '\0' character) to the array pointed to by dest.
So, if you are trying to fill in your newly allocated array, you should be doing:
strcpy(t, s);
Not the other way around.
If i pass a char * into a function. I want to then take that char * convert it to a std::string and once I get my result convert it back to char * from a std::string to show the result.
I don't know how to do this for conversion ( I am not talking const char * but just char *)
I am not sure how to manipulate the value of the pointer I send in.
so steps i need to do
take in a char *
convert it into a string.
take the result of that string and put it back in the form of a char *
return the result such that the value should be available outside the function and not get destroyed.
If possible can i see how it could be done via reference vs a pointer (whose address I pass in by value however I can still modify the value that pointer is pointing to. so even though the copy of the pointer address in the function gets destroyed i still see the changed value outside.
thanks!
Converting a char* to a std::string:
char* c = "Hello, world";
std::string s(c);
Converting a std::string to a char*:
std::string s = "Hello, world";
char* c = new char[s.length() + 1];
strcpy(c, s.c_str());
// and then later on, when you are done with the `char*`:
delete[] c;
I prefer to use a std::vector<char> instead of an actual char*; then you don't have to manage your own memory:
std::string s = "Hello, world";
std::vector<char> v(s.begin(), s.end());
v.push_back('\0'); // Make sure we are null-terminated
char* c = &v[0];
You need to watch how you handle the memory from the pointer you return, for example the code below will not work because the memory allocated in the std::string will be released when fn() exits.
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
return s.c_str(); //BAD
}
One solution is to allocate the memory in the function and make sure the caller of the function releases it:
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
char *ret = new char[s.size()]; //memory allocated
strcpy(ret, s.c_str());
return ret;
}
....
const char* p = fn("some text");
//do something with p
delete[] p;// release the array of chars
Alternatively, if you know an upper bound on the size of the string you can create it on the stack yourself and pass in a pointer, e.g.
void fn(const char*in size_t bufsize, char* out) {
std::string s(psz);
// do something with s
strcpy_s(out, bufsize, s.c_str()); //strcpy_s is a microsoft specific safe str copy
}
....
const int BUFSIZE = 100;
char str[BUFSIZE];
fn("some text", BUFSIZE, str);
//ok to use str (memory gets deleted when it goes out of scope)
You can maintain a garbage collector for your library implemented as
std::vector<char*> g_gc; which is accessible in your library 'lib'. Later, you can release all pointers in g_gc at your convenience by calling lib::release_garbage();
char* lib::func(char*pStr)
{
std::string str(pStr);
char *outStr = new char[str.size()+1];
strcpy(outStr, str.c_str());
g_gc.push_back(outStr); // collect garbage
return outStr;
}
release_garbage function will look like:
void lib::release_garbage()
{
for(int i=0;i<g_gc.size();i++)
{
delete g_gc[i];
}
g_gc.clear();
}
In a single threaded model, you can keep this g_gc static. Multi-threaded model would involve locking/unlocking it.