convert vector<string> into char** C++ - c++

I have a vector<std::string> variable. I need to pass it onto a method which accepts char**as an input parameter.
how to do this ? If possible I need to pass a writable one.
Update 1:
In a tool for creating a service method, i give parameters as std::vector, but it sets automatically the qualifier as &, which means my method definition generated by the tool will look as:
std::string SvcImpl::myMethodname ( const std::string par1, const std::vector< std::string >& par2, const std::vector< std::string >& par3 )
{
}
This method gets called automatically with values in the patameter passed.
Now from inside this method I'm going to call a method in a dll in a lib folder which looks like:
int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);
for par1 --> I'm passing (char*)par1.c_str()
I need to know how to pass variables for par2 and par3 and for pRetValue.
values for par2 and par3 are available in vector but the last parameter pRetValue is an output parameter that i need to return it as std::string.
sorry if i am very confusing or asking very basic questions.

It is possible to solve the problem without copying out all the std::strings as long as the function does not modify the passed in char**. Otherwise I can see no alternative but to copy out everything into a new char**` structure (see second example).
void old_func(char** carray, size_t size)
{
for(size_t i = 0; i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
std::vector<std::string> strings {"one", "two", "three"};
std::vector<char*> cstrings;
cstrings.reserve(strings.size());
for(size_t i = 0; i < strings.size(); ++i)
cstrings.push_back(const_cast<char*>(strings[i].c_str()));
// Do not change any of the strings here as that will
// invalidate the new data structure that relies on
// the returned values from `c_str()`
//
// This is not an issue after C++11 as long as you don't
// increase the length of a string (as that may cause reallocation)
if(!cstrings.empty())
old_func(&cstrings[0], cstrings.size());
}
EXAMPLE 2: If the function must modify the passed in data:
void old_func(char** carray, size_t size)
{
for(size_t i = 0; i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
{
// pre C++11
std::vector<std::string> strings {"one", "two", "three"};
// guarantee contiguous, null terminated strings
std::vector<std::vector<char>> vstrings;
// pointers to rhose strings
std::vector<char*> cstrings;
vstrings.reserve(strings.size());
cstrings.reserve(strings.size());
for(size_t i = 0; i < strings.size(); ++i)
{
vstrings.emplace_back(strings[i].begin(), strings[i].end());
vstrings.back().push_back('\0');
cstrings.push_back(vstrings.back().data());
}
old_func(cstrings.data(), cstrings.size());
}
{
// post C++11
std::vector<std::string> strings {"one", "two", "three"};
std::vector<char*> cstrings;
cstrings.reserve(strings.size());
for(auto& s: strings)
cstrings.push_back(&s[0]);
old_func(cstrings.data(), cstrings.size());
}
}
NOTE: Revised to provide better code.

Galik's answer has a number of safety issues. Here is how I would do it in Modern C++:
#include <iostream>
#include <string>
#include <vector>
void old_func(char** carray, std::size_t size)
{
for(std::size_t i(0); i < size; ++i)
std::cout << carray[i] << '\n';
}
void other_old_func(const char** carray, std::size_t size)
{
for(std::size_t i(0); i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
{
std::cout << "modifiable version\n";
std::vector<std::string> strings{"one", "two", "three"};
std::vector<char*> cstrings{};
for(auto& string : strings)
cstrings.push_back(&string.front());
old_func(cstrings.data(), cstrings.size());
std::cout << "\n\n";
}
{
std::cout << "non-modifiable version\n";
std::vector<std::string> strings{"four", "five", "six"};
std::vector<const char*> cstrings{};
for(const auto& string : strings)
cstrings.push_back(string.c_str());
other_old_func(cstrings.data(), cstrings.size());
std::cout << std::endl;
}
}
No messy memory management or nasty const_casts.
Live on Coliru.
Outputs:
modifiable version
one
two
three
non-modifiable version
four
five
six

The top rated answers for this question expect you to pass in a size with your char** parameters. But in method_to_be_called() there is no way to pass in a size for par2 and par3 so these lists of c-style strings probably expect to be null terminated. In other words the last string (char*) in the list of strings (char **) needs to be a null pointer. This is a common paradigm in many c libraries.
int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);
The most expedient way around this is probably to go with a more c-style answer.
//directly create char** par2
std::vector<std::string> par2Vect{"one", "two", "three"};
char ** par2 = (char**) malloc( sizeof(char*)*(par2Vect.size() + 1) );
for(size_t i = 0; i < par2Vect.size(); ++i)
{
par2[i] = strdup(par2Vect[i].c_str());
}
// set the last entry to null to signify the end of the list
par2[par2Vect.size()] = nullptr;
// call your library
method_to_be_called(..., par2,...);
// delete par2
for(size_t i = 0; i < par2Vect.size(); ++i)
{
// free memory for each c-style string
free(par2[i]);
}
// free memory for outer char* array
free(par2);

I believe this is rather easy and can be done without too much of complexity.
std::vector<std::string> vector = {"a", "std::vector", "of", "std::string"};
// Result char**.
char** result = new char*[vector.size()];
for (int index = 0; index < vector.size(); index++) {
result[index] = const_cast<char*>(vector[index].c_str());
}
// Use the result.
delete[] result;
// Deallocate the memory from heap after usage.

Related

Separating Arguments for Multiple programs from Command line in main

I am integrating 2 programs and turning them into one (I know, not ideal). I expect command line args to look something like
bin/programName -optionsProgram1 --optionsProgram2
I have parsed the options out so I now have the separate sets of arguments, shown below.
bin/programName -optionsProgram1
bin/programName --opionsProgram2
This is great, just how I need them to be. The problem is that I did that with arguments being pushed onto vectors and now I need to use pointers to character arrays. Can anyone recommend a way to convert my vectors into char* in a better way? Also, these will have to be returned as char** in the end, please keep that in mind with your answers.
I have tried using strncpy and realized there was a type error.
My attempt is shown below
.h excerpt
std::vector<std::string> myVec; //hold the arguments, one at each pos
std::vector<char*> myCharArray; //intended location for result of conversion
.cpp excerpt
size_t vecSize = myVec.size()
size_t charVecSize;
myCharArray.resize(vecSize);
for(size_t i=0; i < vecSize; ++i)
{
csize = myVec.size()+1 //include null
myCharArray[i] = new char[csize]
strncpy(myCharArray[i], myVec[i].c_str(), csize);
myCharArray[i][csize-1] = '\0'
}
Try std::vector<const char*> populated with pointers from std::string::c_str(), eg:
std::vector<std::string> myVec;
std::vector<const char*> myCharArray;
// populate myVec as needed ...
...
// add +1 if you need the array to be null-terminated...
myCharArray.reserve(myVec.size()/*+1*/);
for (auto &s : myVec) {
myCharArray.push_back(s.c_str());
}
//myCharArray.push_back(nullptr);
or:
myCharArray.resize(myVec.size()/*+1*/);
for (size_t i = 0; i < myVec.size(); ++i) {
myCharArray[i] = myVec[i].c_str();
}
//myCharArray.back() = nullptr;
or:
#include <algorithm>
myCharArray.resize(myVec.size()/*+1*/);
std::transform(myVec.begin(), myVec.end(), myCharArray.begin(),
[](std::string &s){ return s.c_str(); });
//myCharArray.back() = nullptr;
Then you can use myCharArray.data() (which is const char **) as needed.

How do we pass array of strings to another function in c++ and how do we access each string in the called function

While passing an array of strings to another function by reference, how do i print the values(strings) in the called function one by one and what is the type of argument that needs to be declared in the called function's input parameters.
You can pass an array by reference like this:
template <int N>
void foo(string (&arr)[N])
{
arr[0] = "a";
arr[1] = "b";
/// Do other stuff with arr
}
Now you can simply use arr like a regular array. The template parameter N is needed is an array of size i and size j, are distinct types when i!=j.
Here is one approach:
void Func(const std::string* stringArr, int arraySize) {
for ( int n = 0; n < arraySize; ++n ) {
const std::string& sz = stringArr[n];
}
}
std::string array[10];
Func(array, 10); // here array decays to pointer to its first element
#include <iostream>
using namespace std;
string getConcatenate(string arr[], int size)
{
string concatenate;
for (int i = 0; i < size; ++i)
{
concatenate += arr[i];
if (i != size - 1)
concatenate += " ";
}
return concatenate;
}
int main()
{
string balance[6] = { "This", "is", "an", "example", "string", "array" };
string sentence;
sentence = getConcatenate(balance, 6);
cout << "Concatenated value is: " << sentence.c_str() << endl;
getchar();
return 0;
}
This example illustrates, sending string as array and returning string.
void output_function(string str[])
and use str as normal array.
If you have some flexibility in how you define an "array of strings" I suggest you use standard containers.
If your "array" is of fixed size use a std::array, otherwise use std::vector:
void doSomethingWithAnArray(const std::array<std::string, 5>& strings);
void doSomethingWithAVector(const std::vector<std::string>& strings);
Then one way to access each string in the container is to use a ranged-based for loop. For example:
for (auto& str : strings)
std::cout << str << " ";
std::cout << "\n";

String manipulation , at a complete loss

I am trying to grab sub-strings out of a larger string and I have got it to work in a small program but when I try to run it into the real program it just goes wrong. I am building off someone else s function and got it to work for my purpose, but cannot get it to work in the main program I need it in. I will limit the program down to where I think error is occurring.
Problem: I pass in same value into function findStats(std::string sString) but get different results.
Case I:
stats = findStats("^9dff9d[Attribute 0% Active Defense 0]\r^f2f3f2Mana: 1411 ^00ff00(+1975)\r^f2f3f2^9dff9d[Attribute 0% Active Mana 0]\r^f2f3f2^ffc000Fortify Level: 12/12\r^f2f3f2^006effIdentified Attribute: + 6% Crit Damage\rIdentified Attribute: + 6 Accuracy\r^f2f3f2^006eff^O053Sacrifice Elapse(6/8)\r^00ff00 ^O041Desollar's Shadow\rÌÌÌÌÌÌÌÌL«");
The above case will output correctly and stores \r offsets correctly.
Case II:
stats = findStats((std::string)((char*)&buffer));
Case II is the case I need to work and has the same value as above Case I at start of function findStats but offsets for \r Are not stored for w.e reason when sString has same value at start of function.
//Function that finds positioning of \r
void calc_z (std::string &s, std::vector<int> & z)
{
int len = s.size();
z.resize (len);
int l = 0, r = 0;
for (int i=1; i<len; ++i)
if (z[i-l]+i <= r)
z[i] = z[i-l];
else
{
l = i;
if (i > r) r = i;
for (z[i] = r-i; r<len; ++r, ++z[i])
if (s[r] != s[z[i]])
break;
--r;
}
}
std::vector<std::string> findStats(std::string sString){
//sString is exactly the same in value for both cases of stats at this point
int offSet = 0;
int sOffsets[100] = {};
std::vector<std::string> t1;
std::string main_string = sString;
std::string substring = "\r";
std::string working_string = substring + main_string;
std::vector<int> z;
calc_z(working_string, z);
for(int i = substring.size(); i < working_string.size(); ++i){
if(z[i] >=substring.size()){
sOffsets[offSet] = i;
offSet++;
}
}
.... code ....problem occurs right above offsets are not stored for \r
}
void main()
{
std::vector<std::string> stats;
std::string buffer[10];
...code...
...code to find string and store in buffer...
stats = findStats((std::string)((char*)&buffer));
//stats = findStats("^9dff9d[Attribute 0% Active Defense 0]\r^f2f3f2Mana: 1411 ^00ff00(+1975)\r^f2f3f2^9dff9d[Attribute 0% Active Mana 0]\r^f2f3f2^ffc000Fortify Level: 12/12\r^f2f3f2^006effIdentified Attribute: + 6% Crit Damage\rIdentified Attribute: + 6 Accuracy\r^f2f3f2^006eff^O053Sacrifice Elapse(6/8)\r^00ff00 ^O041Desollar's Shadow\rÌÌÌÌÌÌÌÌL«");
for( std::vector<std::string>::const_iterator i = stats.begin(); i != stats.end(); ++i)std::cout << *i << ' ' << std::endl;
std::cin.get();
}
This statement: (std::string)((char*)&buffer) does not do what you think it does.
std::vector is not a simple array.
If you take address of std::vector, that won't be the address of the first element within std::vector.
YOu can't just cast const char* or char* into std::string. You can, however, construct new std::string using provided const char* or char * c-style string. const char *str = asdf; std::string s = std::string(str);.
So, to summarize:
If you want to pass several strings at once in std::vector, pass the buffer by const reference
typedef std::vector<std::string> StringVector;
void test(const StringVector& v){
for (StringVector::const_iterator i = v.begin(); i != v.end(); i++)
std::cout << *i << std::endl;
}
...
StringVector strings;
test(strings);
If you want to WRITE something into std::vector, pass it by reference:
typedef std::vector<std::string> StringVector;
void test(const StringVector& out){
out.push_back("test");
}
...
StringVector strings;
test(strings);
If you want to pass a single string from, vector, just pass the element itself (by reference, const reference, or by value, depending on what you want to do with it), without casts.
typedef std::vector<std::string> StringVector;
void test(const std::string& s){
std::cout << s << std::endl;
}
...
StringVector strings;
strings.push_back("test");
test(strings[0]);
--edit--
IN addition to that:
std::vector<std::string> findStats(std::string sString){
//sString is exactly the same in value for both cases of stats at this point
int offSet = 0;
int sOffsets[100] = {};//<<here's a problem
Using array with fixed size in this case is a bad idea. Your array is small, and it WILL overflow on any string larger than 100 bytes, breaking/crashing your program. You can simply store results on std::vectro<std::string>, make vector of structs, or use std::map, depending on your goals.

c++ vector of boost::shared_ptr

I just started learning boost shared pointers.
I wrote a short program, results look good but I'm not sure if memory is deallocating well with my code. I would like to ask, if someone could look at my code and tell if I correctly use shared pointers.
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
#define VECTSIZE 10
typedef boost::shared_ptr<std::string> StringPtr;
typedef std::vector<StringPtr> StringVect;
///////////////////////////////////////////////////////////////
std::string random_string (size_t length);
///////////////////////////////////////////////////////////////
int main()
{
StringVect vect;
for (int i = 0; i < VECTSIZE; i++)
{
std::string * stdstr;
stdstr = new std::string;
*stdstr = random_string(10);
std::cout << *stdstr << "\r\n";
StringPtr str(stdstr);
vect.push_back(str);
}
std::cout << "\r\n\r\n";
for (int i = 0; i < VECTSIZE; i++)
{
std::cout << *vect[i] << "\r\n";
}
vect.clear();
system("pause");
return 0;
}
///////////////////////////////////////////////////////////////
std::string random_string (size_t length)
{
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[ rand() % max_index ];
};
std::string str(length,0);
std::generate_n( str.begin(), length, randchar );
return str;
}
Thanks for any advice; I hope it'll be helpful for me and others.
Your use is correct in the sense that there are no direct memory leaks. However, you're not really exception safe - if random_string throws, you'll leak stdstr. It's better (and more idiomatic) to bypass rwa pointers entirely. Here's an example with using std::shared_ptr:
for (int i = 0; i < VECTSIZE; i++)
{
StringPtr str = std::make_shared<std::string>(); // Encapsulates new
*str = random_string(10);
std::cout << *str << '\n'; //No \r here: text streams insert it on Windows automatically
vect.push_back(str);
}
Also, as #ForEveR noted, there's little reason to allocate std::string dynamically in real world apps. But I assume you use it just as an excercise with smart pointers, which is fine of course.
All is okay, but you needn't vect.clear() string. However, string is value-type, don't use shared_ptr of string.

Storing strings

I'm trying to write a code which stores strings in an array. I'm trying to do it with char* but I couldn't achieve. I search the net but couldn't find an answer. I've tried the code below, but it didn't compile.I use string stream because at some point I need to concatenate a string with an integer.
stringstream asd;
asd<<"my name is"<<5;
string s = asd.str();
char *s1 = s;
> I'm trying to write a code which stores strings in an array.
Well, first you'll need an arary of strings. I don't like using naked arrays, so I use std::vector:
std::vector<std::string> myStrings;
But, I understand you have to use an array, so we'll use an array instead:
// I hope 20 is enough, but not too many.
std::string myStrings[20];
int j = 0;
> I use string stream because ...
Okay, we'll use stringstream:
std::stringstream s;
s << "Hello, Agent " << 99;
//myStrings.push_back(s.str()); // How *I* would have done it.
myStrings[j++] = s.str(); // How *you* have to do it.
That gets us one string, but you want an array of them:
for(int i = 3; i < 11; i+=2) {
s.str(""); // clear out old value
s << i << " is a" << (i==9?" very ":"n ") << "odd prime.";
//myStrings.push_back(s.str());
myStrings[j++] = s.str();
}
Now you have an array of strings.
Complete, tested program:
#include <sstream>
#include <iostream>
int main () {
// I hope 20 is enough, but not too many.
std::string myStrings[20];
int j = 0;
std::stringstream s;
s << "Hello, Agent " << 99;
//myStrings.push_back(s.str()); // How *I* would have done it.
myStrings[j++] = s.str(); // How *you* have to do it.
for(int i = 3; i < 11; i+=2) {
s.str(""); // clear out old value
s << i << " is a" << (i==9?" very ":"n ") << "odd prime.";
//myStrings.push_back(s.str());
myStrings[j++] = s.str();
}
// Now we have an array of strings, what to do with them?
// Let's print them.
for(j = 0; j < 5; j++) {
std::cout << myStrings[j] << "\n";
}
}
How about something like this?
vector<string> string_array;
stringstream asd;
asd<<"my name is"<<5;
string_array.push_back(asd.str());
char *s1 = s;
Is illegal. You either need:
const char *s1 = s.c_str();
if you're not set on char*, or you'll need to allocate a new char* and use strcpy to copy the contents from the string.
Just change your code to
char const* s1 = s.c_str();
because a pointer to char can't store a string object, only a pointer to char, which is what c_str() returns.
I wouldn't use the char * directly. I would wrap it in something like the template below. You can override the operators you need to do any more operations (example, I would make data a private member, and override the operators to make the data print out cleanly). I did the assignment operator just to demonstrate how clean that could make code.
#include "MainWindow.h"
#include <stdio.h>
using namespace std;
template<size_t size>
class SaferChar
{
public:
SaferChar & operator=(string const & other)
{
strncpy(data, other.c_str(), size);
return *this;
}
char data[size];
};
int main(int argc, char *argv[])
{
SaferChar<10> safeChar;
std::string String("Testing");
safeChar = String.c_str();
printf("%s\n", safeChar.data);
return 0;
}