Changing vector in function by pointer - c++

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());
}

Related

How to pass a vector of strings to a function with a C-style pointer-to-C-string parameter

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());

C++ Create array with dynamic name

I need a create array in c++ but I need array always with variables name
int Magic(string name_array,int n)
{
string Name = "Something";
Name.append(name_array);
double * Name = new double[n];
}
int main()
{
Magic("a.txt",10);
}
And I have this error:
operator' : 'identifier1' differs in levels of indirection from 'identifier2'
I know it's not a python but maybe a map help me? How I can make this?
If you want to be able to access different arrays by string names, consider using a std::map<std::string, std::vector<double>>. This maps strings to C++'s better, more dynamic answer to arrays. In this case your code would be something like:
#include <iostream>
#include <map>
#include <vector>
void AddVector(std::map<std::string, std::vector<double>> &io_map,
const std::string& i_name,
const std::size_t i_size)
{
io_map[i_name].resize(i_size);
}
int main()
{
std::map<std::string, std::vector<double>> vector_map;
AddVector(vector_map, "Vector1", 3);
AddVector(vector_map, "Vector2", 10);
std::cout << "Vector with string key Vector1 has size: " << vector_map["Vector1"].size() << std::endl;
return 0;
}
In this code I've tried to be as close to the code you've given - resizing the vectors to the size you would have created the array in your "Magic" function. However, vectors can dynamically resize, so you may not even need to create/resize them in your code depending on your use case.

Copy vector <char> to 2d vector <string> c++

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]));
}

How to compare C++ string using qsort in c?

