Iterator confusion using maps - c++

sorry because this question isn't really advanced, but I am having lots of trouble understanding why this program works the way it does.
#include <iostream>
#include <fstream>
#include <set>
#include <vector>
#include <map>
using namespace std;
int main() {
ofstream fout("castle.out");
ifstream fin("castle.in");
map<int, int, greater<int> > cnt;
map<int, int, greater<int> >::iterator x;
x = cnt.begin();
cnt[1] = 0;
cnt[2] = 7;
fout << x->first; //This outputs 2
x++;
fout << x->second;//This outputs 2 again, why not 0?
return 0;
}
So I defined a map called cnt, and then made an iterator for it x. I ordered it by greatest integer to least greatest integer. I set that iterator equal to x.begin(), and then I outputted the value of x, using first. But then I wanted to output the value 0, so I did one x++; and then tried to output the value of x->first. The idea behind this was that the iterator would increase by one and point to the next pair in my map, so then it would point to 1, which comes after the 2.
Why does it not work and give me 2 again?
I realized that if I do this instead:
x++;
x++:
fout << x-> first;
with two x++, I will have the value 1. Why is this? Thanks!

Your code has undefined behavior.
x = cnt.begin();
Sets x to begin() while the container is empty which effectively gives you the end() iterator. Since std::map::operartor[] doesn't invalidate any iterators you still have an end() iterator and dereferencing it is undefined behavior.

Related

Segmentation Fault in C++ - Vectors

#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a, b;
cin>>a;
vector<int> numbers;
for(int i=0; i<a; i++)
{
cin>>b;
numbers.push_back(b);
}
int c,d,e;
cin>>c;
numbers.erase(numbers.begin()+c-1);
cin>>d>>e;
numbers.erase(numbers.begin()+d-1, numbers.end()+e);
cout<<numbers.size();
for(int x : numbers)
cout<<x<<" ";
return 0;
}
Hello everyone,
I am learning c++ and writing a very simple program, but this code is giving "Segmentation Fault" as error. I really could not figure out why this is happening.
Thank you.
This line
numbers.erase(numbers.begin()+d-1, numbers.end()+e);
cannot be correct. Incrementing the end iterator never gets you a valid iterator. It is not quite clear what you want to do, but if you want to erase elements in the range of indices [d,e) then that would be
numbers.erase(numbers.begin()+d, numbers.begin()+e);
Note: No +1 needed on the first, because the first is inclusive. And you get an iterator to the e-th element by incrementing the begin iterator not the end iterator (well... I assume the common 0-based counting, ie the "first" element is the 0th element ;).
Also, as mentioned in comments, you should check if the user entered values are in range, before calling erase. erase does no bounds-checking. If you pass invalid iterators your get undefined behavior.

std::map find distance with iterators, program does not terminate

As I compile ( g++ -std=c++14 map.cpp ) and run this program, it doesn't seem to terminate. Can any one explain Why? However as I do find('a') instead of 'c' it gives a zero.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
map<char, float> m;
m['a'] = 3.4;
m['b'] = 5.3;
m['c'] = 33.3;
m['d'] = 43.;
auto it = m.find( 'c' );
cout << "distance : " << std::distance( it , m.begin() ) << endl;
}
Use
std::distance( m.begin(), it )
Otherwise the call
std::distance( it , m.begin() )
has undefined behavior because there is used an invalid range. Ranges in C++ are specified like [first, last ) where first precedes or equal to last. In the last case when first is equal to last the range is empty.
From the C++ Standard (27.4.3 Iterator operations)
4 Effects: If InputIterator meets the requirements of random access
iterator, returns (last - first); otherwise, returns the number of
increments needed to get from first to last.
std::distance(first,last) starts running from first and advances the iterator until it reaches the last. In your case this will never happen because it is most likely found after m.begin() so it'll loop forever. change the order of parameters given to std::distance
std::distance reference:
The behavior is undefined if last is not reachable from first by
(possibly repeatedly) incrementing first.

Erase all even numbers from vector using find_if [duplicate]

