Equal Strings in C++ - c++

I am reversing a string and comparing it to another string whether it matches or not.
String d is reversed correctly, but in the If statement, it is not comparing. Strings comparing like this usually works I have done it before. Can someone explain this?
Thank You
int main()
{
string a, d, e;
int b, c;
cin >> a >> e;
for (int i = a.size(); i >= 0; i--)
{
d.push_back(a[i]);
}
cout << d;
if (d == e)
cout << "YES";
else
cout << "NO";
return 0;
}

If a string is 4 characters long, then s[4] will give you 1 past the end of the string. So here:
for (int i = a.size(); i >= 0; i--)
when you use i which would be 4 in the first step, you are accessing past the end of the string. You could do:
for (int i = a.size() - 1; i >= 0; i--)
but be careful if a is empty! You will underflow the integer and end up with big problems! You could check for empty string at the top of your function but that is extra work. To avoid this problem, you could use an iterator, but these only go forward :( Oh wait, reverse_iterator!
for (auto rit = s.rbegin(); rit != s.rend(); ++rit) {
d.push_back(*rit);
This will solve the problem. You could wrap this up in a function, call it reverse! Luckily, this actually exists: std::reverse:
a = d;
std::reverse(std::begin(d), std::end(d));
Easy peasy

Note that the i = a.size() when used in d.push_back(a[i]); will lead to undesired subscript access (recall that indexing starts with 0, while size() returns the amount of elements in a container).
You should look toward this implementation:
#include <string>
#include <iostream>
int main()
{
std::string a, d, e;
int b, c;
std::cin >> a >> e;
for (auto i = a.rbegin(); i != a.rend(); ++i) // Using return iterators
{
d.push_back(*i); // Dereference the iterator and push_back() it
}
std::cout << d << std::endl;
if (d == e)
std::cout << "YES" << std::endl;
else
std::cout << "NO" << std::endl;
return 0;
}
Example:
foo
oof
oof
YES
This approach uses reverse iterators on the string. Note, in order to advance this type of iterator, you use the same increment operation, only in this case, the iterator goes backwards (from the end of container to beginning).

The issue is that you accessing the NUL terminator of a, and putting that at the start of d. The behaviour of your program was undefined up to but not including C++11.
Using
a = d;
std::reverse(std::begin(d), std::end(d));
is the solution. Alternatives such as character by character access are poor due to the potential pitfalls with using unsigned arithmetic. Using the C++ standard library can also help your compiler in its optimisation choices.

Rather than reversing the string then comparing, you could compare the strings using std::equal:
bool result = std::equal(a.rbegin(), a.rend(),
d.begin(), d.end());

If all you want is to check if the string is a palindrome, you don't need to allocate a new string. Here's a much more efficient way:
#include <algorithm>
#include <string_view>
[[nodiscard]] constexpr bool IsPalindrome(std::string_view const str) noexcept {
auto begin = str.begin();
auto mid = begin + str.size() / 2;
return std::equal(begin, mid, str.rbegin());
}

The usual idiom for writing a loop is to start at the beginning and stop when you've passed the last element. With an index it looks like this:
for (int i = 0; i < a.size(); ++i) {
// do something with a[i]
}
Note that the terminating condition becomes true when i goes off the end.
To do that when you want to go in the other direction you have two choices:
for (int i = a.size(); i > 0; --i) {
// do something with a[i - 1]
}
In this case, the element we're interested in is a[i - 1]. The loop starts with the topmost element, when i is a.size(), and stops after the last element, when i becomes 0 and accessing a[i - 1] would be off the end.
That's a bit tricky to visualize, so you might be tempted to write it like this instead:
for (int i = a.size() - 1; i >= 0; --i) {
// do something with a[i]
}
This version has a subtle bug, and should not be your usual approach. The problem is that a.size() is unsigned. When a is empty, a.size() is 0, and a.size() - 1 wraps around and becomes a very large value. So don't use it.
Another way to avoid problems like this is to use iterators, which handle the details of recognizing the beginning and end of the sequence:
for (auto iter = std::begin(a); iter != std::end(a); ++iter) {
// do something with *iter
}
This is easily adapted to reverse iteration:
for (auto iter = std::rbegin(a); iter != std::rend(a); ++iter) {
// do something with *iter
}
And yet another possibility is to let the standard library handle the iteration:
void do_someting_with_a_sub_i(int) {
// whatever
}
std::for_each(std::begin(a), std::end(a), do_someting_with_a_sub_i);
or, in reverse,
std::for_each(std::rbegin(a), std::rend(a), do_someting_with_a_sub_i);
(yes, modern fashion calls for using a lambda instead of writing out do_something_with_a_sub_i. Sigh.)

Related

How can I iterate through the last element of the vector without going out of bounds?

The expected output is 1a1b1c but I only get 1a1b If I try putting '-1' next to input.size() in the for loop but that will just ignore the bug. What I'm looking for is that I want to be able to iterate through the last member of the string without going out of bounds.
std::string input = "abc";
for (unsigned int i = 0; i < input.size(); i++){
int counter = 1;
while(input.at(i) == input.at(i+1) && i < input.size()-1){
counter++;
i++;
}
number.push_back(counter);
character.push_back(input.at(i));
}
Few points for you to consdier:
1: for (unsigned int i = 0; i < input.size(); i++) specifically i++. This is a postfix operation meaning it returns i then increments the value of i. Not as big a deal here with integers but with iterators this can get very expensive as you create a copy of the iterator each time. Prefer to say what you mean / what you actually want, which is to increment i, not get a copy of i and increment i afterwards. So prefer ++i which only increments i and does not make a copy.
2: unsigned int i = 0 Firstly its better than using an int which has a signed -> unsigned conversaion every comparison with input.size() which returns a size_t. Secondly unsigned int is not guaranteed to be big enough to hold the size of the string and requires a promotion from (probably) 32 bit -> 64 bit unsigned to compare with size_t
3: cognitive complexity, nested loops which both mutate the same invariant (in this case i) makes the code more difficult to reason about and will ultimately lead to more bugs as code evolves over time. where possible only have one place where a loop invariant is mutated.
4: As pointed out by others the while loop while(input.at(i) == input.at(i+1) && i < input.size()-1) can exceed the size of the string and using the .at member function of string will throw for an out of bounds access. This can be simply resolved with point 3 by refactoring ther nested loop into a single loop.
5: Avoid so many calls to .at, we are in complete control of the index we use to index the string so you can use operator[] safely as long as we can guarantee i will always be a valid index which in this case i think you can.
6: i < input.size() using < when its not the check you want and its much more expensive than the check you actually want which is i != input.size(). Check out this trivial comparison in compiler explorer
Thankfully the fix from shadowranger Fixes your problem completely ie: while(i < s.size()-1 && s.at(i) == s.at(i+1)) However i would like to offer an alternitive with no nested loops to show you how to avoid my points 3,4, 5 and 6 :
void do_the_thing(std::string const& s) {
std::cout << "Considering: \"" + s + "\"\n";
if(s.empty()) {
return;
}
size_t const length = s.length(); // avoiding repeated calls to length which never changes in this case
if(length == 1) {
std::cout << "1" << s[0] << "\n";
return;
}
std::vector<unsigned> number;
std::vector<char> character;
// do the stuff your example did
char last = s[0];
unsigned same_count = 1;
for(size_t ii = 1; ii != length; ++ii) {
char const cur = s[ii];
if(cur == last) {
++same_count;
} else {
number.push_back(same_count);
character.push_back(last);
last = cur;
same_count = 1;
}
}
if(*s.rbegin() == last) {
number.push_back(same_count);
character.push_back(last);
}
// print the things or use them in some way
assert(number.size() == character.size());
size_t const out_len = character.size();
for(size_t ii = 0; ii != out_len; ++ii) {
std::cout << number[ii] << character[ii];
}
std::cout << "\n";
}

cant dereference out of range vector iterator- What's the problem?

I tried to realize factorial using vectors. Result's assumed to append the vector<int> Res
//corrected
vector<int> Res;
vector<int> Fact;
for(int i=1; i!=4; i++)
Fact.push_back(i);
int result=1;
for (auto i = Fact.rbegin(), auto e= Fact.rend(); i != e; ++i)
result *= *i;
Res.push_back(result);
The problem is in iterators. Exception: can't dereference out of range vector iterator.
I can't understand what's iterator out of range? Beg and End was defined after filling the Fact. So, what's the problem? I'm only the beginner, I must have missed some impotrant detail in this topic)
End is iterator to after the last element, you shouldn't dereference it (End-i is End when i is 0):
for (int i = 0; End != Beg; End--, i++)
result *= *(End-i);
I guess you need this:
for (; End != Beg; End--)
result *= *(End-1);
The easiest solution preserving semantics is to use reverse_iterator:
for (auto i = Fact.rbegin(), e = Fact.rend(); i != e; ++i)
result *= *i;
Alternatively, using accumulate:
result = std::accumulate(Fact.rbegin(), Fact.rend(), 0, [](int a, int b) { return a * b; })
Alternatively, with C++20 and ranges:
for (int i : std::ranges::reverse_view{Fact})
result *= i;
Alternatively, since multiplication is commutative, any of the above methods with forward iteration.
Alternatively, since multiplication by 0 yields 0 for any number and you start with 0:
result = 0;
end() returns "one past the last element". In your first pass,
i == 0, so "one past the end minus zero equals kaboom".
If you happen to know that you're dealing with a vector/contiguous memory, you can just someVec[length-n], so long as you know the result is a valid index (n <= 0 or n >= size would both be bad). For this code, I wouldn't use iterators at all.

Problems with vectors, how to remove the arrays in my vectors?

I have created a function that creates all the possible solutions for a game that I am creating... Maybe some of you know the bullcow game.
First I created a function that creates a combination of numbers of max four integers and the combination can't have any repeating number in it... like...
'1234' is a solution but not '1223' because the '2' is repeating in the number. In total there is 5040 numbers between '0123' and '9999' that haven't repeating numbers.
Here is my function:
std::vector <std::array<unsigned, 4>> HittaAllaLosningar(){
std::vector <std::array<unsigned, 4>> Losningar;
for (unsigned i = 0; i < 10; i++) {
for (unsigned j = 0; j < 10; j++) {
for (unsigned k = 0; k < 10; k++) {
for (unsigned l = 0; l < 10; l++) {
if (i != j && i != k && i != l && j != k && j != l && k != l) {
Losningar.push_back({i,j,k,l});
}
}
}
}
}
return Losningar;
}
Now let's say I have the number '1234' and that is not the solution I am trying to find, I want to remove the solution '1234' from the array since that isn't a solution... how do I do that? have been trying to find for hours and can't find it. I have tried vector.erase but I get errors about unsigned and stuff... also its worth to mention the guesses are in strings.
What I am trying to do is, to take a string that I get from my program and if it isn't a solution I want to remove it from the vector if it exists in the vector.
Here is the code that creates the guess:
std::string Gissning(){
int random = RandomGen();
int a = 0;
int b = 0;
int c = 0;
int d = 0;
for (unsigned i = random-1; i < random; i++) {
for (unsigned j = 0; j < 4; j++) {
if (j == 0) {
a = v[i][j];
}
if (j == 1) {
b = v[i][j];
}
if (j == 2) {
c = v[i][j];
}
if (j == 3) {
d = v[i][j];
}
}
std::cout << std::endl;
AntalTry++;
}
std::ostringstream test;
test << a << b << c << d;
funka = test.str();
return funka;
}
The randomgen function is just a function so I can get a random number and then I go in the loop so I can take the element of the vector and then I get the integers of the array.
Thank you very much for taking your time to help me, I am very grateful!
You need to find the position of the element to erase.
std::array<unsigned, 4> needle{1, 2, 3, 4};
auto it = std::find(Losningar.begin(), Losningar.end(), needle);
if (it != Losningar.end()) { Losningar.erase(it); }
If you want to remove all the values that match, or you don't like checking against end, you can use std::remove and the two iterator overload of erase. This is known as the "erase-remove" idiom.
std::array<unsigned, 4> needle{1, 2, 3, 4};
Losningar.erase(std::remove(Losningar.begin(), Losningar.end(), needle), Losningar.end());
To erase from a vector you just need to use erase and give it an iterator, like so:
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
auto it = vec.begin(); //Get an iterator to first elements
it++; //Increment iterator, it now points at second element
it = vec.erase(it); // This erases the {4,3,2,1} array
After you erase the element, it is invalid because the element it was pointing to has been deleted. Ti continue to use the iterator you can take the return value from the erase function, a valid iterator to the next element after the one erased, in this the case end iterator.
It is however not very efficient to remove elements in the middle of a vector, due to how it works internally. If it's not important in what order the different solution are stored, a small trick can simplify and make your code faster. Let's say we have this.
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
vec.push_back({3,2,1,4});
To remove the middle one we then do
vec[1] = vec.back(); // Replace the value we want to delete
// with the value in the last element of the vector.
vec.pop_back(); //Remove the last element
This is quite simple if you have ready other functions:
using TestNumber = std::array<unsigned, 4>;
struct TestResult {
int bulls;
int cows;
}
// function which is used to calculate bulls and cows for given secred and guess
TestResult TestSecretGuess(const TestNumber& secret,
const TestNumber& guess)
{
// do it your self
… … …
return result;
}
void RemoveNotMatchingSolutions(const TestNumber& guess, TestResult result)
{
auto iter =
std::remove_if(possibleSolutions.begin(),
possibleSolutions.end(),
[&guess, result](const TestNumber& possibility)
{
return result == TestSecretGuess(possibility, guess);
});
possibleSolutions.erase(iter, possibleSolutions.end());
}
Disclaimer: it is possible to improve performance (you do not care about order of elements).

How to output a missing number in set in c++?

If I have a set in C++, and it contains numbers from 0 to n. I wish to find out the number that is missing from 1 to n and output that and if none of them is missing, then output the number (n+1).
For example, if the set contains, 0 1 2 3 4 5 6 7, then it should output 8
If it contains, 0 1 3 4 5 6, then it should output 2.
I made the following code for this, but it always seems to output 0. I dont know what is the problem.
set<int>::iterator i = myset.begin();
set<int>::iterator j = i++;
while (1)
{
if ( *(j) != *(i)+1 )
{
cout<<*(j)<<"\n";
break;
}
else
{
i++;
j++;
}
}
What is the problem? Thanks!
The problem is that you're advancing i:
set<int>::iterator i = myset.begin(); // <-- i points to first element
set<int>::iterator j = i++; // <-- j points to first element
// i points to second!
while (1)
{ // so if our set starts with {0, 1, ...}
if ( *(j) != *(i)+1 ) // then *j == 0, *i == 1, *i + 1 == 2, so this
// inequality holds
What you meant to do is have j be the next iterator after i:
std::set<int>::iterator i = myset.begin(), j = myset.begin();
std::advance(j, 1);
With C++11, there's also std::next():
auto i = myset.begin();
auto j = std::next(i, 1);
Or, alternatively, just reverse your construction:
std::set<int>::iterator j = myset.begin();
std::set<int>::iterator i = j++; // now i is the first element, j is the second
Or, lastly, you really only need one iterator:
int expected = 0;
for (std::set<int>::iterator it = myset.begin(); it != myset.end();
++it, ++expected)
{
if (*it != expected) {
std::cout << "Missing " << expected << std::endl;
break;
}
}
The easiest stuff: Use count() function of set to check whether an element is present in set or not.
The count() takes an integer argument: The number whose existence in the set is to be checked. If the element is present in set, count() returns a non zero value, else it returns 0.
For example:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> s;
//I insert 0 - 4 in the set.
for(int i=0;i < 5; ++i)
s.insert(i);
//Let 10 be the 'n'.
for(int i = 0; i < 10; ++i)
{
//If i is NOT present in the set, the below condition will be true.
if (!s.count(i))
cout<<i<<" is missing!\n";
}
}
One problem is that you access beyond the end of the set if the set is
dense, which is undefined behavior. Another is that you always output
an element in the set (*j, where j is an iterator into the set);
according to your description, what you want to output is a value which
isn't in the set.
There are a couple of ways of handling this. The simplest is probably
just to maintain a variable expected, initialized with 0 and
incremented each time. Something like the following.
int
firstAvailable( std::set<int> const& allocated )
{
int expected = 0;
for ( auto current = allocated.begin(), end = allocated.end();
current != end && *current == expected;
++ current ) {
++ expected;
}
return expected;
}
If you don't want to return 0 if the list isn't empty, but starts with
some other value, initialize expected with the first element of the
set (or with whatever you want to return if the set is empty).
EDIT:
Of course, other algorithms may be better. For this sort of thing, I usually use a bit map.
The problem with your original code has already been pointed out in the other answers. You're modifying i while assigning j. You can fix this by initializing the iterators as:
set<int>::iterator i = myset.begin();
set<int>::iterator j = i;
j++;
A more elegant solution is to take advantage of the fact that the sum of all values up to n is n * (n + 1) / 2. You can calculate the sum of the actual values, and subtract it from the full sum to obtain the missing value:
int findMissing(const std::set<int>& valSet) {
int valCount = valSet.size();
int allSum = (valCount * (valCount + 1)) >> 1;
int valSum = std::accumulate(valSet.begin(), valSet.end(), 0);
return allSum - valSum;
}
The big advantage of this approach is that it does not rely on using a container where iterators provide the values in sorted order. You can use the same solution e.g. on an unsorted std::vector.
One danger to look out for when using this approach is overflow. With 32-bit ints, it will overflow with approximately 2^16 values. It might actually still work if it overflows, particularly if you use unsigned instead of int, but I did not confirm that.
There's a similar approach that uses the XOR of all values instead of the sum, which does not have the problem with overflow.

Iterating over a vector in reverse direction

I need to iterate over a vector from the end to the beginning. The "correct" way is
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
{
//do Something
}
When //do Something involves knowing the actual index, then some calculations need to be done with rit to obtain it, like index = v.size() - 1 - (rit - v.rbegin)
If the index is needed anyway, then I strongly believe it is better to iterate using that index
for(int i = v.size() - 1; i >= 0; --i)
{
//do something with v[i] and i;
}
This gives a warning that i is signed and v.size() is unsigned.
Changing to
for(unsigned i = v.size() - 1; i >= 0; --i) is just functionally wrong, because this is essentially an endless loop :)
What is an aesthetically good way to do what I want to do which
is warning-free
doesn't involve casts
is not overly verbose
As you've noted, the problem with a condition of i >= 0 when it's unsigned is that the condition is always true. Instead of subtracting 1 when you initialize i and then again after each iteration, subtract 1 after checking the loop condition:
for (unsigned i = v.size(); i-- > 0; )
I like this style for several reasons:
Although i will wrap around to UINT_MAX at the end of the loop, it doesn't rely on that behavior — it would work the same if the types were signed. Relying on unsigned wraparound feels like a bit of a hack to me.
It calls size() exactly once.
It doesn't use >=. Whenever I see that operator in a for loop, I have to re-read it to make sure there isn't an off-by-one error.
If you change the spacing in the conditional, you can make it use the "goes to" operator.
There's nothing to stop your reverse_iterator loop also using the index as described in multiple other answers. That way you can use the iterator or index as needed in the // do the work part, for minimal extra cost.
size_t index = v.size() - 1;
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin();
rit != v.rend(); ++rit, --index)
{
// do the work
}
Though I'm curious to know what you need the index for. Accessing v[index] is the same as accessing *rit.
to be aesthetically pleasing! ;)
for(unsigned i = v.size() - 1; v.size() > i; --i)
I would prefer the reverse iterator variant, because it's still easy to interpret and allows to avoid index-related errors.
Sometimes you can simply use the BOOST_REVERSE_FOREACH, which would make your code look the following way:
reverse_foreach (int value, vector) {
do_something_with_the_value;
}
Actually speaking, you can always use foreach statements for these kinds of loops, but then they become a bit unobvious:
size_t i = 0;
foreach (int value, vector) {
do_something;
++i;
}
In C++20 one can use ranges (#include <ranges>)
//DATA
std::vector<int> vecOfInts = { 2,4,6,8 };
//REVERSE VECTOR (
for (int i : vecOfInts | std::views::reverse)
{
std::cout << i << " ";
}
or if it is required to save in a different variable.
//SAVE IN ANOTHER VARIABLE
auto reverseVecOfInts = std::views::reverse(vecOfInts);
//ITERATION
for (int i : reverseVecOfInts)
{
std::cout << i << " ";
}
Try out a do while :
std::vector<Type> v;
// Some code
if(v.size() > 0)
{
unsigned int i = v.size() - 1;
do
{
// Your stuff
}
while(i-- > 0);
}
Hi i think better way use iterator as you use in first sample and if you need get iterator index you can use
std::distance to calculate it, if i understand your question
loop condition i != std::numeric_limits<unsigned>::max() ... or use UINT_MAX if you think its to verbose.
or another way:
for(unsigned j=0, end=v.size(), i=end-1; j<end; --i, ++j)
or
for(unsigned end=v.size(), i=end-1; (end-i)<end; --i)
I think that:
for(unsigned i = v.size() - 1; i >= 0; --i)
is fine if you check
!v.empty()
earlier.
for (it = v.end()-1; it != v.begin()-1; --it)
{
}
The "goes to" operator definitely messes with my head.