Is there an easy way to copy a vector char to a position in a 2d vector string while leaving the 2d vector as a member variable?
For example:
I want to copy the buffer into data[0][0]
class foo
{
private:
vector<vector<string>> data;
};
in source somewhere
vector<char> buffer = {copyMe}
#include <algorithm> // std::copy
#include <iterator> // std::back_inserter
std::copy(buffer.begin(), buffer.end(), std::back_inserter(data[0][0]));
This appends the contents of buffer to the string at data[0][0].
Basically we can just copy vector into another using memcpy if these vectors are of same type
std::vector<char> vc;
//...
std::vector<char> vs;
vs.resize( vc.size());
memcpy( &vs[0], &vc[0], vs.size());
or
std::copy( vc.begin(), vc.end(), vs.begin());
but here because of different types char and std::string casting won't work. We can do a copy in loop, element by element, this way:
std::vector<char> vc;
//...
std::vector<std::string> vs;
for ( size_t i = 0; i < vc.size(); i++) {
vs.push_back( std::string(&vc[i], &vc[i+1]));
}
Related
I need to call the getList function below which comes from a library I cannot change.
#include <iostream>
#include <vector>
#include <string>
//function already exists in a separate library, can't be changed
void getList(const char* list[], int count){};
int main()
{
std::vector<std::string> vectorOfStrings = {"123" , "abc", "def", "456"};
//call getList and pass vectorOfStrings and vectorOfStrings.size()
getList(/*convert std::vector<std::string> to const char** */, vectorOfStrings.size());
return 0;
}
I already asked a similar question here and got an answer but I thought there might be a C++ way of doing this.
Use a std::vector<const char*> to store the pointers of the string data stored in the original std::vector<std::string>.
This is a fast operation because you're copying the original data but mind that: this requires that the const char* passed to the function are not stored anywhere because they'll become INVALID once the original string is deallocated (you'll get undefined behavior).
std::vector<std::string> strings = { "foo", "bar", "baz" };
std::vector<const char*> cstrings;
cstrings.reserve(strings.size());
std::transform(
strings.begin(),
strings.end(),
std::back_inserter(cstrings),
[] (const auto& string) { return string.c_str();}
);
getList(cstrings.data(), cstrings.size());
Given that the vector elements are not a C type, you'll need to construct an array to pass to the function:
const char **a = new const char *[vectorOfStrings.size()];
for (int i=0;i<vectorOfStrings.size();i++) {
a[i] = vectorOfStrings[i].c_str();
}
getList(a, vectorOfStrings.size());
delete[] a;
Or, in a more C++ way:
std::vector<const char *> v2;
for (int i=0;i<vectorOfStrings.size();i++) {
v2.push_back(vectorOfStrings[i].c_str());
}
getList(v2.data(), vectorOfStrings.size());
How to insert elements in it ?
vector <int> arr[10];
then how to insert more elements in the vector at position arr[i] when required?
#include <iostream>
using namespace std;
int main()
{
vector<int> v[3]; // here statically i have mentioned size,
// create 3 contiguous vectors of type int
//remember that it's is 2d kind
v[0].push_back(2);
v[0].push_back(3);
v[1].push_back(3);
// This is how you can add more elements than the
// specified size-dynamically can change the size
// This is the advantage of vector as we can
// dynamically add more elements
cout<<v[0].front(); //2
cout<<v[0].back(); //3
cout<<v[1].at(0) ; //3
//it's structure is something like this{{2,3},{3},{\0}}
return 0;
}
In C++ we can create a vector from another vector via
std::vector<unsigned char> tmp_1 { &some_vector[i] , &some_vector[j] };
Question : Is there any way to do the same for std::string?
Something like:
std::string tmp2 { &some_vector[i] , &some_vector[j] };
Attempts to use constructor from documentation always return error;
Note:
*some_vector is the vector of unsigned chars
UPD: Found answer: had typo so tried to access [-1] element.
std::string has several constructors, some of which can be used to construct the string from a std::vector, eg:
// using a char* pointer and a size...
std::string tmp2( reinterpret_cast<char*>(&some_vector[i]), j-i );
// using char* pointers as iterators...
std::string tmp2( &some_vector[i], &some_vector[j] );
// using vector iterators...
std::string tmp2( some_vector.begin()+i, some_vector.begin()+j );
Live Demo
This:
std::string tmp2 { &some_vector[i] , &some_vector[j] };
should work for std::vector but I would prefer more readable and safer solution:
std::string tmp2 { std::next( some_container, i ) , std::next( some_container.begin(), j ) };
which should work on any container with type, that can be convertible to char. For example if you or somebody else later would decide to replace std::vector<char> to std::deque<char> for whatever reason, your program will suddenly and what is more dangerous quietly start to be unpredictable with &container[i].
Newbie in cpp, cannot understand what's going wrong:
void addElem(vector<someCustomByteType> *result, string str_to_add) {
someCustomByteType *elem = (someCustomByteType*)str_to_add.data();
int elem_size = str_to_add.size();
memcpy(&(*result).back(), elem, elem_size);
}
int main(int argc, _TCHAR* argv[])
{
vector<someCustomByteType> vec(5);
vector<someCustomByteType> *vec_ptr = &vec;
addElem(signed_string_ptr, "abcd");
return 0;
}
outside, in main:
vector not changed outside. But memcpy works. What's going on?
Thank you!
The function does not make sense.
For starters it is unclear why you are using a pointer to the vector instead of a reference to the vector.
Nevertheles, this declaration
vector<unsigned char> vec(5);
does not reseeve a memory for the vector. It initializes the vector with 5 zero-characters which will be appended with other characters in the function.
The expression
&(*result).back()
returns reference to the last element of the vector. And this call
memcpy(&(*result).back(), elem, elem_size);
will try to overwrite memory that does not belong to the vector. As result the function has undefined behaviour.
Youy can imagine the situation the following way
vector
|0|0|0|0|0|
|a|b|c|d|
string
so as it is seen there is an attempt to copy characters 'b', 'c', and 'd' to the memory that does not belong to the vector.
You should use methods of the class template std::vector to append new elements.
The function can look the following way as it is shown in the demonstrative program (provided that you want to use a pointer to vector).
#include <iostream>
#include <vector>
#include <string>
void addElem( std::vector<unsigned char> *result, const std::string &str_to_add )
{
result->reserve( result->size() + str_to_add.size() );
result->insert( result->end(), str_to_add.begin(), str_to_add.end() );
}
int main()
{
std::vector<unsigned char> vec;
std::vector<unsigned char> *vec_ptr = &vec;
addElem( vec_ptr, "abcd" );
for ( auto c : *vec_ptr ) std::cout << c;
std::cout << std::endl;
return 0;
}
Its output is
abcd
What you are doing is undefined behavior. Neither std::vector or std::string are trivially copyable which is a requirement of std::memcpy. If you want to copy a std::string into a std::vector you can just do something like
void addString(vector<unsigned char>& vec, const std::string& str)
{
vec.assign(str.begin(), str.end());
}
Is there a way to pass 'std::vector 2d' as a pointer to '2d c array' to a function.
I know you can pass std::vector 1d as a pointer to c array to some function.
for example,
function:
void foo(char* str); //requires the size of str to be 100 chars
std::vector<char> str_;
str_.resize(100);
foo(&str_[0]); //works
I'm wondering if it is possible for 2d vectors too like for
function
void foo(char** arr_2d);
and vector
std::vector<std::vector<char>> vector_2d;
I tried the following code but im getting some error related to heap corruption.
std::vector<std::vector<unsigned char>> vector_2d;
//assuming function expects the size of the vector to be 10x10
vector_2d.resize(10);
for(int i=0;i<10;i++)
{
vector_2d[i].resize(10);
}
foo(&vector_2d[0]);//error here
Here's what you can do:
std::vector< std::vector<unsigned char> > vector_2d;
vector_2d.resize(10);
std::vector<unsigned char*> ptrs(vector_2d.size());
for(int i=0;i<10;i++)
{
vector_2d[i].resize(10);
ptrs[i] = &vector_2d[i][0];
}
foo(&ptrs[0]);
No, you cannot do that. The reason is that char** is a pointer to a pointer to char, but &vector_2d[0] is of type std::vector<char>*.
I would recommend that you change the interface of the function to take your bidimensional vector (which you might want to redesign to be a class holding a single std::vector<char> and providing operator()(int x,int y) to access element (x,y) in the buffer. Alternatively, you can create the needed data structure on demand:
std::vector<std::vector<char> > data2d;
std::vector<char *> iface_adapter;
iface_adapter.reserve(data2d.size());
for ( unsigned int i = 0; i < data2d.size(); ++i ) {
iface_adapter.push_back( &data2d[i][0] );
}
foo( &iface_adapter[0] );