I am trying to copy 5 characters from a character array into a std::string
char name[] = "Sally Magee";
std::string first;
copy(name, name + 5, first.begin()); //from #include <algorithm>
std::cout << first.c_str();
However I get the string plus a whole bunch of unprintable characters that I do not want. Any ideas? Thanks.
Just do
char name[] = "Sally Magee";
std::string first(name, name + 5);
std::cout << first << std::endl;
see std::string constructor link
What the std::copy algorithm does is to copy one source element after the other, and advance the destination iterator after each element.
This assumes that
either the size of the destination container has been set large enough to fit all the elements you copy,
or you use an iterator type that increases the size of the destination container each time you make an assignment to it.
Therefore, if you want to use the std::copy algorithm, there are two ways of solving this:
Resize the string before making the copies:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
char source[] = "hello world";
std::string dest;
dest.resize(5);
std::copy(source,source+5,begin(dest));
std::cout << dest << std::endl;
return 0;
}
Using a back-insert iterator instead of the standard one:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
int main()
{
char source[] = "hello world";
std::string dest;
std::copy(source,source+5,std::back_inserter(dest));
std::cout << dest << std::endl;
return 0;
}
However, as pointed out by others, if the goal is simply to copy the first 5 characters into the string at initialization time, using the appropriate constructor is clearly the best option:
std::string dest(source,source+5);
Related
I need to use a function func(uint8_t* buffer, uint size); supposing I can't change its parameters, I want to pass it a string.
I have a vector<string> that I must convert to uint8_t* and then read it and convert it back to vector<string>.
I tried this code for reading (printing) the vector.data() output but it prints garbage:
#include <cstdint>
#include <string>
#include <vector>
#include <iostream>
int main() {
std::string a1 = {"ath"};
std::cout <<"1: "<< a1<<" end\n";
std::vector<std::string> vec;
vec.push_back(a1);
uint8_t *ptr = reinterpret_cast<uint8_t*>(vec.data());
std::cout <<"2: "<< ptr[0]<<" end\n";
}
output:
1: ath end
2: � end
questions:
why this doesn't work?
I saw in some links that they init a std::string with char* array like this:
char *ptr={'a'};
std::string myStr(ptr);
I suppose this works because of added '\0', is this related to my problem?
why this doesn't work?
This can't work, because a std::string is not just a contiguous piece of memory containing nothing but the characters in the string. You're simply mistaken about what std::string is!
Using a vector here is plain not the right approach. A vector does not contain your string's contents. Just the std::string objects themselves, which are not the string data.
Instead, you want to make one long std::string:
std::string foo {"foo"};
std::string bar {"bar "};
std::string baz {"bazaz"};
std::string complete = foo + bar + baz;
auto* whole_cstring = reinterpret_cast<uint8_t*>(complete.c_str());
// call your C-string-accepting function
func(whole_cstring, complete.length());
If you actually do have a std::vector of std::strings to begin with, the concatenation can be done in a simple loop:
std::vector<std::string> my_vector_of_strings;
// insert strings into the vector
/// … ///
std::string complete;
for(const auto& individual_string : my_vector_of_strings) {
complete += individual_string;
}
auto* whole_cstring = reinterpret_cast<uint8_t*>(complete.c_str());
// call your C-string-accepting function
func(whole_cstring, complete.length());
… missing \0 … I suppose this works because of added '\0', is this related to my problem?
No, that's completely unrelated.
I have a vector that I must convert to uint8_t*
std::vector<std::string> vec;
"Converting" has a relatively strong definition in the C++ (and other languages) world. If I understand what you mean, I'd suggest the following:
#include <string>
#include <vector>
#include <algorithm>
int main(){
std::vector<std::string> vec;
// populate
std::vector<uint8_t*> vec2(vec.size());
std::transform(begin(vec), end(vec), begin(vec2), [](auto& s){ return reinterpret_cast<unsigned char*>(s.data()); });
}
Alternatively, if possible, you can use a std::basic_string<uint8_t> instead of std::string (a/k/a std::basic_string<char>) to avoid reinterpreting its content.
I am building a fast copy application using xcopy. I want to pass two variable source and destination to system(); I am trying like this
char *source = "D:\\SOFTWARE\\Internet";
char *destination = " D:\\test /s /e /d /y";
system("xcopy "+source+destination);
But it doesnt work. It work fine in java. same code. Thanks.
Rewriting Mike's code to eliminate all the issues we tend to flag in code being reviewed!
#include <string>
#include <cstdlib>
using std::string;
int main()
{
const string str{ "dir" };
const string str2{ " /w" };
const string final_string = str + str2;
std::system(final_string.c_str());
}
Your problem in your original code is that operator+ doesn't work with C style strings, which are just char* or char[] and not objects. You are asking to add pointers together, which is not a sensible thing.
As Mike points out, turn your raw char array input into std::string objects as soon as you need to do stuff with it, and then + will work.
In this particular case, you only need to copy one of the character arrays into objects (see docs on operator+= form 3):
string s {"xcopy "};
s += source;
s += destination; // this works, as there is an optimized form of operator+ for this.
std::system(s.c_str()); // access a nul-terminated character array to make the system call.
One more way of string concatenation is use of std::ostringstream. Source and destination paths are quoted in the code bellow to be more safe:
#include <sstream>
int main() {
const char *source = "\"D:\\SOFTWARE\\Internet\"";
const char *destination = " \"D:\\test\" /s /e /d /y";
std::ostringstream cmd;
cmd << "xcopy " << source << destination;
system(cmd.str().c_str());
}
Compile and run
You need to use std::string (from string header). Also, you need to go from string to a const char pointer.
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdlib>
#include <string>
int main()
{
using namespace std;
string str{ "dir" };
string str2{ " /w" };
string final_string = str + str2;
char* cstr = new char[final_string.size() + 1];
strcpy(cstr, final_string.c_str());
system(cstr);
}
I'm trying to put a character on the stack, but it is putting the ASCII integer value of the character. What is causing this and how can I get an actual character onto the stack?
Here is some simple code to show what I mean:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> v;
std::string s = "ABCDEF";
char c = s[0];
v.push_back(std::to_string(c));
std::cout << v[0] << std::endl;
}
std::to_string doesn't have a conversion from char, but it does have a conversion from int. So c will implicitly be converted to an int with the corresponding ASCII value, and this is converted to a std::string.
If you want to push_back the character c as a std::string, you can do:
v.push_back({c});
Here's a demo.
I have executed the below code and it works perfectly. Since it is about pointers, I just want to be sure. Though I'm sure that assigning char* to string makes a copy and even if I delete char*, string var is gonna keep the value.
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
int main()
{
std::string testStr = "whats up ...";
int strlen = testStr.length();
char* newCharP = new char[strlen+1];
memset(newCharP,'\0',strlen+1);
memcpy(newCharP,testStr.c_str(),strlen);
std::cout << " :11111111 : " << newCharP << "\n";
std::string newStr = newCharP ;
std::cout << " 2222222 : " << newStr << "\n";
delete[] newCharP;
newCharP = NULL;
std::cout << " 3333333 : " << newStr << "\n";
}
I'm just changing some code in my company project and char* are passed between functions in C++. The char* pointer has been copied to the string, but the char* is deleted in the end of the function. I couldn't find any specific reason for this. So I'm just deleting the char*, as soon as it is copied into a string. Would this make any problem ...?
P.S : I have already asked this question in Codereview , but I got suggestion to move it to SO. So i have flagged it for close there and posting the question here.
No, because std::string copies the contents of your char*, so you're free to delete it when you no longer need it.
There is no problem, as long as newChar points to a null-terminated string, and is not null itself.
std::string has constructor that allows an implicit construction from a const char*. It makes a copy of the character string represented by the input const char * so it works under the assumption that the char* is a null terminated string, since there is no other way to know how many characters to copy into the string's own data storage. Furthermore, a NULL pointer is actually disallowed by the standard.
The code is fine, if you look at the constructors of std::basic_string here you'll be able to deduce that std::string has two interesting constructors here:
(4) string(char const*,
size_type count,
Allocator const& alloc = Allocator() );
(5) string(char const* s,
Allocator const& alloc = Allocator() );
Both perform a copy, and the first reads exactly count characters whilst the second reads up until it encounters a NUL-character.
That being said, I actively encourage you not to use dynamic allocation here. If you want a temporary buffer to play with, consider using std::vector instead.
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
int main()
{
std::string testStr = "whats up ...";
unsigned strlen = testStr.length();
std::vector<char> buffer(strlen+1);
memset(&buffer[0],'\0',strlen+1);
memcpy(&buffer[0], testStr.c_str(), strlen);
std::cout << " :11111111 : " << &buffer[0] << "\n";
std::string newStr(&buffer[0]);
std::cout << " 2222222 : " << newStr << "\n";
buffer.clear();
std::cout << " 3333333 : " << newStr << "\n";
}
Note: both vector and string have range-constructors, to build them from a range of iterators, that I purposefully refrained from using to avoid confusion and you being overwhelmed. Just know that you could have used them to avoid calling memcpy and risking a buffer overflow though.
Is there any way to write a cstring literal (or variable) directly into an existing std::array?
I.e., I want to do something like this:
std::array<unsigned char, 100> test;
// std::copy("testing", test);
// test="testing";
I expect the behavior to be "copy until either a null terminator is copied or the destination buffer is full."
I was trying to avoid doing a strlcpy(test.data()... because I was looking for a way that could cope with a buffer overrun without having to explicitly include the buffer length as a parameter.
Thanks.
edit:
Here're the best solutions I've found so far from suggestions. This one only works for literals. MSVC does not have uniform initialization, so it requires the = before then {. It also requires the buffer size, but fails compilation if the buffers sizes don't match or if there is an overrun:
#include <array>
#include <algorithm>
#include <iostream>
int main() {
std::array<char, 100> arr1={"testing"};
std::array<char, 100> arr2;
arr2=arr1;
std::cout << arr2.data();
}
This one works for strings in general, but be careful because the embedded null does not get copied and to have the null included you have to construct by array, ie string mystring("junk\0", 5).
#include <string>
#include <array>
#include <algorithm>
#include <iostream>
int main()
{
const std::string str("testing");
std::array<char, 100> arr;
std::copy(str.begin(), str.end(), arr.begin());
// Note that the null terminator does not get copied.
}
This should do it:
std::array<unsigned char, 100> test = { "testing" };
If you use a too-large string literal, the std::array construction will fail on compile time. This won't work for non-literals though.
For non-literals, you need to check for the null terminator yourself. You could do something like std::copy(my_non_literal, my_non_literal + length_literal, test.begin());, but I think you've already come across that one.
How about something like this?
#include <string>
#include <array>
#include <algorithm>
int main(int argc, char *argv[])
{
std::string str("testing");
std::array<char, 100> arr;
std::copy(str.begin(), std.end(), arr.begin());
}
Direct operation between C strings and C++ data structures is not a problem the Standard library typically deals with. c_str() and the std::string constructor are pretty much it. You will have to manually write a loop.
#include <iostream>
#include <array>
#include <cstring>
int main(){
std::array<char,100> buffer;
char * text = "Sample text.";
std::memcpy (buffer.data(),text,100);
std::cout << buffer.data() << std::endl;
return 0;
}