So I have this code and it crashes xcode
void strrev(const std::string& str)
{
for(size_t i=str.length();i>=0;i--)
{
std::cout << str[i];
}
}
It works fine if I do i>0 but then the first character does not get printed
Any suggestions on what is wrong with i>=0 ?
Problem
i is of type size_t (it is an unsigned integral), so when i is zero and i-- is performed, its value wraps around, getting i the highest possible value it can store. This i is then used in the expression str[i] causing a crash.
Solution
You can separately handle the case for i equal to zero. Also, since indices start at zero, the highest possible index is str.length()-1.
It should be then:
for(size_t i=str.length()-1; i > 0; i--)
std::cout << str[i];
std::cout << str[0];
Recommended alternatives
Consider using reverse iterators instead to avoid having to deal with indices:
void strrev(const std::string& str)
{
for (auto rit = str.rbegin(); rit != str.rend(); ++rit)
std::cout << *rit;
}
Note that you can also use std::copy in combination with reverse iterators and a std::ostream_iterator object for std::cout:
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
void strrev(const std::string& str)
{
std::copy(str.rbegin(), str.rend(),
std::ostream_iterator<std::string::value_type>{std::cout});
}
or directly use std::reverse_copy instead of std::copy and therefore no need for reverse iterators:
std::reverse_copy(str.begin(), str.end(),
std::ostream_iterator<std::string::value_type>{std::cout});
It's better to do this in an idiomatic, index-free way using std::reverse.
#include <algorithm>
#include <iostream>
#include <string>
int main() {
std::string str = "Hello World!";
std::reverse(str.begin(), str.end());
std::cout << str << "\n"; // !dlroW olleH
}
Since the strings in c++ are base zero -the first character in a string is str[0]- therefor the index of the last character in a c++ string is always str.length()-1 or str.size()-1
So it should be
void strrev(const std::string& str)
{
for(size_t i=str.length()-1;i>=0;i--)
{
std::cout << str[i];
}
}
Related
well I was doing this problem from leetcode " https://leetcode.com/problems/valid-palindrome/ " and to remove the punctuations I used this
for (auto i:s)
{
if (ispunct(i))
{
s.erase(remove(s.begin(), s.end(), i), s.end());
continue;
}
}
but when it runs it leaves some punctuation characters in the string like this:
ip-> "Marge, let's "[went]." I await {news} telegram."
op-> "margelets[wentiawaitnewstelegram"
Modifying a string (or any other collection) while looping over it is a poor idea. Your iterator into the string is based on the state of the string at the beginning of your loop. Changing the state of the string inside the loop may lead to unexpected behavior of your iterator.
Rather you may want to create a new string without the offending characters.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string s1 = "Hello world!";
std::string s2;
std::copy_if(s1.begin(), s1.end(),
std::back_inserter(s2),
[](auto ch) { return !std::ispunct(ch); });
std::cout << s2 << std::endl;
return 0;
}
I have a function that reads a file to find a certain word. The system I currently have however searched for a specific word and isn't case sensitive. I can't simply use .find("word" && "Word")
As far as I can tell, the easiest way to do this would be with a vector with both versions of the word inside for the function to look for both however I can't figure out how to pass the vector into the function.
Any help would be appreciated. Thanks
You may just call find for every possible word in your vector. But i would suggest to use only lowercase if possible
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
std::string str = "HeLlo WorLd";
std::vector<std::string> vec{ "HELLO","HeLlo","hEllO","WORLD","WorLd" };
std::for_each(vec.begin(), vec.end(), [&](const std::string& comp)
{
auto found = str.find(comp);
if (found != std::string::npos)
std::cout << "Found World " << comp << " in str at " << std::distance(str.begin(), str.begin() + found) << std::endl;
});
return 0;
}
In c++ you can pass the vector to a function as a reference or absolute value. To pass as the reference, You can follow this approach.
int fun(std::vector<std::string>& arr) {
int value = 0;
// your operation
return value;
}
int main() {
std::vector<std::string> arr;
// your logic
int value = fun(arr);
return 0;
}
I am attempting to iterate over a string to check for punctuation. I've tried to use ispunct() but am receiving an error that there is no matching fucntion for call to ispunct. Is there a better way to implement this?
for(std::string::iterator it = oneWord.begin(); it != oneWord.end(); it++)
{
if(ispunct(it))
{
}
}
Is there a better way to implement this?
Use std::any_of:
#include <algorithm>
#include <cctype>
#include <iostream>
int main()
{
std::string s = "Contains punctuation!!";
std::string s2 = "No puncuation";
std::cout << std::any_of(s.begin(), s.end(), ::ispunct) << '\n';
std::cout << std::any_of(s2.begin(), s2.end(), ::ispunct) << '\n';
}
Live Example
it is an iterator; it points to a character in a string. You have to dereference it to get the thing it points to.
if(ispunct(static_cast<unsigned char>(*it)))
for (vector<int>::const_iterator i = vec.begin(); i != vec.end(); ++i)
{
int number = *i;
char* c;
itoa(number, c, 10);
result += c;
}
std::cout << result << std::endl;
I'm trying to convert each int in "vec" to a char and adding it to a string but I just get a compiler error. what am I doing wrong?
You can use the std::to_string available in C++11:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<int> vec;
for (int i = 0; i < 100; i++)
{
vec.push_back(i);
}
std::string result;
for (std::vector<int>::const_iterator i = vec.begin(); i != vec.end(); ++i)
{
result += std::to_string(*i);
}
std::cout << result << std::endl;
}
Combining sounds like a job for std::accumulate.
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
auto main() -> int
{
const std::vector<int> vec{ 1, 2, 3 };
const std::string result = std::accumulate(vec.begin(), vec.end(), std::string(),
[](const std::string& s, const int value)
{
return s + std::to_string(value);
});
std::cout << result << std::endl;
}
There's an error in your code:
You call itoa() with a non-initialized char pointer. That's bad, because itoa() needs a valid buffer! Besides, itoa() is not part of the c++ standard.
Better do leave char* behind and do it with more modern C++ features, especially std::stringstream, which is a string builder, which is powerful in conversion (and also often faster than the string += operator). It builds a string by pushing elements to it with the << operator (these can be string literals, strings, numbers of all kinds), it can be extended via external operators for own data types, and it also has a lot of formatting options (e.g. number of digits, hex etc), and returns its built string with the method str().
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::vector<int> vec;
for (int i = 0;i<100;i++)
vec.push_back(i);
std::stringstream ss;
for (auto& number : vec)
ss << number;
std::cout << ss.str() << std::endl;
}
The code is from C++ primer(3 third).
The error is :
*filterString.cpp: In function ‘int main()’:
filterString.cpp:32:68: error: cannot convert ‘__gnu_cxx::__normal_iterator*, std::vector > >’ to ‘std::string* {aka std::basic_string}’ in initialization
pls help me analyse the error,
thanks.
code:
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
template <class InputIterator>
void filter_string(InputIterator first, InputIterator last, string filt_elems = string("\",?.")) {
for (; first != last; first++){
string:: size_type pos = 0;
while ((pos = (*first).find_first_of(filt_elems, pos)) != string::npos)
(*first).erase(pos, 1);
}
}
bool length_less (string s1, string s2) {
return s1.size() < s2.size();
}
int main() {
istream_iterator<string> input(cin), eos;
vector<string> text;
copy(input, eos, back_inserter(text));
string filt_elems("\",.?;:");
filter_string(text.begin(), text.end(), filt_elems);
int cnt = text.size();
string *max = max_element(text.begin(), text.end(), length_less);
int len = max->size();
cout << "The number of words read is " << cnt << endl;
cout << "The longest word has a length of " << len << endl;
cout << "The longest word is " << *max << endl;
return 0;
}
In line 32 ,
std::max_element(text.begin(), text.end(), length_less);
this function returns a forward iterator addressing the position of the first occurrence of the largest element in the range searched and not a string .
What you can do instead of this line:
string *max = max_element(text.begin(), text.end(), length_less);
you have to do this ,
//First find the index of the max_element , by subtracting the forward iterator you get from calling max_element from the iterator for first element .
int index=max_element(text.begin(), text.end(), length_less) - text.begin();
//And then find string stored on that index.
string *max = text.at(index);
This is interesting. Iterators behave much like pointers, but not exactly. In particular, you can't convert an iterator to a pointer.
However, you can change this code to use an iterator as a sort of string* pointer:
vector<string>::iterator max = max_element(text.begin(), text.end(), length_less);
That declares max to be not a pointer to a string, but an iterator into a vector of strings, which is what the max_element algorithm returns when applies to a vector of strings.
You can also use a pointer, but it's a bad habit. Just for testing the idea, you can:
string *max = &*max_element(text.begin(), text.end(), length_less);
The *max_element(...) returns a reference to the string the returned iterator points to (just like dereferencing a real pointer) and & creates a (string*) pointer to that string.
This invites trouble, since a structural modification of the vector could quietly invalidate that pointer. Subsequent use of the pointer would be treating "random" memory as a string object. Even worse, it might work during your testing and not fail until the software was shipped!
A decent implementation of iterators should detect the invalidation and throw an exception. A predictable fail is better than a random meltdown.
OK, so I went overboard. Here is what I think is a more modern solution using lambdas and auto. I leave it to others to decide if it is easier to understand.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <string>
#include <vector>
using namespace std;
template <class InputIterator>
void filter_string(InputIterator first, InputIterator last,
const string filt_elems = const string("\",?."))
{
for_each(first, last,
[filt_elems](string& s)
{
s.erase(
// Shift valid characters up before erasing the undesirable
remove_if(s.begin(), s.end(),
[filt_elems](string::value_type c)
{ return filt_elems.find_first_of(c) != string::npos; }),
s.end());
});
}
int main()
{
istream_iterator<string> input(cin);
istream_iterator<string> eos;
vector<const string> words;
copy(input, eos, back_inserter(words));
const string filt_elems("\",.?;:");
filter_string(words.begin(), words.end(), filt_elems);
const int count = words.size();
// Get a reference to the longest word
const auto& max_word = *max_element(words.cbegin(), words.cend(),
[](const string& lhs, const string& rhs)
{ return lhs.size() < rhs.size(); });
const int length = max_word.size();
cout << "The number of words read is " << count << endl;
cout << "The longest word has a length of " << length << endl;
cout << "The longest word is " << max_word << endl;
return 0;
}