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.
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 facing an issue with string and null characters in C++.
When I am writing '\0' in between the string and printing the string then I am getting only part before '\0' but on the other hand when I am taking string as input then changing any index as '\0' then it is printing differently. Why is it so and why the sizeof(string) is 32 in both the cases
Code is below for reference. Please help.
First code:
#include<iostream>
using namespace std;
int main(){
string s = "he\0llo";
cout<<s.length()<<"\n";
cout<<s<<endl;
cout<<sizeof(s)<<"\n";
}
output of First code:
2\n
he\n
32\n
Second code
#include<iostream>
using namespace std;
int main(){
string s;
cin>>s;
s[1] = '\0';
cout<<s<<"\n";
cout<<s.length()<<"\n";
cout<<sizeof(s)<<"\n";
return 0;
}
output of second code:
hllo\n
5\n
32\n
Below is the image for your reference.
std::string's implicit const CharT* constructors and assignment operator don't know the exact length of the string argument. Instead, it only knows that this is a const char* and is forced to assume that the string will be null-terminated, and thus computes the length using std::char_traits::length(...) (effectively std::strlen).
As a result, constructing a std::string object with an expression like:
std::string s = "he\0llo";
will compute 2 as the length of the string, since it assumes the first \0 character is the null terminator for the string, whereas your second example of:
s[1] = '\0';
is simply adding a null character into an already constructed string -- which does not change the size of the string.
If you want to construct a string with a null character in the middle, you can't let it compute the length of the string for you. Instead, you will have to construct the std::string and give it the length in some other way. This could either by done with the string(const char*, size_t) constructor, or with an iterator pair if this is an array:
// Specify the length manually
std::string s{"he\0llo",6};
Live Example
// Using iterators to a different container (such as an array)
const char c_str[] = "he\0llo";
std::string s{std::begin(c_str), std::end(c_str)};
Live Example
Note: sizeof(s) is telling you the size of std::string class itself in bytes for your implementation of the standard library. This does not tell you the length of the contained string -- which can be determined from either s.length() or s.size().
As of c++14, there is an option to specify quoted strings as a std::string by using std::literals. This prevents conversion of an array of chars to string which automatically stops at the first nul character.
#include<iostream>
#include <string>
using namespace std;
using namespace std::literals;
int main() {
string s = "he\0llo"s; // This initializes s to the full 6 char sequence.
cout << s.length() << "\n";
cout << s << endl;
cout << sizeof(s) << "\n"; // prints size of the s object, not the size of its contents
}
Results:
6
hello
28
I am having problems with std::string..
Problem is that '\0' is being recognized as end of the string as in C-like strings.
For example following code:
#include <iostream>
#include <string>
int main ()
{
std::string s ("String!\0 This is a string too!");
std::cout << s.length(); // same result as with s.size()
std::cout << std::endl << s;
return 0;
}
outputs this:
7
String!
What is the problem here? Shouldn't std::string treat '\0' just as any other character?
Think about it: if you are given const char*, how will you detemine, where is a true terminating 0, and where is embedded one?
You need to either explicitely pass a size of string, or construct string from two iterators (pointers?)
#include <string>
#include <iostream>
int main()
{
auto& str = "String!\0 This is a string too!";
std::string s(std::begin(str), std::end(str));
std::cout << s.size() << '\n' << s << '\n';
}
Example: http://coliru.stacked-crooked.com/a/d42211b7199d458d
Edit: #Rakete1111 reminded me about string literals:
using namespace std::literals::string_literals;
auto str = "String!\0 This is a string too!"s;
Your std::string really has only 7 characters and a terminating '\0', because that's how you construct it. Look at the list of std::basic_string constructors: There is no array version which would be able to remember the size of the string literal. The one at work here is this one:
basic_string( const CharT* s,
const Allocator& alloc = Allocator() );
The "String!\0 This is a string too!" char const[] array is converted to a pointer to the first char element. That pointer is passed to the constructor and is all information it has. In order to determine the size of the string, the constructor has to increment the pointer until it finds the first '\0'. And that happens to be one inside of the array.
If you happen to work with a lot zero bytes in your strings, then chances are that std::vector<char> or even std::vector<unsigned char> would be a more natural solution to your problem.
You are constructing your std::string from a string literal. String literals are automatically terminated with a '\0'. A string literal "f\0o" is thus encoded as the following array of characters:
{'f', '\0', 'o', '\0'}
The string constructor taking a char const* will be called, and will be implemented something like this:
string(char const* s) {
auto e = s;
while (*e != '\0') ++e;
m_length = e - s;
m_data = new char[m_length + 1];
memcpy(m_data, s, m_length + 1);
}
Obviously this isn't a technically correct implementation, but you get the idea. The '\0' you manually inserted will be interpreted as the end of the string literal.
If you want to ignore the extra '\0', you can use a std::string literal:
#include <iostream>
#include <string>
int main ()
{
using namespace std::string_literals;
std::string s("String!\0 This is a string too!"s);
std::cout << s.length(); // same result as with s.size()
std::cout << std::endl << s;
return 0;
}
Output:
30
String! This is a string too!
\0 is known as a terminating character so you'll need to skip it somehow.
Take that as an example.
So whenever you want to skip special characters you would like to use two backslashes "\\0"
And '\\0' is a two-character literal
std::string test = "Test\\0 Test"
Results :
Test\0 Test
Most beginners also make mistake when loading eg. files :
std::ifstream some_file("\new_dir\test.txt"); //Wrong
//You should be using it like this :
std::ifstream some_file("\\new_dir\\test.txt"); //Correct
In very few words, you're constructing your C++ string from a standard C string.
And standard C strings are zero-terminated. So, your C string parameter will be terminated in the first \0 character it can find. And that character is the one you explicitly provided in your string "String!\0 This is a string too!"
And not in the 2nd one that is implictly and automatically provided by the compiler in the end of your C standard string.
Escape your \0
std::string s ("String!\\0 This is a string too!");
and you will get what you need:
31
String!\0 This is a string too!
That's not a problem, that's the intended behavior.
Maybe you could elaborate why you have a \0 in your string.
Using a std::vector would allow you to use \0 in your string.
For some reason, I was trying to covert a C++ string to a char array. Below is what I did:
string aS="hello world";
char aC[aS.size()];
strcpy(aC, aS.c_str());
cout << aC[0] << endl;
string bS="veooci m eode owtwolwwwwtwwj mooawee mdeeme eeeec eme aemmeledmll llllleolclclcmslococecewaccocmelaeaccoaaooojutmjooooocoemoooealm omjcdmcmkemmdemmmiwecmcmteeeote eoeeeem ecc e yolc e w dtoooojttttmtwtt ttjcttoowl otdooco ko mooooo aowmemm o et jmc cmlctmmcccjcccecomatocooccoeoclooomoecwooo mcdoo dcdco dddooedoemod eddeedoedje emadleweemeeedeeeec or o m wejeetoj o ojjjlwdjjjj mjmceaeoaai laaadoaa aetmotaemmj mmmmmmlmm cmol c mwoaoe omav";
char bC[bS.size()];
strcpy(bC, bS.c_str());
cout << aC[0] << endl;
When aC[0] was first called, it gave 'h' as expected. However, when aC[0] is called at the second time, it gave ''. Could someone explain me what happened here?
For some reason, I was trying to covert a C++ string to a char array
Why don't you just use .c_str(), it does this for you
string aS="hello world";
cout << aS.c_str();
char aC[aS.size()];
would need to be:
char aC[aS.size() + 1];
in order to allow for the terminating '\0' required for a C string.
If you don't want to use the std::string::c_str() member function, you should then allocate the char array dynamically, as you cannot declare variable length arrays in C++, such as:
char* bC = new char[aS.size() + 1]; // don't forget to delete[]
strcpy(bC, bS.c_str());
I can see some utility of changing to an array if you're calling a function that will change the string buffer (pre C++11). Otherwise, use the other solutions such as c_str() if the buffer is not going to be changed.
However, if you really wanted a char array due to the buffer possibly being changed, use std::vector<char>. This will bypass the issue of using non-standard syntax (aC[aS.size()]), and removes the need to dynamically allocate memory. A std::vector<char> effectively is a changeable string buffer, only wrapped.
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
string aS="hello world";
std::vector<char> aC(aS.begin(), aS.end()); // copy
aC.push_back(0); // null-terminate
cout << &aC[0] << endl;
}
Output:
hello world
Now, where you need to specify a character array pointer, you just pass the address of the first element in the vector (provided that the vector is not empty).
Live Example: http://ideone.com/tF32Zt
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);