I'm using a C routine to write to an std::string's datafield. This is a contrived example, in reality I'm getting a non-null terminated string and its size via network:
#include <string>
#include <cstdio>
#include <cstring>
const char* str = "Some examplory string..";
int main()
{
std::string some_str;
some_str.resize(strlen(str));
std::strcpy(&some_str.front(), str);
printf(some_str.c_str());
}
Now according to cppref there's no overload for resize() which just resizes and does not initialize memory with '\0' or something else. But why should I pay for that if all I'm doing is overwriting it again? Can this somehow be avoided?
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.
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[])
{
int i=0;
string s1 = "";
s1[i++]='F';
s1[i++]='U';
s1[i++]='A';
s1[i++]='A';
s1[i++]='D';
cout << s1;
return 0;
}
You're trying to modify elements in an empty string.
If you want your code to work there are several ways to do this:
add elements to s1, you can use s1 += 'A' or s1.push_back('A') instead.
Allocate enough space to modify each element by doing s1.resize(5) after string s1 = "";.
And possibly more, but that should get you started. Think of std::string as an array of characters. If your array is empty, you either have to resize it or add things to it.
Note: Don't use #include <bits/stdc++.h> just do #include <string>.
Note: Avoid using using namespace std;
s1 is empty, any indexing into it will be out of bounds and lead to undefined behavior. Do e.g. s1 += 'F' instead. – Some programmer dude
I am using th following code but it only asks me for a input and closes without couting my input
#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main(){
int balance=0;
int withdraw=0;
char* str;
cin.getline(str,10);
cout<<str;
withdraw=atoi(strtok(str," "));
balance=atoi(strtok(NULL," "));
cout<<withdraw<<" "<<balance;
return 0;
}
char* str;
This only gives you a pointer. That pointer doesn't point anywhere, especially not at some chars that you can write to. When you call cin.getline(str,10), it tries to write to where this pointer is pointing to. That gives you undefined behaviour. An easy fix for this is to make str an array of 10 chars:
char str[10];
However, I recommend that you start using std::string instead and figure out how to do strtok-like operations with a std::string. Hint: look at std::istringstream.
You need to allocate memory for str.
char *str = new char[10];
otherwise using uninitialized pointer will invoke undefined behavior. And call delete to free the allocated memory once you done with str.
delete[] str;
Instead of using char *, it is better to use std::string.
Compiler tell me "incompatibles type in assignments of char* to char[32]"
this is my code:
char* generalOperations[2]={"Off","On"};
void test(){
char value[32];
switch(swapVariable){
case 0:
value=generalOperations[0]; //<==Error HERE!
break;
}
}
[Solved]:
strcpy(value,generalOperations[0]);
Use std::string instead of char* and std::array<T, N> instead of T[N]. Both are type safe (as opposed to memcpy), both are in modern C++ style and both are directly assignable using the assignment operator.
#include <array>
#include <string>
std::array<std::string, 2> generalOperations{"Off", "On"};
void test() {
std::string value;
switch(swapVariable) {
case 0: value = generalOperations[0]; break;
}
}
You can't assign arrays. You can either change the type of value to a char* or copy the content of generalOptions[0] into value. If you are going to copy the content, then you need to ensure that value has enough space to hold the content of the element in generalOperations.
Modifying a string literal is undefined behaviour, by changing the type to const char* the compiler can detect any attempt to modify one of the entries in generalOperations instead of experiencing odd behaviour at runtime:
const char* generalOperations [2]={"Off","On"};
const char* value;
Note you don't have to specify the number of elements in the array if you are initialising it:
const char* generalOperations [] = {"Off","On"};
Or, if this really is C++ you can make value a std::string instead and just assign to it which will copy the generalOperations element.
As C++ appears to really be the language and C++11 features are permitted instead of using a switch you could create a std::map that associates the int values with the std::string:
#include <iostream>
#include <string>
#include <map>
const std::map<int, std::string> generalOperations{ {17, "Off"},
{29, "On" } };
int main()
{
auto e = generalOperations.find(17);
if (e != generalOperations.end())
{
// Do something with e->second.
std::cout << e->second << "\n";
}
return 0;
}
Demo: http://ideone.com/rvFxH.
#include <string.h>
...
strcpy(value, generalOptions[0]);
You cannot assign arrays in C/C++. There are functions do to that for you. If your char array represents a C style string (i.e. a null terminated sequence of characters), then there are more specialist functions for that as well. strcpy is one of those functions.
Your assignment is wrong, since you cannot assign a char * to char array instead of using this assignment you can use strcpy().
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;
}