C++ Assign char** to an array of strings - c++

I know that you can assign a character array to a string:
#include <string>
using std::string;
char foo[] = "foo";
string str = foo;
But how do you assign an array of character arrays (char**) to an array of strings?

Here you are
#include <iostream>
#include <vector>
#include <iterator>
int main()
{
const char * a[] = { "Hello", "World" };
std::vector<std::string> v( std::begin( a ), std::end( a ) );
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << '\n';
return 0;
}
The program output is
Hello World
Or
#include <iostream>
#include <vector>
int main()
{
const size_t N = 2;
const char ** a = new const char * [N] { "Hello", "World" };
std::vector<std::string> v( a, a + N );
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << '\n';
delete [] a;
return 0;
}

Related

C++ function to return a reversed char array

Can somebody please help me get this code working? The Reverse method is to take a char array parameter, and return a reversed array. Then I want to print it out in main
#include <iostream>
#include <iomanip>
using namespace std;
char[] Reverse(char ch[]) {
char arr[sizeof(ch)];
for (int i=0; i< sizeof(ch); i++){
arr[i] = ch[sizeof(ch) -i -1];
}
return arr;
}
int main() {
char ch1[] = {'a', 'b', 'c'};
char ch2[] = Reverse(ch1);
cout << ch2[0] << endl;
return 0;
}
For starters this function declaration
char[] Reverse(char ch[]);
is incorrect. Functions may not have an array return type.
You could declare the function like
char * Reverse(char ch[]);
but as your function does not deal with strings then in this case it is more logical consistent to declare your function like
void Reverse( char ch[], size_t n );
As the function parameter of the array type is adjusted by the compiler to pointer to the element type of the array like
void Reverse( char *ch, size_t n );
then within the function the parameter ch is a pointer. As a result this expression sizeof( ch ) used within the function yields the size of pointer that depending on the used system is equal to either 4 or 8. so it is why I specified the second parameter of the function because you need explicitly to pass the array size if the array is not passed to the function by reference.
Within the function you are trying to return pointer to the first element of a local array
char arr[sizeof(ch)];
//...
return arr;
that makes the returned pointer invalid because the array will not be alive after exiting the function.
As the first parameter of the function is declared without the qualifier const then it means that the function needs to reverse the original array instead of making a reversed copy of the original array.
Pay attention to that this statement in main
cout << ch2[0] << endl;
does not make great sense. It outputs only the first element of the array.
Taking all this into account the function can be defined the following way
#include <iostream>
#include <utility>
void Reverse( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
std::swap( s[i], s[n-i-1] );
}
}
int main()
{
char s[] = { 'a', 'b', 'c' };
std::cout.write( s, sizeof( s ) ) << '\n';
Reverse( s, sizeof( s ) );
std::cout.write( s, sizeof( s ) ) << '\n';
return 0;
}
The program output is
abc
cba
An alternative approach is to write a template function. In this case the second parameter is not required.
Here you are.
#include <iostream>
#include <utility>
template <size_t N>
void Reverse( char ( &s )[N] )
{
for ( size_t i = 0; i < N / 2; i++ )
{
std::swap( s[i], s[N-i-1] );
}
}
int main()
{
char s[] = { 'a', 'b', 'c' };
std::cout.write(s, sizeof( s ) ) << '\n';
Reverse( s );
std::cout.write(s, sizeof( s ) ) << '\n';
return 0;
}
If you want to write a function that reverses a string stored in a character array then the function declaration can look like
char * Reverse( char s[] );
Here is one more demonstrative program.
#include <iostream>
#include <utility>
#include <cstring>
char * Reverse( char *s )
{
for ( size_t i = 0, n = std::strlen( s ); i < n / 2; i++ )
{
std::swap( s[i], s[n-i-1] );
}
return s;
}
int main()
{
char s[] = { 'a', 'b', 'c', '\0' };
std::cout << s << '\n';
std::cout << Reverse( s ) << '\n';
return 0;
}
The program output will be the same as it is shown above that is
abc
cba
Pay attention to that there is standard algorithm std::revrese that you could use for your original array
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
char s[] = { 'a', 'b', 'c' };
std::cout.write( s, sizeof( s ) ) << '\n';
std::reverse( std::begin( s ), std::end( s ) );
std::cout.write( s, sizeof( s ) ) << '\n';
return 0;
}
If the array contains a string then in general case a call of the algorithm will look the following way
#include <iostream>
#include <algorithm>
#include <cstring>
int main()
{
char s[] = { 'a', 'b', 'c', '\0' };
std::cout << s << '\n';
std::reverse( s, s + std::strlen( s ) );
std::cout << s << '\n';
return 0;
}