I tried to learn the qsort function of the c-library stdlib. This is provided even in c++. But i dont understand how to use them for sorting c++ strings. I am not sure of what the parameters should be for the sizeof() operator and whether my compare_str code is right. I tried this code:
#include<iostream>
#include<cstdlib>
using namespace std;
#include<string>
int compare_str( const void *a, const void *b){
string obj = (const char*)a;
string obj1 = (const char*)b;
return obj.compare(obj1);
}
int main(){
string obj[4] = {"fine", "ppoq", "tri", "get"};
qsort(obj, 4, sizeof(obj[0].length()), compare_str);
for( int i=0; i<4; i++)
cout<<obj[i]<<endl;
return 0;
}
My output was:
ppoq
tri
get
fine
I am not able to make out the error. Please help.
You cannot and must not use qsort on an array of std::strings. The elements must be of trivial type, which strings are not, and thus the behaviour is undefined. From 25.5/4 ("qsort"):
The behavior is undefined unless the objects in the array pointed to by base are of trivial type.
The reason is that qsort will memcpy the array elements around, which is not possible for C++ objects in general (unless they're sufficiently trivial).
If you do have a trivial type, you can use this generic qsorter-comparator (but of course this is a terrible idea, and the inlined std::sort is always preferable):
template <typename T>
int qsort_comp(void const * pa, void const * pb)
{
static_assert<std::is_trivial<T>::value, "Can only use qsort with trivial type!");
T const & a = *static_cast<T const *>(pa);
T const & b = *static_cast<T const *>(pb);
if (a < b) { return -1; }
if (b < a) { return +1; }
return 0;
}
Use: T arr[N]; qsort(arr, N, sizeof *arr, qsort_comp<T>);
Don't use this. Use std::sort instead.
Better be C++ oriented and use std::sort for your array:
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
int main() {
std::string obj[4] = {"fine", "ppoq", "tri", "get"};
std::sort(obj, obj + 4);
std::copy(obj, obj + 4, std::ostream_iterator<std::string>(std::cout, "\n"));
}
AFAIK - std::sort uses quick sort.
[UPDATE] See comments, std::sort is not always pure quick sort.
[UPDATE2]
If you want to learn qsort - change std::string to const char* and define function based on strcmp. Remember that qsort passes pointers to elements in an array - so dereference const void* to get const char*. See:
#include <stdlib.h>
#include <string.h>
int compare_cstr(const void* c1, const void* c2)
{
return strcmp(*(const char**)(c1), *(const char**)(c2));
}
int main() {
const char* obj[4] = {"fine", "ppoq", "tri", "get"};
qsort(obj, 4, sizeof(obj[0]), compare_cstr);
std::copy(obj, obj + 4, std::ostream_iterator<const char*>(std::cout, "\n"));
}
The problem is that you give qsort an array of C++ strings. In your comparison function, you seem to except C strings, since you cast them to (const char*).
Also, the third parameter of qsort, the size of data, you actually give wrong value. sizeof(obj[0].length()) will result in sizeof(size_t), which is obviously wrong. sizeof(obj[0]) would be more correct, but remember that qsort won't call copy constructor of string, which might lead to problems.
I would suggest not to use qsort with C++ strings.
See answer provided by PiotrNycz for correct solution.
You should use the std::sort template function provided by the C++ standard library (in the <algorithm> header file). By default, std::sort uses the less than comparison operator to order elements (std::string already implements operator<). If you need to specify an ordering condition (for example, case insensitive string compare), std::sort allows you to specify an ordering function object.
Example:
#include <string>
#include <algorithm>
bool caseInsensitiveOrdering(const std::string& lhs, const std::string& rhs)
{
// return true if lowercase lhs is less than lowercase rhs
}
int main()
{
std::string names[] = {"chuck", "amy", "bob", "donna"};
size_t nameCount = sizeof(names) / sizeof(names[0]);
// Sort using built-in operator<
std::sort(names, names + nameCount);
// Sort using comparison function
std::sort(names, names + nameCount, &caseInsensitiveOrdering);
}
Your error is in the declaration of the size in qsort. What is expected is the size of a member, which is, in your case, a string. So you want to use:
qsort(obj, 4, sizeof(string), compare_str);
However, you need to work with pointer to string, rather than strings themselves. Then, the code should look like:
int compare_str( const void *a, const void *b){
const string* obj = (const string*)a;
const string* obj1 = (const string*)b;
return obj->compare(*obj1);
}
// ...
string* obj[4] = { new string("fine"), new string("ppoq"),
new string("tri"), new string("get") };
qsort(obj, 4, sizeof(string*), compare_str);
// And delete the objects
for(int i = 0 ; i < 4 ; ++i) delete obj[i];
Works for me:
#include<iostream>
#include<cstdlib>
using namespace std;
#include<string>
int compare_str( const void *a, const void *b){
string* obj = (string*)a;
string* obj1 = (string*)b;
return obj->compare(*obj1);
}
int main(){
string obj[4] = {"fine", "ppoq", "tri", "get"};
qsort(obj, 4, sizeof(string), compare_str);
for( int i=0; i<4; i++)
cout<<obj[i]<<endl;
return 0;
}

return underlying array from vector

