I try execute code:
char* m[3] = {"123", "456", "789"};
for(char* st=*m; st!=0; st=*(m+1))
{
cout <<st;
}
but it hung up and print: 123456456456...
The loop you wrote is invalid
char* m[3]={"123","456","789"};
for(char* st=*m;st!=0; st=*(m+1))
{
cout <<st;
}
Expression *m has type char * and array m does not contain NULL pointer. So condition st!=0;
is wrong. And the pointer always will point the same element because expression st=*(m+1) gives always the second element of the array
Also take into account that the correct definition of the array will be
const char* m[3] = { "123", "456", "789" };
because it is an array of pointers to string literals and string literals may not be changed.
You could use simply the range based for statement
const char* m[3] = { "123", "456", "789" };
for ( const char* st : m )
{
cout <<st << std::endl;
}
Or you could use iterators in the loop. For example
const char* m[3] = { "123", "456", "789" };
for ( auto it = std::begin( m ); it != std::end( m ); ++it )
{
cout << *it << std::endl;
}
And you could use standard algorithm std::copy
#include <iostream>
#include <algorithm>
#include <iterator>
//,,,
const char* m[3] = { "123", "456", "789" };
std::copy( std::begin( m ), std::end( m ),
std::ostream_iterator<const char *>( std::cout, "\n" ) );
Stop using char* for strings immediately and start using std::string. The same goes for C-style arrays: start using std::array or std::vector. This will save you years of your life and unnecessary pain.
Just look at how beautiful this code is:
std::array<std::string, 3> m = {"123", "456", "789"};
for (auto& s : m)
std::cout << s;
and here's the live example.
Using the code you provided here is one way of doing it:
const char* m[3]={"123","456","789"};
const unsigned int element_count = sizeof(m) / sizeof(m[0]);
//not a nice to have sizeof here, but i used this to keep the code
// consistent with the code provided in the question
for( const char** st = m; st!= (m + element_count) ; st ++ )
{
cout << *st;
}
As you can see to iterate trough an array of char* elements you need to use a pointer to char* and therefore the type is char ** for the iteration variable st.
The code you has was an infinite loop because you assigned st with *(m+1) which is never equal to 0, in fact it's the second element every time.
However there are safer ways of using doing this, by using a std::vector for example:
std::vector<std::string> m = {"123", "456", "789"};
for (auto& st : m)
std::cout << st;
//or:
for(std::vector<std::string>::iterator i = m.begin(),e = m.end();i != e;i++)
std::cout << *i;
//or:
for(std::size_t i = 0;i < m.size() ;i++)
std::cout << m[i];
The problem is that you point a pointer to the same location in each iteration:
char* m[ 3]={ "123","456","789"};
for( char* st = *m; st != 0; st = *( m + 1))
// ^^^^^^^^^ <- this doesn't change,
// st points to *(m+1)
{
std::cout << st;
}
Also you should not use a non-const char * to point to a nonmodifiable string literal:
const char* m[ 3]={ "123","456","789"};
const unsigned int n = sizeof( m) / sizeof( m[ 0]);
for( const char** st = m; st != (m + n) ; st ++ )
{
cout << *st;
}
Even range - based iteration will work:
const char* m[ 3] = { "123", "456", "789" };
for ( const char* st : m )
{
std::cout << st << std::endl;
}
If for some reason you have to stick to simple iteration, this will also work:
const char* m[ 3]={ "123","456","789"};
const char* st;
int r = 0;
for( st = *m; r < 3; st = *( m+r))
{
std::cout << st << std::endl;
r++;
}
Please consider using a standard container, i.e std::vector or std::array. It will help you a lot, mainly in dynamic memory management.
std::vector< std::string> v = { "123", "456", "789"};
for ( auto& s : v)
std::cout << s;
This is the least intrusive solution:
char* m[4] = {"123", "456", "789", NULL};
for(char** st=m; *st!=0; st=(st+1))
{
cout <<*st;
}
Related
I need to double-loop through the characters of each string in a vector array and am getting stuck on how what the syntax would be to call each character of each element.
the vector [] operator will return std::string&, then you use [] operator of std::string to get the character (as char&).
std::vector<std::string> vec{"hello","world"};
std::cout<<vec[0][3];
as #RyanP commented, the method std::vector::at and std::string::at will preform boundry check and will throw an exception if you try to dereference an index which is bigger than the vector/string size.
try{
std::cout<<vec.at(0).at(3);
}
catch (std::exception& e){
//handle
}
As you need to iterate over string in a vector, ie use it multiple times, create a (const) reference:
std::vector<std::string> vec { "abc", "efg" };
for( size_t i = 0; i < vec.size(); ++i ) {
const auto &str = vec[i];
for( size_t j = 0; j < str.length(); ++j )
std::cout << str[j];
}
Otherwise you would have to write vec[i][j] multiple times, which is too verbose
Here are shown different approaches
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> v = { "Hello", "World" };
for ( const auto &s : v )
{
for ( auto c : s ) std::cout << c;
std::cout << ' ';
}
std::cout << std::endl;
for ( auto i = v.size(); i != 0; )
{
for ( auto j = v[--i].size(); j != 0; ) std::cout << v[i][--j];
std::cout << ' ';
}
std::cout << std::endl;
for ( auto it1 = v.begin(); it1 != v.end(); ++it1 )
{
for ( auto it2 = it1->rbegin(); it2 != it1->rend(); ++it2 ) std::cout << *it2;
std::cout << ' ';
}
std::cout << std::endl;
}
The program output is
Hello World
dlroW olleH
olleH dlroW
You can combine these approaches in various ways.
If you want to change a character in a string using the range-based for statement then you have to write the loops the following way
for ( auto &s : v )
{
for ( auto &c : s ) /* assign something to c */;
}
I need to implement a function in C++,
vector<string> generateSubstrings(string s),
that returns a vector of all substrings of a string. For example, the substrings of the string “rum” are the seven strings
“r”, “ru”, “rum”, “u”, “um”, “m”, “”.
The function has to be recursive and has to return the results as a vector.
Here is my code so far. It's only printing "r", "ru" and "rm". I'm having alot of trouble implementing this function. I've been working on this for the past few hours but I just can't figure out how to get it working as stated, so any help would be appreciated.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> generateSubstrings(string s, int num){
int index = num;
int SIZE = s.size();
vector<string> substrings;
if(index == s.size()){//BASE CASE
string temp = s.substr(index,1);
substrings.push_back(temp);
}
else{
for(int i = 0; i < SIZE; ++i){
string temp = s.at(index) + s.substr(i,i);
substrings.push_back(temp);
}
generateSubstrings(s, num + 1);
}
return substrings;
}
int main() {
vector<string> vec(20);
vec = generateSubstrings("rum", 0);
cout << endl << endl;cout << "PRINTING VECTOR" << endl;
for ( int i = 0; i<vec.size();++i){
cout << vec.at(i);
cout << endl;
}
cout << "DONE";
}
In your assignment there is written that the recursive function has to be declared like
vector<string> generateSubstrings(string s),
But you are trying to make another function recursive that declared like
vector<string> generateSubstrings(string s, int num);
So in any case your solution does not satisfy the requirement of the assignment.
The function can look the following way
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return {};
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
for ( const std::string &t : generateSubstrings( s.substr( 1 ) ) )
{
v.push_back( t );
}
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
Its output is
r
ru
rum
u
um
m
If you need also to include an empty string then you should change condition
if ( s.empty() ) return {};
in appropriate way. For example
if ( s.empty() ) return { "" };
Also in this case you should write
v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );
Also you can replace the loop in the shown function with method insert. For example
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return {};
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );
v.insert( v.end(), v2.begin(), v2.end() );
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
The program output will be the same as shown above.
Here is a program modification that includes an empty string in the vector.
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return { "" };
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );
v.insert( v.end(), v2.begin(), v2.end() );
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
Here's an answer using Python. It prints the correct result for "rum", but for "rumm" it prints two "m" substrings for obvious reasons:
def substrings(s):
result = []
if len(s) == 0:
result.append("")
if len(s) > 0:
result += substrings(s[1:])
for n in range(1,len(s)+1):
result.append(s[0:n])
return result
print substrings("rum")
print substrings("rumm")
The idea of the algorithm is the following: for "rum", the substrings are the substrings of "um" followed by "r", "ru" and "rum". For "um", the substrings are the substrings of "m" followed by "u" and "um". For "m", the substrings are the substrings of "" followed by "m". For "", the substrings are simply "". So, the final list is "", "m", "u", "um", "r", "ru", "rum".
Although this isn't C++, you should be able to translate the code to C++. But that may not necessarily be what you want as "rumm" has two "m" substrings. If you think that "rumm" should have only one "m" substring, please leave a comment and I'll post another answer.
First, you should pay attention about code indent.
Then, I don't look your code, I wrote some code to achieve your aim, as follow:
void generateSubstrings(string s, int num, vector<string> &sta)
{
if (num == s.size())
return;
auto b = begin(s) + num;
string temp = "";
temp += *b;
sta.push_back(temp);
b++;
while (b != end(s))
{
temp += *b;
sta.push_back(temp);
b++;
}
generateSubstrings(s, num + 1, sta);
}
I have some arrays of strings and a function that gets a string and return the type of it (the array that the string belongs to)
How can I do it with the best speed?
string arr1[] = {"a", "b", "c"};
string arr2[] = {"d", "e", "f"};
string arr3[] = {"g", "h", "i"};
string arr4[] = {"j", "k", "l"};
...
string getFamily(string input)
{
if(arr1.contains(input)
return "TYPE_1";
...
}
Thanks
This is not elegant, but if you want fast, you can make a prepared unordered_map to do the search which would be useful if this function will be called 100s of times (wasteful if rarely called). Ideally, you can make this container in a class object rather than a global variable and the return type an integral value rather than a string. This would produce a search of O(1) with the cost being in the hashing of the key. But I do not know enough of your requirements.
If you would rather call once, then do as Joachim Pileborg suggested and do a series of std::find calls until you get a hit.
#include <iostream>
#include <unordered_map>
#include <string>
std::unordered_map< std::string, std::string > g_map;
std::string arr1[] = {"a", "b", "c"};
std::string arr2[] = {"d", "e", "f"};
std::string arr3[] = {"g", "h", "i"};
std::string arr4[] = {"j", "k", "l"};
const char * map_value( const std::string & input )
{
std::unordered_map< std::string, std::string >::iterator iter( g_map.find( input ) );
return iter == g_map.end() ? "NOT FOUND" : iter->second.c_str();
}
int main( int argc, char ** argv )
{
// Build the map;
for( int i = 0; i < sizeof( arr1 ) / sizeof( std::string ); ++i )
g_map[arr1[i]] = "TYPE_1";
for( int i = 0; i < sizeof( arr2 ) / sizeof( std::string ); ++i )
g_map[arr2[i]] = "TYPE_2";
for( int i = 0; i < sizeof( arr3 ) / sizeof( std::string ); ++i )
g_map[arr3[i]] = "TYPE_3";
for( int i = 0; i < sizeof( arr4 ) / sizeof( std::string ); ++i )
g_map[arr4[i]] = "TYPE_4";
std::string input;
std::cout << map_value( "b" ) << std::endl;
std::cout << map_value( "z" ) << std::endl;
std::cout << map_value( "eb" ) << std::endl;
std::cout << map_value( "j" ) << std::endl;
std::cout << map_value( "f" ) << std::endl;
return 0;
}
Output:
TYPE_1
NOT FOUND
NOT FOUND
TYPE_4
TYPE_2
I have a std::vector<const char*> v vector fully initiated with strings. How do I copy it into an initialized void*?
int main() {
std::vector<const char*> v;
v.push_back("abc");
v.push_back("def");
void* b = malloc(6);
// how to copy v in to b?
}
Thank you
You can use the range based for statement. For example
void *p = b;
for ( const char *s : v )
{
size_t n = std::strlen( s );
std::memcpy( p, s, n );
p = ( char * )p + n;
}
The same can be done with standard algorithm std::accumulate declared in header <numeric>
For example
#include <iostream>
#include <vector>
#include <numeric>
#include <cstring>
int main()
{
std::vector<const char*> v;
v.push_back( "abc" );
v.push_back( "def" );
void *b = new char[6];
auto p = std::accumulate( v.begin(), v.end(), b,
[]( void *acc, const char *s ) -> void *
{
size_t n = std::strlen( s );
return ( ( char * )std::memcpy( acc, s, n ) + n );
} );
std::cout.write( (const char * )b , ( const char * )p - ( const char * )b );
std::cout << std::endl;
return 0;
}
The output is
abcdef
Take into account that it would be better to write
void* b = new char[6];
Iterate through the vector moving your pointer along by the string length each time.
int currentIndex = 0;
for(int i = 0; i < v.length(); i++) {
memcpy(b + currentIndex, v[i], strlen(v[i]));
currentIndex += strlen(v[i]);
}
Something like that, may not work I didn't test it.
And if you want to use b as a string, you need to put a 0 on the end.
try this :
std::vector<const char*> v;
v.push_back("abc");
v.push_back("def");
void* b = malloc(6);
int l = strlen(v[0]);
memcpy(b, v[0], l);
l = strlen(v[1]);
memcpy(b+l, v[1], l);
This is the most C++-like way I can think of. It doesn't use any C-style string manipulation or memory management functions and it is as safe as can be. Downside is that a temporary buffer is allocated and released without actual need.
The following headers are used in this example.
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
Now, the first version (which I prefer) allocates a buffer of the correct size and returns it wrapped in a std::unique_ptr<char[]> from which the caller can then extract the buffer and implicitly cast it to void * if needed.
std::unique_ptr<char[]>
concatenate(const std::vector<const char *>& words)
{
std::string buffer {};
std::unique_ptr<char[]> dup_uptr {};
for (const auto word : words)
buffer += word;
dup_uptr.reset(new char[buffer.size() + 1]);
buffer.copy(dup_uptr.get(), buffer.size());
dup_uptr.get()[buffer.size()] = '\0';
return dup_uptr;
}
The second version takes the destination buffer and its size as parameters and copies the concatenated string there. This can obviously fail if the buffer happens to be too small and it is also less safe since we might make a mistake and pass the wrong buffer size. For convenience, it returns a char * pointer to the string or a nullptr if the buffer was too small.
char *
concatenate(const std::vector<const char *>& words,
void *const dest,
const std::size_t size)
{
char * dest_chars = static_cast<char *>(dest);
std::string buffer {};
for (const auto word : words)
buffer += word;
// If we cannot copy the whole thing, copy nothing at all.
if (buffer.size() >= size)
return nullptr;
buffer.copy(dest_chars, buffer.size());
dest_chars[buffer.size()] = '\0';
return dest_chars;
}
The two functions can be used like this:
int
main()
{
const std::vector<const char*> vec {"abc", "def"};
// first version
{
auto concat = concatenate(vec);
std::cout << concat.get() << std::endl;
}
// second version
{
auto tempbuff = std::get_temporary_buffer<void>(100);
if (auto concat = concatenate(vec, tempbuff.first, tempbuff.second))
std::cout << concat << std::endl;
std::return_temporary_buffer(tempbuff.first);
}
return 0;
}
I have a small unsorted array and I'd like to find the index of a particular value. Does C++ have a built-in sequential search function for this, or do you just write the loop yourself each time it comes up?
I'm specifically using a C-style array like:
std::string arr[5] = { "EVEN", "ODD", "NONE", "MARK", "SPACE" };
and I need the index of a value that the user supplies.
Use std::find() from the STL-algorithm-library, or the find()-method of your particular container.
std::find() should work:
#include <stdio.h>
#include <algorithm>
#include <string>
using std::string;
std::string arr[5] = { "EVEN", "ODD", "NONE", "MARK", "SPACE" };
int main() {
string* pArrEnd = arr + sizeof( arr)/sizeof(arr[0]);
string* pFound = std::find( arr, pArrEnd, "MARK");
if (pFound == pArrEnd) {
printf( "not found\n");
}
else {
printf( "%s was found at index %d\n", pFound->c_str(), pFound - arr);
printf( "or using STL: %d\n", std::distance( arr, pFound));
}
return 0;
}
You can use STL algos on containers other than just STL containers. For example, you can std::find() in a C-style array:
// alloc the array
static const size_t numItems = 100000;
int * items = new int[numItems];
// fill the array
for( size_t n = 0; n < numItems; ++n )
items[n] = n;
// find 42 using std::find()
int* found = std::find(&items[0], &items[numItems], 42);
if( found == &items[numItems] )
{
// this is one past the end, so 42 was not found
items[0] = 42;
}
else
{
// we found the first instance of 42 at this location
// change it to 43
*found = 43;
}
I suppose you need the index and not the iterator.
int main()
{
// for c++ vector
typedef int Element;
typedef std::vector<Element> CppVector;
CppVector v;
v.push_back( 2 );
v.push_back( 4 );
v.push_back( 8 );
v.push_back( 6 );
const Element el = 4;
CppVector::const_iterator it = std::find( v.begin(), v.end(), el );
if ( it == v.end() )
{
std::cout << "there is no such element" << std::endl;
}
else
{
const CppVector::size_type index = it - v.begin();
std::cout << "index = " << index << std::endl;
}
// for C array
typedef Element CVector[4];
CVector cv;
cv[0] = 2;
cv[1] = 4;
cv[2] = 8;
cv[3] = 6;
const std::size_t cvSize = sizeof( cv ) / sizeof( Element );
std::cout << "c vector size = " << cvSize << std::endl;
const Element* cit = std::find( cv, cv + cvSize, el );
const std::size_t index = cit - cv;
if ( index >= cvSize )
std::cout << "there is no such element" << std::endl;
else
std::cout << "index = " << index << std::endl;
}
In addition to the STL possibility (std::find) already mentioned there is the POSIX function lsearch (with c semantics).