Removing all occurrences of a character from a string in C++

My assignment says I should write a function called removeChar that;
Takes 4 inputs: an integer num, a string str, a string s and a character c, but does not return
anything.
Finds the number of all the occurrences of c in s (both capital and lower case (hint: you may
use ASCII codes for comparison)) and saves it in num
Copies the trimmed string in str
Write in the same file a main() function containing a series of tests to showcase the correct
behavior of removeChar ().
But all printing operations should be done from the main() function. I have this code:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string removeChar(int num, string s, string str, char c);
int main()
{
string s = "asdfasdf";
s = removeChar(1, "a", "hello", 'h');
cout << s;
}
string removeChar(int num, string s, string str, char c)
{
int i;
for (i = 0; i < s.length(); i++)
if (int(s.at(i)) == int(c))
num = int(c);
str.erase(std::remove(str.begin(), str.end(), (char)num), str.end());
return str;
}
It doesn't work, and even if it did, I need to have a void function.
If I have understood the description of the assignment correctly,
then you need something like the following:
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <cctype>
void removeChar( std::string::size_type &n, std::string &str, const std::string &s, char c )
{
str.clear();
c = std::toupper( ( unsigned char )c );
auto equal_to_c = [&c]( const auto &item )
{
return std::toupper( ( unsigned char )item ) == c;
};
std::remove_copy_if( std::begin( s ), std::end( s ),
std::back_inserter( str ),
equal_to_c );
n = s.size() - str.size();
}
int main()
{
std::string::size_type n = 0;
std::string str;
removeChar( n, str, "This is a silly assignment", 's' );
std::cout << "n = " << n << ", str = " << str << '\n';
return 0;
}
The program output is:
n = 5, str = Thi i a illy aignment

Counting the appearance of words in a vector and listing those in a list, C++