Will the array be deallocated and if so, what is a workaround?
double * GetArrayFromVector( std::map<std::string, double> m, char ** names, int count )
{
if(!names) return 0;
std::vector<double> vec(m.size());
for (int i=0; i<count; ++i)
{
if(!names[i]) return 0;
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec.push_back(iter->second);
else
return 0;
}
return &vec[0];
}
Thanks a lot
Divide your function on two.
Make your functions make just one action:
1. fill vector from map.
2. create array from vector.
Don't forget to pass map by const reference.
Main note: caller of the GetArrayFromVector is responsible for memory deallocation.
void FillVector( const std::map<std::string, double>& m,
std::vector< double >& v,
char ** names,
int count )
{
.......
}
double* createArray( const std::vector< double >& v )
{
double* result = new double [v.size()];
memcpy( result, &v.front(), v.size() * sizeof( double ) );
return result;
}
// and finally your function
double* GetArrayFromVector( const std::map<std::string, double>& m,
char ** names,
int count )
{
std::vector< double > v;
FillVector( m, v, names, count );
return CreateArray( v );
}
Yes -- it's deallocated as soon as your return from the function, because vec is declared on the stack. The std::vector destructor takes care of freeing the memory. Since you're returning the address of a deallocated array, you're going to start messing around with deallocated memory, which is a big no-no. At best, you'll crash immediately. At worst, you'll silently succeed with a big gaping security hole.
There are two ways to fix this: (1) return the entire vector by-value, which makes a copy of the entire vector, or (2) return the vector via a reference parameter.
Solution 1:
std::vector<double> GetArrayFromVector(...)
{
...
return vec; // make copy of entire vec, probably not a good idea
}
Solution 2:
void GetArrayFromVector(..., std::vector<double> & vec)
{
// compute result, store it in vec
}
Yes the array will be deallocated.
Change the function to:
double * GetArrayFromVector( std::map<std::string, double> m, vector<double> &vec, char ** names, int count )
{
vec.clear();
vec.reserve(m.size());
for (int i=0; i<count; ++i)
{
if(!names[i]) return 0;
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec.push_back(iter->second);
else
return 0;
}
return &vec[0];
}
Or else use boost::shared_array (also, look at boost::scoped_array)
boost::shared_array<double> GetArrayFromVector( std::map<std::string, double> m, char ** names, int count )
{
boost::shared_array<double> vec(new double[m.size()]);
for (int i=0; i<count; ++i)
{
if(!names[i]) return boost::shared_array<double>();
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec[i] = iter->second;
else
return boost::shared_array<double>();
}
return vec;
}
vec is a local variable. Its scope is limited to the GetArrayFromVector() function only. Never return the address of a local variable. Either return the array by value:
std::vector<double> GetArrayFromVector( std::map<std::string, double> m,
char ** names, int count )
or, pass a reference to the vector as an output parameter:
void GetArrayFromVector( std::map<std::string, double> m,
char ** names, int count,
std::vector<double>& vec)
or, pass an output iterator:
void GetArrayFromVector( std::map<std::string, double> m,
char ** names, int count,
std::vector<double>::iterator vecIter)
The last two will require some careful implementation of the function definition and calling though.
Additionally, if you are game for a bit more adventure try this:
// you'd need to change the value to use when an element is not
// found in the map to something that suits your needs
double pred(std::map<char*, double> haystick, char* const needle) {
std::map<char*, double>::iterator i = haystick.find(needle);
return i != haystick.end() ? i->second : 0;
}
int main(int argc, char* argv[])
{
std::map<char *, double> m;
std::vector<char *> names;
std::vector<double> dv;
m[ "Sasha" ] = 729.0;
m[ "josh" ] = 8154.0;
names.push_back("Sasha");
names.push_back("JonSkeet");
names.push_back("josh");
// transform is part of STL's <algorithm> header
// it takes a container (actually a range -- [begin(), end())
// note it is a half-open range -----------^
// as is customary for all STL algorithms, applies the function
// or functor specified as the last parameter to each element of
// the sequence and writes the result back to another container
// specified via the output iterator -- the third argument
//
// since I have not reserved enough elements for the vector dv
// i cannot blindly use it -- i need a back_inserter to coax
// transform to push_back() instead of do an insert operation
// of course, for vectors, this is costly since reallocations
// may happen, but let's leave the performance aside for a while!
//
// ok, so what about the last parameter, you ask? it has to be an
// unary_operation. well, mostly so. but what is it that we want?
// we want to take an iterator from the original char* (string)
// array and see if there's an entry in the map. if there is one
// we retrieve the associated double value and put it in dv; else,
// we set a default value of 0 -- change it to whatever pleases you
// maybe a std::numeric_limit<double> if it works for you.
//
// you can create a functor inheriting std::unary_function and pass
// it on. that's the easy way out. but what if you already have a
// comparator, a C-style find() function? will it work? yes, it will.
// but we have to wrap it using the function adaptor std::ptr_fun
// to make the compiler happy (after all it wants a unary_function, right?)
//
// this simple scheme of things works very well, save for a last little
// glitch. the comparator actually takes two parameters -- a what to search
// and a where to search. and guess what -- the where to search is always
// fixed. so that gives us a good oppertunity to fix the first parameter to
// our map<char*, double> which is exactly what std::bind1st() does.
// surprisingly, now that you've fixed one function, you no longer have a
// binary function (one taking two arguments) but an unary one -- which is
// just what you'd pass to transform. voila!
std::transform(names.begin(), names.end(), std::back_inserter(dv),
std::bind1st(std::ptr_fun(pred), m));
std::copy(dv.begin(), dv.end(),
std::ostream_iterator<double>(std::cout, "\n"));
return 0;
}
Some interesting links:
transform [actually, comes in two flavors]
bind1st or binder1st [there's a binder2nd too!]
back_inserter
ptr_fun [check out mem_fun also]
unary_function [and there's binary_function]
Also check out Boost. They have done some magic with bind()!
You can pass it by reference or new/delete it, but as posted your vector will be destructed after the function returns.
Yes, the vector (and the data store it holds) will be deallocated when the function ends.
Why are you creating a vector? If you want an array, just create & fill one of those..
double * GetArrayFromVector( std::map<std::string, double> m, char * names[], int count )
{
if(!names) return 0;
double* vec = new double[m.size()];
int j = 0;
for (int i=0; i<count; ++i)
{
if(!names[i]) return 0;
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec[j++] =iter->second;
else
return 0;
}
return vec;
}
Yes the vector will be deallocated when the function exits (and the 'vec' variable goes out of scope). The pointer you return will therefore be invalid.
An alternative is to allocate the array on the heap (using the 'new' operator) and return that pointer instead, but it will be the caller's responsibility to 'delete' the pointer, which is usually frown upon.
A better alternative is to return a shared_ptr to your array.
Since you know count up front, there's no benefit to using an stl vector. You could simply do this:
double* GetArrayFromVector(std::map<char*, double> m, char** names, int count)
{
double* result = new double[count];
for (int i = 0; i < count; ++i)
{
if(!names[i])
{
delete[] result;
return 0;
}
map<std::string, double>::iterator iter = m.find(name[i]);
if(iter != m.end())
{
result[i] = iter->second;
}
else
{
delete[] result;
return 0;
}
}
return result;
}
Note that you are passing ownership of the allocated array to the caller. Personally, I'd try to write the code in a way that observes the RAII principle; either pass in a vector to be populated, or use a managed/shared pointer, etc. (both of these options have been suggested in other answers).
There is a concept call move constructors that would allow you to transfer the ownership of a resource held by a (stack-based) object to a new object. I have heard that STLport has a move_source template to accomplish this
This will be coming to C++0x.
In this case, you would be returning std::vector<double> instead of double*.
Kinda surprised no one has mentioned vector::swap. Have the caller pass in a reference to a vector which will have its contents replaced by the function:
void GetArrayFromVector( std::vector<double>& output, ... )
{
std::vector<double> vec(m.size());
// construct vec here...
output.swap(vec);
}
BTW: "GetArrayFromVector" and you pass in a map?
You could use std::auto_ptr smart pointer (but passing vector reference to your function is better solution).
Example of std::auto_ptr:
std::auto_ptr< std::vector<int> > getArray(int& count){
std::auto_ptr< std::vector<int> > vec(new std::vector<int>());
vec->push_back(10);
vec->push_back(12);
vec->push_back(14);
vec->push_back(16);
count = vec->size();
return vec;
}
int main(){
int size = 0;
std::auto_ptr< std::vector<int> > autoPtrVec = getArray(size);
int* ptr = &(*autoPtrVec)[0];
std::cout << "Size: " << size << std::endl;
for(int i=0; i<size; i++){
std::cout << "[" << i << "]=" << ptr[i] << std::endl;
}
return 0;
}
C++ vectors have a data() method which returns a pointer to the underlying array.
// vector::data
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
which outputs
myvector contains: 10 20 0 100 0