Why am I getting a segmentation fault in this iterator? - c++

I'm writing a program that should look through a graph and calculate the minimum number of edges that need to be deleted to leave a forest where each connected group has an even number of vertices. I know how to solve the problem, but when I try and iterate through a list I get a segmentation fault and can't figure out why.
#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int N;
cin >> N;
int M;
cin >> M;
// matrix of adjacency list to hold node values
vector<list<int> > adjList(N, list<int>());
// find the number of children nodes each node has
int ui, vi;
for (int i = 0; i < M; i++) {
cin >> ui;
cin >> vi;
ui--;
vi--;
//cout << ui << " " << vi << endl;
adjList[ui].push_back(vi);
adjList[vi].push_back(ui);
//cout << "list length: " << adjList[ui].size() << endl;
}
//cout << "after for loop" << endl;
// count the number of nodes with even numbers of children
for (int i = 0; i <= M; i++) {
cout << i << "-> ";
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int edgesRemoved = 0;
for (int i = 0; i <= M; i++) {
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); ++it) {
int j = *it;
if (adjList[j].size() % 2 == 1) {
// delete vertex from current list
cout << "test" << endl;
adjList[i].erase(it);
// delete vertex on the other list
cout << "test" << endl;
cout << j << endl;
cout << *adjList[j].begin() << endl;
for (list<int>::iterator it2 = adjList[j].begin(); it2 != adjList[j].end(); ++it2) {
cout << *it2 << " ";
if (i == *it2) {
adjList[j].erase(it2);
}
}
edgesRemoved++;
}
}
}
cout << edgesRemoved << endl;
return 0;
}
After using cout statements to debug the program I figured out that the problem is here:
for (int i = 0; i <= M; i++) {
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); ++it) {
int j = *it;
if (adjList[j].size() % 2 == 1) {
// delete vertex from current list
cout << "test" << endl;
adjList[i].erase(it);
// RIGHT UNDER HERE
// vvvvvvvvvv
for (list<int>::iterator it2 = adjList[j].begin(); it2 != adjList[j].end(); ++it2) {
cout << *it2 << " ";
if (i == *it2) {
adjList[j].erase(it2);
}
}
edgesRemoved++;
}
}
}
I get a segmentation fault after the program creates an iterator that is meant to go through another list in the vector. I don't understand why though, the syntax is the same as the first for loop with another iterator going through the first list.
Here is an example of what happens after I type in the input of the digits that represent a tree, the program then prints the adjacency matrix and goes on to the actual calculation (this part works fine, it's the end result during calculation):
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
0-> 1 2 5
1-> 0 4 6
2-> 0 3
3-> 2
4-> 1
5-> 0 7
6-> 1
7-> 5 8 9
8-> 7
9-> 7
test
test
1
0
Segmentation fault

Erasing the item under the iterator invalidates the iterator; using it further results in undefined behavior, so anything could happen. The usual idiom for this sort of thing is:
std::list<int>::iterator it = adjList[i].begin();
while ( it != adjList[i].end() ) {
if ( *it == i ) {
it = adjList[j].erase( it );
} else {
++ it;
}
}
The erase function returns an iterator to the element immediately following the one which was removed.
This is valid for all sequence types, not just std::list.

You must not delete the current item in a list (the thing the iterator is pointing to) while you are iterating over it. You could do something like this:
adjList[j].erase(it2++);
However, afaik, it is considered best practice to neither shrink nor expand a list while iterating.

Related

Why is my code not working properly? Is there something in STL-list which I am forgetting?

This is my code:
#include <iostream>
#include <list>
using namespace std;
template <class T>
void display(list<T> l){
list<int>::iterator i;
for (i = l.begin(); i != l.end(); i++)
{
cout << *i << " ";
}
}
void enter(list<int> l){
list<int>::iterator i;
int index = 1;
for (i = l.begin(); i != l.end(); i++, index++)
{
// cout << "check" << endl;
cout << "Enter element at index " << index << endl;
cin >> *i;
}
}
int main(){
list<int> l;
display(l);
cout << endl;
l.push_front(1);
l.push_front(2);
l.push_front(3);
l.push_front(4);
l.push_front(5);
list<int> l2(3);
enter(l2);
display(l2);
cout << "EXE";
return 0;
}
The output of the following program is:
Enter element at index 1
1
Enter element at index 2
2
Enter element at index 3
3
0 0 0 EXE
Required Output:
Enter element at index 1
1
Enter element at index 2
2
Enter element at index 3
3
1 2 3 EXE
The issue is that you pass the list by value in enter. When you update the list with cin >> *i, you are updating a copy of l2 instead of the l2 declared in main().
If you would like to update the list you will need to pass by reference instead.
void enter(list<int>& l){
list<int>::iterator i;
int index = 1;
for (i = l.begin(); i != l.end(); i++, index++)
{
// cout << "check" << endl;
cout << "Enter element at index " << index << endl;
cin >> *i;
}
}

Debug assertion failed with list

Hello everybody can you help me?
the problem is that when a person enters a element from list he can insert before this element elements from another list, but I constantly knock out mistakes. Maybe someone will help?
It looks like:
3 6 7 9
user enters 6
he can create another list like 8 7 5
and output is 3 8 7 5 6 7 9
The error
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
int main()
{
int size
int size1;
int el1;
int znach=0;
cout << "Enter size: " << endl;
cin >> size;
list<int>lis;
list<int>lis1;
list <int> ::iterator it;
int s = lis.size() / 2;
auto it1 = lis.begin();
advance(it1, s);
for (int i = 0; i <size; i++)
{
cout << "Enter " << i << " element: ";
cin >> t;
lis.push_back(t);
}
cout << "Enter element: " << endl;
cin >> el1;
for (it = lis.begin(); it != lis.end(); it++)
{
if (*it = el1)
{
znach++;
}
}
if (znach == 0)
{
cout << "There is no element;" << endl;
}
else
{
cout << "Enter size of new vector: " << endl;
cin >> size1;
for (int i = 0; i < size1; i++)
{
int t1;
cout << "Enter " << i << " element: ";
cin >> t1;
lis1.push_back(t1);
}
auto it2 = lis.begin();
while (*it2 != el1)
{
it2++;
}
--it2;
lis.splice(it2, lis1);
}
for (it = lis.begin(); it != lis.end(); it++)
{
cout << *it<<" ";
}
}
I don't know what your code is doing, and maybe there are other problems. However, the runtime error you get is caused by
auto it2 = lis.begin();
while (*it2 != el1)
{
it2++;
}
--it2;
When *lis.begin() == el1 then you never increment it2 and then decrement it, but you cannot decrement the begin iterator. Usually thats just undefined, but as you compiled a debug build you got an assertion fired up that tells you what went wrong.

Breaking a loop when entering a specific number?

How would I break a loop when the user enters 0 after entering a series of numbers? For this project I am trying to read the amount of time a number comes up.
Example: if the user enter 1 5 6 9 8 7 1 3 5
then the program would go
1 appeared 2 times
5 appeared 2 times
6 appeared 1 time
... and so on,
Another question I have is, how do I only print the elements that the user inputs instead of printing all elements?
I really appreciate any help. Thanks!
#include <iostream>
using namespace std;
void nums(int[]);
int main() {
cout << "Enter the however much numbers between 1-100 that you want, when you are done type 0 to finish: " << endl;
int myarray[100] = { 0 };
for (int i = 0; i < 100; i++) {
cin >> myarray[i];
if (myarray[i] == 0) {
break;
}
}
nums(myarray);
system("pause");
return 0;
}
void nums(int myarray[]) {
for (int i = 0; i < myarray[i]; i++) {
cout << myarray[i] << " "; //This code only prints out all the elements if the user inputs numbers in order. How do I get it to print out the elements the user inputs?
}
}
I used the indexes of each element to hold actual value and and the count as value of that index, hope it help :
#include <iostream>
#include <vector>
int main() {
//create a vector with size 100
std::vector<int> numberVector(100);
//init all elements of vector to 0
std::fill(numberVector.begin(), numberVector.end(), 0);
int value;
std::cout << "Enter the however much numbers between 1-100 that you want, when you are done type 0 to finish: " << std::endl;
while (true) {
std::cin >> value;
//braek if 0
if (value == 0) {
break;
}
//++ the value of given index
++numberVector.at(value);
}
//for all elements of the vector
for (auto iter = numberVector.begin(); iter != numberVector.end(); ++iter) {
//if the count of number is more than 0 (the number entered)
if (*iter > 0) {
//print the index and count
std::cout << iter - numberVector.begin() << " appeared " << *iter << " times\n";
}
}
//wait for some key to be pressed
system("pause");
return 0;
}
EDIT : If your are not using c++1z, replace auto iter with std::vector<int>::iterator iter

Find Occurrences in Array

I Have to find the occurrences of every element in array.
So far My code is this
void Occurrences()
{
int numers[10], count = 0, i;
for (i = 0; i < 10; i++)
{
cout << "Enter Number";
cin >> numers[i];
}
for (i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (numers[i] == numers[j])
{
count++;
}
}
cout << numers[i] << " is Occur " << count << " Time in Array" << endl;
count = 0;
}
}
int main()
{
Occurrences();
}
Output is coming multiply same numbers i.e If I entered six 1 and 4 2's. Output is
1 is occur 6 time in array.
1 is occur 6 time in array.
1 is occur 6 time in array.
1 is occur 6 time in array.
1 is occur 6 time in array.
1 is occur 6 time in array.
2 is occur 4 time in array.
2 is occur 4 time in array.
2 is occur 4 time in array.
2 is occur 4 time in array.
But I want output like this:
1 is occur 6 time in array.
2 is occur 4 time in array.
How do I do this?
Since you tagged this C++11, I would use std::unordered_map:
void Occurrences()
{
std::unordered_map<int, int> occurrences;
// enter 10 numbers
for (int i = 0; i < 10; ++i) {
cout << "Enter Number";
int x;
cin >> x;
++occurrences[x]; // increment the count for x
}
// print results
for (const auto& pr : occurrences) {
std::cout << pr.first << " appears " << pr.second << " times." << std::endl;
}
}
Your problem is you're searching for items you've already output. you can skip those items if you sort the array first.
Just to be different, I'm going to tell you how to do this with your existing code, an array, and not a map.
read the values in the array.
sort the array.
enumerate the array, and ignore (but count) any elements matching the previous element. reset the counter when you discover a new element.
thats it.
Example:
#include <iostream>
#include <algorithm>
void Occurrences()
{
int numers[10], i;
for (i = 0; i < 10; ++i)
{
std::cout << "Enter Number";
if (!(std::cin >> numers[i]))
break;
}
// sort the array in ascending order , O(NlogN)
std::sort(numers, numers+i);
for (const int* it = numers; it != numers+i;)
{
unsigned int count = 1;
int value = *it;
for (++it; (it != numers+i) && *it == value; ++count, ++it);
std::cout << value << " occurs " << count << " times." << std::endl;
}
}
int main()
{
Occurrences();
}
Your Sample Run
Enter Number1
Enter Number1
Enter Number1
Enter Number1
Enter Number1
Enter Number1
Enter Number2
Enter Number2
Enter Number2
Enter Number2
1 occurs 6 times.
2 occurs 4 times.
No map required. if you choose to use a map, consider an unordered map (hash table) as it may produce better performance.
Best of luck.
Better store it in a map and display everything later.
void Occurrences()
{
int numers[10],count = 0,i;
std::map<int,int> mapCnt;
for(i =0;i<10;i++)
{
cout<<"Enter Number";
cin>>numers[i];
}
for( i = 0;i<10;i++)
{
for(int j = 0;j<10;j++)
{
if(numers[i] == numers[j])
{
count++;
}
}
mapCnt[numers[i]]=count;
count = 0;
}
// Print the map Here
typedef std::map<int,int>::iterator it_type;
for(it_type iterator = mapCnt.begin(); iterator != mapCnt.end(); iterator++) {
cout << iterator->first << " is Occur " << iterator->second << " Time in Array" << endl;
}
}
Looping through map https://stackoverflow.com/a/4844904/2466168
A variation from maandoo's code if you can process as your read the numbers in:
void Occurrences()
{
int i;
std::map<int,int> mapCnt;
for(i =0;i<10;i++)
{
int num;
cout<<"Enter Number";
cin>>num;
std::map< int, int >::iterator iter( mapCnt.find( num ) );
if( iter != mapCnt.end() )
mapCnt[num] = 1;
else
++( iter->second );
}
// Print the map Here
for( i = 0; i < mapCnt.size(); ++i )
std::cout << mapCnt[i].first << " occurs " << mapCnt[i].second << " times in array\n";
}