I have a cpp vector containing separate words and I need to count how many times a word appears using a list. I try to iterate through the list but failing with the comparison of the two STL containers, whether the following word is already in my list or not. If not, I want to add that word to my list with an appearance of 1. I have a struct that counts the times a word appeared in the text.
The following code returns a list of words and numbers, but not each in my vector and I can't see why.
struct counter{
string word;
int sum = 1;
counter(){};
counter(string word): word(word){};
};
list<counter> list_count(vector<string> &text){
list<counter> word_count;
list<counter>::iterator it = word_count.begin();
for(string t:text){
if(it != word_count.end()){
it -> sum++;
} else {
word_count.push_back(counter(t));
}
++it;
}
return word_count;
}
Thank you in advance.
list<counter> list_count(const vector<string>& text) {
list<counter> word_count;
for (const string& t : text) {
auto it = std::find_if(word_count.begin(), word_count.end(),
[&](const counter& c){ return c.word == t; });
if (it != word_count.end()) {
it -> sum++;
} else {
word_count.push_back(counter(t));
}
}
return word_count;
}
Untested code.
You are not actually searching the std::list at all. On every loop iteration through the std::vector, you need to search the entire std::list from front to back, eg:
#include <string>
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
struct counter {
string word;
int sum = 1;
counter(const string &word): word(word) {}
};
list<counter> list_count(const vector<string> &text) {
list<counter> word_count;
for(const string &t: text) {
// perform an actual search here!
list<counter>::iterator it = find_if(
word_count.begin(), word_count.end(),
[&](counter &c){ return (c.word == t); }
);
if (it != word_count.end()) {
it->sum++;
} else {
word_count.emplace_back(t);
}
}
return word_count;
}
Live Demo
That being said, a std::list is a poor solution for counting elements. A better solution is to use a std::(unordered_)map instead (unless you need to preserve the order of the words found, which neither one will do), eg:
#include <string>
#include <map>
#include <vector>
using namespace std;
map<string, int> list_count(const vector<string> &text) {
map<string, int> word_count;
for(const string &t: text) {
word_count[t]++;
}
return word_count;
}
Live Demo (using std::map)
Live Demo (using std::unordered_map)
You are trying to use an inefficient approach. The standard class template list does not have random access to its elements. Each new element is appended to the end of the list. To find whether an element is already present in the list elements of it are traversed sequentially.
It would be much efficiently to use the standard container std::map . Moreover in this container words will be ordered.
For example you could declare
std::map<std::string, size_t> counters;
Nevertheless if you want to use the list then the function can look as it is shown in the demonstrative program below.
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <iterator>
#include <algorithm>
struct counter
{
std::string word;
size_t n = 0;
counter() = default;
counter( const std::string &word ): word( word ), n( 1 ){}
};
std::list<counter> list_count( const std::vector<std::string> &text )
{
std::list<counter> word_count;
for ( const auto &s : text )
{
auto it = std::find_if( std::begin( word_count ), std::end( word_count ),
[&s]( const auto &c ) { return c.word == s; } );
if ( it == std::end( word_count ) )
{
word_count.push_back( s );
}
else
{
++it->n;
}
}
return word_count;
}
int main()
{
std::vector<std::string> v { "first", "second", "first" };
auto word_count = list_count( v );
for ( const auto &c : word_count )
{
std::cout << c.word << ": " << c.n << '\n';
}
return 0;
}
Its output is
first: 2
second: 1
Pay attention to that the definition of the struct counter is redundant. You could use instead the standard class std::pair. Here you are.
#include <iostream>
#include <string>
#include <utility>
#include <list>
#include <vector>
#include <iterator>
#include <algorithm>
std::list<std::pair<std::string, size_t>> list_count( const std::vector<std::string> &text )
{
std::list<std::pair<std::string, size_t>> word_count;
for ( const auto &s : text )
{
auto it = std::find_if( std::begin( word_count ), std::end( word_count ),
[&s]( const auto &p ) { return p.first == s; } );
if ( it == std::end( word_count ) )
{
word_count.emplace_back( s, 1 );
}
else
{
++it->second;
}
}
return word_count;
}
int main()
{
std::vector<std::string> v { "first", "second", "first" };
auto word_count = list_count( v );
for ( const auto &p : word_count )
{
std::cout << p.first << ": " << p.second << '\n';
}
return 0;
}
If to use std::map then the function will look very simple.
#include <iostream>
#include <string>
#include <vector>
#include <map>
std::map<std::string, size_t> list_count( const std::vector<std::string> &text )
{
std::map<std::string, size_t> word_count;
for ( const auto &s : text )
{
++word_count[s];
}
return word_count;
}
int main()
{
std::vector<std::string> v { "first", "second", "first" };
auto word_count = list_count( v );
for ( const auto &p : word_count )
{
std::cout << p.first << ": " << p.second << '\n';
}
return 0;
}
Using of the list will be efficient only in the case when the vector of strings is sorted.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <list>
#include <vector>
struct counter
{
std::string word;
size_t n = 0;
counter() = default;
counter( const std::string &word ): word( word ), n( 1 ){}
};
std::list<counter> list_count( const std::vector<std::string> &text )
{
std::list<counter> word_count;
for ( const auto &s : text )
{
if ( word_count.empty() || word_count.back().word != s )
{
word_count.push_back( s );
}
else
{
++word_count.back().n;
}
}
return word_count;
}
int main()
{
std::vector<std::string> v { "A", "B", "B", "C", "C", "C", "D", "D", "E" };
auto word_count = list_count( v );
for ( const auto &c : word_count )
{
std::cout << c.word << ": " << c.n << '\n';
}
return 0;
}
Its output is
A: 1
B: 2
C: 3
D: 2
E: 1

