This question already has answers here:
convert vector<string> into char** C++
(4 answers)
Closed 2 years ago.
I'm trying to convert a vector<char * > into a char** array. When I print parsed[0], I get garbage. How would I fix this?
char **parse(vector<string> arr){
vector<char*> res;
for(int i = 1; i < arr.size(); i++){
string s = arr.at(i);
char temp[s.length() + 1];
s.copy(temp, s.length()+1);
temp[s.length()] = '\0';
res.push_back(temp);
}
res.push_back(NULL);
char **parsed = res.data();
cout << parsed[0] << endl;
return parsed;
}
Just going by the title calling vector<char*>.data() seems to be the most straightforward way:
#include <type_traits>
#include <vector>
int main()
{
std::vector<char*> chars{};
static_assert(std::is_same_v<char**, decltype(chars.data())>);
}
This seems like a really convoluted method of just doing:
#include <algorithm>
#include <vector>
#include <iostream>
#include <string>
std::vector<const char*> to_ptrs(const std::vector<std::string>& arr) {
std::vector<const char*> res;
for (auto& s : arr) {
res.emplace_back(s.c_str());
}
return res;
}
int main() {
std::vector<std::string> input = {
"test",
"example",
"of",
"strings"
};
auto ptr_vec = to_ptrs(input); // To avoid dangling temporary
const char** result = ptr_vec.data();
for (size_t i = 0; i < input.size(); ++i) {
std::cout << result[i] << std::endl;
}
return 0;
}
Or if you prefer a C++20 solution with std::transform:
std::vector<const char*> to_ptrs(const std::vector<std::string>& arr) {
std::vector<const char*> res;
std::transform(arr.begin(), arr.end(), std::back_inserter(res), [](const std::string& s) -> const char* { return s.c_str(); });
return res;
}
Note conversion to char** is not possible because the result of c_str() is const char*.
Note: Any alterations to the original strings or string data invalidates these pointers.
Related
I have file names and I need to check if these files end with any extension of the vector extensions; I would like to use some of the algorithms that are in the library instead of how I have done it, is there any way?
#include <iostream>
#include <algorithm>
#include <vector>
std::string tail(const std::string &st, const size_t len)
{
if (len >= st.size())
return st;
return st.substr(st.size() - len);
}
std::vector<std::string> filtered_files(const std::vector<std::string>& files, const std::vector<std::string>& extensions) {
std::vector<std::string> re;
for(const std::string f : files) {
for(const std::string ex : extensions) {
if(ex == tail(f,ex.size())) {
re.push_back(std::move(f));
break;
}
}
}
return re;
}
int main(int argc, char **argv) {
std::vector<std::string> v{"main.cpp","main.c","main.py"};
std::vector<std::string> re = filtered_files(v,{".c",".cpp"});
for(const std::string s :re) {
std::cout << s << '\n';
}
}
Have a look at the std::find_if() standard algorithm in place of the inner loop. You can use the std::string::compare() method to perform substring comparisons without having to actually allocate new std::string objects, as your loops and tail() function currently do. The only string allocations you need are for the strings pushed into re (and even that allocation can be avoided if you return a std::vector<std::string*> of pointers that point to the strings in te files vector).
Try this:
#include <iostream>
#include <algorithm>
#include <vector>
std::vector<std::string> filtered_files(const std::vector<std::string>& files, const std::vector<std::string>& extensions)
{
std::vector<std::string> re;
for(const std::string &f : files)
{
if (std::find_if(extensions.begin(), extensions.end(),
[&](const std::string &ex){
return (f.size() >= ex.size()) && (f.compare(f.size()-ex.size(), ex.size(), ex) == 0);
}
) != extensions.end())
{
re.push_back(f);
}
}
return re;
}
Live Demo
There are actually many ways of solving this, personally, this is the way I've achieved it before
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>
#include <vector>
int main()
{
std::vector<std::string> v{"main.cpp","main.c","main.py"};
std::vector<std::string> ext{".cpp", ".c"};
std::vector<std::string> res;
for (auto& s : v) {
auto pos = s.find_last_of('.');
if (pos != s.npos) {
char* str = &s[pos];
if (std::any_of(ext.begin(), ext.end(),
[str](const string& a) { return str == a; })) {
res.push_back(s);
}
}
}
for (auto& r : res)
cout << r << endl;
return 0;
}
Does c++11 offer elegant solution as implemented in python maketrans/translate?
from string import maketrans
intab = "aeiou"
outtab = "12345"
trantab = maketrans(intab, outtab)
str = "this is string example....wow!!!";
print str.translate(trantab);
As as I'm aware there's no built-in function for this, but you could conceivably implement one:
#include <functional>
#include <string>
#include <unordered_map>
std::function<std::string(std::string)>
maketrans(const std::string& from, const std::string& to) {
std::unordered_map<char, char> map;
for (std::string::size_type i = 0;
i != std::min(from.size(), to.size()); ++i) {
map[from[i]] = to[i];
}
return [=](std::string s) {
for (auto& c : s) {
const auto mapped_c = map.find(c);
if (mapped_c != map.end()) {
c = mapped_c->second;
}
}
return s;
};
}
#include <iostream>
int main() {
const std::string intab = "aeiou";
const std::string outtab = "12345";
const auto translate = maketrans(intab, outtab);
const std::string str = "this is string example....wow!!!";
std::cout << translate(str) << std::endl;
return 0;
}
My try. Would would need to make a helper to create the map from two strings:
#include <iostream>
#include <string>
#include <map>
using namespace std;
using TransMap = std::map<char, char>;
void translate(std::string& string, TransMap map ){
for(auto& c : string){
const auto itr = map.find(c);
if(itr != map.end()) c = itr->second;
}
}
int main() {
std::string test = "123456789";
TransMap map{ {'1', 'a'}, {'2', 'b'}, {'3', 'c'}, {'4', 'd'}, {'5', 'e'} };
translate(test, map);
std::cout << test << '\n';
return 0;
}
I am trying to sort two cstrings, and I'm running into trouble while using qsort to complete this task. I believe my problems are that I'm not sure what to put as the parameters for compare, if my compare function is correct, or if it is even necessary for me to write my own compare function at all.
#include <algorithm>
#include <iterator>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
bool anagram(const char *s1, const char *s2);
int main() {
string sWord1, sWord2;
char cWord1[10], cWord2[10];
char *cPtr1 = cWord1;
char *cPtr2 = cWord2;
cout << "Enter Word 1: ";
cin.getline(cWord1, 10);
cout <<"\nEnter Word 2: ";
cin.getline(cWord2, 10);
anagram(cPtr1, cPtr2);
return 0;
}
bool anagram(const char *s1, const char *s2) {
char w1[10];
char w2[10];
for (int i = 0; i < 10; i++) {
w1[i] = s1[i];
w2[i] = s2[i];
}
sort(w1.begin(), w1.end()); //DOES NOT WORK
sort(begin(w1), end(w1)); //DOES NOT WORK - Says begin is not in std
}
The correct way to sort an array of chars in C++ is to use std::sort:
#include <algorithm>
#include <iterator>
bool anagram(const char *s1, const char *s2) {
// ...
std::sort(std::begin(w1), std::end(w1));
// If you can't use C++11, then use
// std::sort(w1, w1 + 10);
// ...
}
If you have to use qsort for some weird reason, it expects a function pointer taking two const void * parameters that point to the elements to be compared:
int compare(const void * e1, const void *e2){
char c1 = *static_cast<const char *>(e1), c2 = *static_cast<const char *>(e2);
return c1 - c2; // <0 if c1 < c2, etc.
}
qsort(w1, 10, sizeof(char), compare);
This is slow, error prone, and causes undefined behavior for nontrival types, and is not recommended.
This is your code as you were trying to write it. But as has been pointed out, qsort is not the preferred approach.
#include <cstdlib>
#include <cstring>
#include <iostream>
int compare(const void* c1, const void* c2) {
const char& cc1 = *static_cast<const char*>(c1);
const char& cc2 = *static_cast<const char*>(c2);
return cc1 - cc2; }
bool anagram(const char* s1, const char* s2) {
char w1[10];
char w2[10];
for (int i = 0; i < 10; i++) {
w1[i] = s1[i];
w2[i] = s2[i]; }
qsort(w1, 10, sizeof(char), compare);
qsort(w2, 10, sizeof(char), compare);
return 0 == strncmp(w1, w2, 10); }
int main(int, char* []) {
std::cout << anagram("abcdefghij", "bcdaghefji") << std::endl;
std::cout << anagram("abcdefghij", "xxxxxxxxxx") << std::endl;
return 0; }
I have 2 char arrays like "const char *arr1[ArrSize] = {"Blah1", "Wibble1", "Shrug1"};".
For putting them into a vector I found a nice quick solution:
void fillVecTest()
{
const int ArrSize = 3;
const char *arr1[ArrSize] = {"Blah1", "Wibble1", "Shrug1"};
const char *arr2[ArrSize] = {"Blah2", "Wibble2", "Shrug2"};
std::vector<std::string> vec1(arr1, arr1+ArrSize);
std::vector<std::string> vec2(arr2, arr2+ArrSize);
std::vector<std::string>::iterator l_It1Vec1;
std::vector<std::string>::iterator l_It = vec1.end();
l_It = find(vec1.begin(), vec1.end(), std::string("Blah1"));
if(l_It != vec1.end())
{
size_t l_pos = l_It - vec1.begin();
printf("found %s, pos=%u val: %s\n", l_It->c_str(),l_pos, vec2[l_pos].c_str());
}
}
Now I thought it should be also possible to put both directly into a map as arr1 is the key and arr2 is the value. I tried some ways but I didn't succeed.
void fillMapTest()
{
const int ArrSize = 3;
const char *arr1[ArrSize] = {"Blah1", "Wibble1", "Shrug1"};
const char *arr2[ArrSize] = {"Blah2", "Wibble2", "Shrug2"};
std::map<std::string,std::string> map1;//(pair(arr1,arr1), pair(arr1+ArrSize,arr2+ArrSize));
std::map<std::string,std::string>::iterator l_It1Map1;
//l_It1Map1 = find(map1.begin(), map1.end(), std::string("Blah1"));
if(l_It1Map1 != map1.end())
{
printf("found key: %s, val: %s\n",l_It1Map1->first.c_str(), l_It1Map1->second.c_str());
}
}
int _tmain(int /*argc*/, _TCHAR* /*argv[]*/)
{
fillVecTest();
fillMapTest();
return 0;
}
I think that just the commented lines in function "fillMapTest" would need to be solved.
Constuctor and find don't work like I want.
Please has any STL expert an idea?
The easiest way to write this:
std::map<std::string, std::string> m {
{ "key1", "value1" },
{ "key2", "value2" },
};
This requires your compiler to support initializer lists (a feature of C++11).
std::map<std::string, std::string> m;
for(int i = 0; i < ArrSize; i++) {
std::pair<std::string, std::string> p =
std::make_pair(std::string(arr1[i]), std::string(arr2[i]));
m.insert(p);
}
If you really want to use the map constructor you need an iterator of pairs and the only way(i know) is to use a std::vector<std::pair<std::string, std::string> >::iterator but this seems to be an unneeded extra step to get the same result.
#include <vector>
#include <map>
#include <string>
std::vector<std::pair<std::string, std::string> > values;
for(int i = 0; i < ArrSize; i++) {
std::pair<std::string, std::string> p =
std::make_pair(std::string(arr1[i]), std::string(arr2[i]));
values.push_back(p);
}
std::map<std::string, std::string> m(values.begin(), values.end());
for(int i = 0; i < ArrSize; i++) {
m.insert(pair<string, string>(arr1[i], arr2[i]));
}
I have a vector of strings. Need help figuring out how to convert it into vector of integers in order to be able to work with it arithmetically. Thanks!
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[]) {
vector<string> vectorOfStrings;
vectorOfStrings.push_back("1");
vectorOfStrings.push_back("2");
vectorOfStrings.push_back("3");
for (int i=0; i<vectorOfStrings.size(); i++)
{
cout<<vectorOfStrings.at(i)<<endl;
}
vector<int> vectorOfIntegers;
//HELP NEEDED HERE
//CONVERSION CODE from vector<string> to vector<int>
int sum;
for (int i=0; i<vectorOfIntegers.size(); i++)
{
sum += vectorOfIntegers.at(i);
}
cout<<sum<<endl;
cin.get();
return 0;
}
There are mulitple ways of converting a string to an int.
Solution 1: Using Legacy C functionality
int main()
{
//char hello[5];
//hello = "12345"; --->This wont compile
char hello[] = "12345";
Printf("My number is: %d", atoi(hello));
return 0;
}
Solution 2: Using lexical_cast(Most Appropriate & simplest)
int x = boost::lexical_cast<int>("12345");
Surround by try-catch to catch exceptions.
Solution 3: Using C++ Streams
std::string hello("123");
std::stringstream str(hello);
int x;
str >> x;
if (!str)
{
// The conversion failed.
}
Use boost::lexical_cast. And surround it with try-catch block.
try
{
for (size_t i=0; i<vectorOfStrings.size(); i++)
{
vectorOfIntegers.push_back(boost::lexical_cast<int>(vectorOfStrings[i]));
}
}
catch(const boost::bad_lexical_cast &)
{
//not an integer
}
Or you can use Boost.Spirit parser (which someone claims is faster than even atoi()) as:
int get_int(const std::string & s)
{
int value = 0;
std::string::const_iterator first = s.begin();
bool r = phrase_parse(first,s.end(),*int_[ref(value)=_1], space);
if ( !r || first != s.end()) throw "error";
return value;
}
//Usage
int value = get_int("17823");
std::cout << value << std::endl; //prints 17823
The full demo using your code : http://ideone.com/DddL7
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <boost/lexical_cast.hpp>
using namespace std;
int stringToInteger(const std::string& s)
{
return boost::lexical_cast<int>(s);
}
int main(int /*argc*/, char* /*argv*/[])
{
vector<string> vectorOfStrings;
// ..
vector<int> vectorOfIntegers;
std::transform(vectorOfStrings.begin(), vectorOfStrings.end(), std::back_inserter(vectorOfIntegers), stringToInteger);
// ..
}
You can replace the implementation of stringToInteger(..) with your preferred conversion function.
Here is the working version made up using the above comments.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
int main(int argc, char* argv[]) {
vector<string> vectorOfStrings;
vectorOfStrings.push_back("1");
vectorOfStrings.push_back("2");
vectorOfStrings.push_back("3");
for (int i=0; i<vectorOfStrings.size(); i++)
{
cout<<vectorOfStrings.at(i)<<endl;
}
vector<int> vectorOfIntegers;
int x;
for (int i=0; i<vectorOfStrings.size(); i++)
{
stringstream str(vectorOfStrings.at(i));
str >> x;
vectorOfIntegers.push_back(x);
}
int sum = 0;
for (int i=0; i<vectorOfIntegers.size(); i++)
{
sum += vectorOfIntegers.at(i);
}
cout<<sum<<endl;
cin.get();
return 0;
}
What about:
#include <algorithm>
#include <boost/lexical_cast.hpp>
template<typename C1, typename C2>
void castContainer(const C1& source, C2& destination)
{
typedef typename C1::value_type source_type;
typedef typename C2::value_type destination_type;
destination.resize(source.size());
std::transform(source.begin(), source.end(), destination.begin(), boost::lexical_cast<destination_type, source_type>);
}
It can convert vector<string> into vector<int>, and also other container<T1> into container2<T2>, e.g.: list -> list.
Full code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <boost/lexical_cast.hpp>
template<typename C1, typename C2>
void castContainer(const C1& source, C2& destination)
{
typedef typename C1::value_type source_type;
typedef typename C2::value_type destination_type;
destination.resize(source.size());
std::transform(source.begin(), source.end(), destination.begin(), boost::lexical_cast<destination_type, source_type>);
}
template<typename T, typename T2>
std::vector<T>& operator<<(std::vector<T>& v, T2 t)
{
v.push_back(T(t));
return v;
}
main(int argc, char *argv[])
{
std::vector<std::string> v1;
v1 << "11" << "22" << "33" << "44";
std::cout << "vector<string>: ";
std::copy(v1.begin(), v1.end(), std::ostream_iterator<std::string>(std::cout, ", "));
std::cout << std::endl;
std::vector<int> v2;
castContainer(v1, v2);
std::cout << "vector<int>: ";
std::copy(v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
There are two independent tasks.
Convert a single string to an integer
Having something that can convert from A to B, convert std::vector<A> to std::vector<B>
I suggest you try to do them separately, and then combine the results. If one of these tasks proves difficult, you will be able to ask a more focused question.
The most general way to convert strings to integers is with stringstream and a function template. You can optionally set the base for the conversion if you're dealing with hexadecimal. The boost library would also be helpful in your example.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <stdexcept>
#include <boost/static_assert.hpp>
#include <boost/foreach.hpp>
/******************************************************************************
* Handy string to type conversion
* First parameter is the string to convert
* Second optional parameter is the number base, e.g. std::hex
*
* Because this is a function template, the compiler will instantiate one
* instance of the function per type
*****************************************************************************/
// the std::dec thingy is actually a function, so extra glue required.
typedef std::ios_base& (*ios_base_fn)( std::ios_base& str );
template <class T>
T strtotype( const std::string& s, ios_base_fn base = std::dec )
{
// C++ can't convert 8-bit values, they are *always* treated
// as characters. :( At least warn the user.
// this gives a cryptic error message, but better than nothing.
BOOST_STATIC_ASSERT( sizeof(T) > 1 );
T val;
std::istringstream iss(s);
iss >> base >> val;
if( iss.fail() )
throw std::runtime_error( "Error: strtotype(): Can't convert string '" + s + "' to numeric value" );
return val;
}
using namespace std;
int main(int argc, char* argv[]) {
vector<string> vectorOfStrings;
vectorOfStrings.push_back("1");
vectorOfStrings.push_back("2");
vectorOfStrings.push_back("3");
for (int i=0; i<vectorOfStrings.size(); i++)
{
cout<<vectorOfStrings.at(i)<<endl;
}
vector<int> vectorOfIntegers;
for( size_t i = 0; i < vectorOfStrings.size(); i++ )
vectorOfIntegers.push_back( strtotype<int>( vectorOfStrings[i] ));
// or better yet, use boost_foreach
BOOST_FOREACH( const string& s, vectorOfStrings )
vectorOfIntegers.push_back( strtotype<int>( s ));
int sum;
for (int i=0; i<vectorOfIntegers.size(); i++)
{
sum += vectorOfIntegers.at(i);
}
cout<<sum<<endl;
cin.get();
return 0;
}
If you don't want or can't use boost, you can remove the sizeof() check in strtotype. However, be careful never to try to convert to strings to individual bytes. Doing so will fail silently by only converting the first nibble of the byte.
If you're suing GNU tools, then compile like so:
g++ -Wall -O3 -I /path/to/boost/include main.cpp
or, if you delete the boost related bits:
g++ -Wall -O3 main.cpp