I want to output the unique item from specific c++ array

I have created a function to count the duplicate items in array .
And everything is fine . but I want to output the unique items only , and this is my problem .
My function:
void RepeatedCounter(int n){
int i, j, temp, count= 0;
int *Numbers = new int[n];
for(i=0;i<n;i++){
cout << "Enter the number (" << i+1 << "): ";
cin >> *(Numbers+i);
}
cout << "---------------------\n";
for(i=0;i<n;i++){
temp = *(Numbers+i);
for(j=0;j<n;j++){
if(temp == *(Numbers+j)){
++count;
}
}
if(*(Numbers+i+1) != temp)
cout << *(Numbers+i) << "= " << count << endl;
count= 0;
}
delete []Numbers;
}
Main function:
int Num_Of_Digits= 0;
cout << "How many numbers: ";
cin >> Num_Of_Digits;
RepeatedCounter(Num_Of_Digits);
Example:
Inputs
1
5
3
5
1
Wrong result (current output)
1= 2
5= 2
3= 1
5= 2
1= 2
What I want
1= 2
5= 2
3= 1
First of: read the user data into a proper dynamic container like a vector:
std::vector<int> v;
v.reserve(100);
while (true)
{
int n;
std::cout << "Enter the number: ";
if (!(std::cin >> n)) { break; }
v.push_back(n);
}
Second, make a histogram using a map:
std::map<int, unsigned int> histogram;
for (int i : v) { ++histogram[i]; }
Now output the count:
for (auto const & p : histogram)
{
std::cout << "The number " << p->first
<< " appears " << p->second << " times.\n";
}
This has been done for you.
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
int repeated_counter(int n){
std::vector<int> vec;
std::vector<int> uniques;
int t;
for(int i=0; i!=n; ++i)
{
std::cin >> t;
vec.push_back(t);
}
std::sort(vec.begin(), vec.end());
std::unique_copy(vec.begin(), vec.end(),
std::back_inserter(uniques));
for(std::vector<int>::iterator it=uniques.begin();
it!=uniques.end();
++it)
{
std::cout << *it << "="
<< std::count(vec.begin(), vec.end(), *it) << "\n";
}
return 0;
}
please refrain from newing memory like you have done it is worse in every way to using a vector.
http://www.sgi.com/tech/stl/unique_copy.html
http://en.cppreference.com/w/cpp/container/vector
Try this,
for(i=0;i<n;i++){
count= 0;
temp = *(Numbers+i);
bool found = false;
for(j=0;j<n;j++){
if(temp == *(Numbers+j)){
++count;
}
}
for(j=i+1;j<n;j++) {
if(temp == *(Numbers+j)){
found = true;
}
}
if(found) continue;
if(*(Numbers+i+1) != temp)
cout << *(Numbers+i) << "= " << count << endl;
}
The problem is you are only checking against the next number in the list.
if(*(Numbers+i+1) != temp)
cout << *(Numbers+i) << "= " << count << endl;
What you should do is loop over the front on the list (until you get to the number you're on) and check to see if any of those numbers are the same as your current number and only print out if they aren't. You could also check the number before you started the count and not do it if the number has been done already.