Deleting empty elements from vector

I am trying to delete empty entries from std::vector. Here is a sample code, but something is wrong here.
#include <iostream>
#include <string>
#include<vector>
#include <cctype>
int main()
{
std::vector<std::string> s1 = {"a"," ", "", "b","c"," ","d"};
for (auto it = s1.begin(); it != s1.end() && isspace(*it); )
{
it = s1.erase(it);
}
std::cout<<"vector size = "<<s1.size();
for (auto &i:s1)
std::cout<<i<<"\n";
}
I am running a for loop to find out empty elements and deleting from there. There should be STL method too, but not sure how it will work.
It seems you mean the following
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<std::string> v = { "a", " ", "", "b", "c", " ", "d" };
auto is_empty = []( const std::string &s )
{
return s.find_first_not_of( " \t" ) == std::string::npos;
};
v.erase( std::remove_if( std::begin( v ), std::end( v ), is_empty ), std::end( v ) );
for ( const auto &s : v )
{
std::cout << "\"" << s << "\" ";
}
std::cout << std::endl;
return 0;
}
The program output is
"a" "b" "c" "d"
As for your code then it is inefficient because you are trying to remove each found element separately and this loop for example
for (auto it = s1.begin(); it != s1.end() && isspace(*it); )
{
it = s1.erase(it);
}
can iterate never because the first element is not satisfies the condition isspace(*it) that moreover is invalid. That is you are supplying an object of the type std::string to a function that expects an object of the type char (more precisely of the type int).
If to use the C function isspace then the program can look the following way.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cctype>
int main()
{
std::vector<std::string> v = { "a", " ", "", "b", "c", " ", "d" };
auto is_empty = []( const std::string &s )
{
return std::all_of( std::begin( s ), std::end( s ),
[]( char c )
{
return std::isspace( ( unsigned char )c );
} );
};
v.erase( std::remove_if( std::begin( v ), std::end( v ), is_empty ), std::end( v ) );
for ( const auto &s : v )
{
std::cout << "\"" << s << "\" ";
}
std::cout << std::endl;
return 0;
}
The program output is the same as shown above.

Replace a loop to count the number elements matching a criteria

Could we replace a loop with a strcmp by something easier to read, something similar to the C# extension methods?
I maintain legacy C++ and wonder how to start a transition to a more modern C++ and there is profusion of code that looks like this one:
int numberOfPipe = 10;
char* collection[5] = { "pompe","pipe","turbine","pompe", "pipe" };
// Count the pipes in the collection
int nPipeFound = 0;
int nPipe = 5;
for (int idx = 0; idx < nPipe; idx++)
{
if (strcmp(collection[idx], "pipe") == 0)
nPipeFound++;
}
cout << nPipeFound << endl;
Use the standard library:
Use std::count and use the std::string comparison.
#include <algorithm>
#include <iostream>
#include <string>
int main() {
char const * collection[] = { "pompe","pipe","turbine","pompe","pipe" };
auto n_pipe_found = std::count( std::begin( collection ), std::end( collection ), std::string{"pipe"});
std::cout << n_pipe_found << '\n';
}
Use std::count_if and write a predicate which does C string comparison for you.
#include <algorithm>
#include <cstring>
#include <iostream>
int main() {
char const * collection[] = { "pompe","pipe","turbine","pompe","pipe" };
auto n_pipe_found = std::count_if( std::begin( collection ), std::end( collection ),
[](char const * a) { return std::strcmp(a,"pipe") == 0; } );
std::cout << n_pipe_found << '\n';
}
You could also use a predicate like [](std::string const& a) { return a == "pipe"; } and again make use of std::string comparison.
Use std::accumulate if you need more fine grained control over counting.
#include <numeric>
#include <iostream>
#include <string>
int main() {
char const * collection[] = { "pompe","pipe","turbine","pompe","pipe" };
auto n_pipe_found = std::accumulate( std::begin( collection ), std::end( collection ), int{0},
[](int a, std::string const& b) { return a + (b == "pipe"); });
std::cout << n_pipe_found << '\n';
}