This question already has answers here:
Iterator invalidation rules for C++ containers
(6 answers)
Closed 5 years ago.
#include <iostream>
#include <vector>
#include <algorithm>
#include <time.h>
#include <iomanip>
using namespace std;
bool isEven(int n)
{
return n%2 == 0;
}
int main()
{
srand(time(NULL));
vector<int> myVec;
for(int i = 0; i < 20; i++)
{
myVec.push_back(rand() % 100);
}
while(1)
{
vector<int>::iterator q = std::find_if(myVec.begin(), myVec.end(), isEven);
cout << *q << endl;
if(q == myVec.end())
{
myVec.erase(q);
break;
}
else
myVec.erase(q);
}
return 0;
}
This code is giving segmentation fault. The above code is to remove all the even numbers from the vector using find_if and erase function
Please help. Any help will be highly appreciated.
EDIT: I have edited it to make sure that iterator will be valid always.
Still it is giving segmentation fault.
std::vector::erase invalidates all iterators to and after the point of erasure. You can't continue using that iterator, not to increment it, use it to access the vector, or even compare it to end().
The correct algorithm to use is std:remove_if. Unlike the name implies, it will only move all even items of the vector "to the back", without invalidating any iterators. It will return an iterator to the start of this sub-range, which you can then just feed to the appropriate erase overload (the one that accepts a pair of iterators).
This has been used so much in code that it's even named "the erase-remove idiom".
When using the erase(it); function the iterator changes so you need to set the iterator again to the new one returned by the erase function.
In your code, you are checking for the end if(q == myVec.end()) and then using erase this will throw an error as.end() does not point to data, and to be able to erase an item from the vector the iterator needs to be valid. So by changing if(q == myVec.end()) to if(q == (myVec.end()-1)) it will allow you to delete the last element in case of been a pair.

Segmentation fault while initializing vector by an initialized array in C++

I wanted to use the sort() in the algorithm library in C++. I could find examples for sorting vectors only, thus I am trying to initialize a vector by an initialized array. When executing I am getting a segmentation fault and couldn't figure out what is wrong here in the code I wrote.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n,k,packet[1000],min=0;
scanf("%d",&n);
scanf("%d",&k);
for (int i = 0; i < n; ++i)
{
scanf("%d",&packet[i]);
cout<<i<<endl;
}
cout<<"debug";
vector<int> packets(packet,packet+n);
vector<int>::iterator start,stop;
sort(packets.begin(),packets.begin()+n);
min=*(packets.begin())- *(packets.end());
cout<<min;
for (vector<int>::iterator it=packets.begin(); it!=packets.end()-k; ++it)
{
printf("%d ",*it );
if((*(it+k) - *it)<min)
{
start=it;
stop=it+k;
}
}
printf("%d\n",*stop- *start );
return 0;
}
*(packets.end())
packets.end() returns an iterator to the element, following the last element of the vector.
Attempting to derefenrence it causes Undefined Behavior.
The comments explain that you can use sort with an array just fine (if you look at http://en.cppreference.com/w/cpp/algorithm/sort you'll see that sort takes two arguments that: -RandomIt must meet the requirements of ValueSwappable and RandomAccessIterator.. Plain pointers fulfill this requirement).
In your example, the segfault happens because you try to dereference a valid but undereferencable iterator (the iterator returned by 'end()' in: min=*(packets.begin())- *(packets.end());. Basically it returns an iterator that points to after the last element of the vector. If you want to get an iterator to the last element, you can use rbegin() but of course you need to make sure that the vector is not empty first).
You could have seen this quite easily by running your code under a debugger, you'd see that the segmentation fault had nothing to do with the call to sort

std::vector and std::min behavior

Why following program is not returning minimum value as 1.
#include <vector>
#include <algorithm>
#include <iostream>
int main ( int argc, char **argv) {
std::vector<int> test;
test.push_back(INT_MAX);
test.push_back(1);
int min = *(std::min(test.begin(), test.end()));
std::cout << "Minimum = " << min << std::endl;
}
It returns minimum values as 2147483647
You could try this:
int min = *std::min_element(test.begin(), test.end());
std::min
Return the lesser of two arguments
Returns the lesser of a and b. If both are equivalent, a is returned.
std::min_element
Returns an iterator pointing to the element with the smallest value in the range [first,last). The comparisons are performed using either operator< for the first version, or comp for the second; An element is the smallest if no other element compares less than it (it may compare equal, though).
Be aware that std::vector<T>::end() does NOT give you an iterator to the last element. It returns an iterator pointing BEHIND the last element.
If you want to address the first and last element with iterator logic you need to use (test.begin(), test.end()-1).