ambiguous runtime error causing the program to crash immediately - c++

#include <bits/stdc++.h>
using namespace std;
int freq[101034];
int main() {
int n;
cin >> n;
set<int> st;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
freq[x]++;
st.insert(x);
}
while (!st.empty()) {
for (auto x : st) {
if (freq[x] <= 0) {
st.erase(x);
continue;
}
cout << x << ' ';
freq[x]--;
}
cout << '\n';
}
return 0;
}
The problem I have tried to solve: Given an array of integers n up to 10^5 and each element up to 10^5, the task is to print the array sorted without repetition, then delete the array elements that are printed, then repeat until the array is empty.
For instance if array [1, 1, 2, 3, 4, 4]
This should be printed
1 2 3 4
1 4
I maintained a frequency array to hold each element frequency and the code above causes runtime error. The program crashes. I've tried to remove the if statement, the program runs normally, but goes to infinite loop for sure! I really can't figure why the if causes runtime error.

The issue is in this snippet:
while (!st.empty()) {
for (auto x : st) {
if (freq[x] <= 0) {
st.erase(x);
continue;
}
cout << x << ' ';
freq[x]--;
}
cout << '\n';
}
The range-based for loop uses iterators in the back (see this for more details). When you erase x from st the loop iterator (pointing to x) becomes invalid (this means that you mustn't use it anymore), but in the snippet above, it still gets incremented at the end of the loop in the background, that result undefined behavior, hence the runtime error.
Take a look at this page to see how you should implement it properly. Applying the practice of the previous link to your code:
while (!st.empty()) {
for (auto it = cbegin(st); it != cend(st);) {
auto x = *it;
if (freq[x] <= 0) {
it = st.erase(it);
} else {
++it;
cout << x << ' ';
freq[x]--;
}
}
cout << '\n';
}

Related

Selection Sort Implementation with C++ incorrect

really new to C++, trying to instantiate some basic algorithms with it. Having trouble returning the correct result for selection sort. Here is my code
#include <iostream>
#include <array>
#include <vector>
using namespace std;
// Selection Sort :
int findMin(vector<int> &arr, int a)
{
int m = a;
for (int i = a + 1; i < arr.size(); i++)
{
if (arr[i] < arr[m])
{
m = i;
}
return m;
}
}
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
void selectionSort(vector<int> &arr)
{
if (!arr.empty())
{
for (int i = 0; i < arr.size(); ++i)
{
int min = findMin(arr, i);
swap(arr[i], arr[min]); // Assume a correct swap function
}
}
}
void print(vector<int> &arr)
{
if (!arr.empty())
{
for (int i = 0; i < arr.size(); i++)
{
cout << arr[i] << "";
cout << endl;
}
}
}
int main()
{
vector<int> sort;
sort.push_back(2);
sort.push_back(1);
sort.push_back(7);
sort.push_back(4);
sort.push_back(5);
sort.push_back(3);
print(sort);
cout << "this was unsorted array";
cout << endl;
cout << findMin(sort, 0);
cout << "this was minimum";
cout << endl;
selectionSort(sort);
print(sort);
}
I am getting the following results:
comparison_sort.cpp:20:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]
}
^
1 warning generated.
2
1
7
4
5
3
this was unsorted array
1
this was minimum
1
2
4
5
3
0
My question is: What is causing this control path error? Why is the "7" here being replaced with a "0"?
Thanks in advance! Sorry for the noob question.
I have reviewed all my current functions and nothing seems to explain why the 7 is replaced with a 0. I have tried multiple integers and it looks like the maximum number is always replaced.
The warning is very real, and it alludes to the problem that's breaking your sort as well.
You are currently returning m inside your loop body. What that means is that if the loop is entered, then the function will return m on the very first time around the loop. It only has a chance to check the first element.
And of course, if a is the last index of the array, then the loop will never execute, and you will never explicitly return a value. This is the "control path" which does not return a value.
It's quite clear that you've accidentally put return m; in the wrong place, and even though you have good code indentation, some inexplicable force is preventing you from seeing this. To fix both the warning and the sorting issue, move return m; outside the loop:
int findMin(vector<int> &arr, int a)
{
int m = a;
for (int i = a + 1; i < arr.size(); i++)
{
if (arr[i] < arr[m])
{
m = i;
}
}
return m;
}

Trouble Sort Google CodeJam 2018 Qualifiers

I am trying to improve my programming skills by solving couple of Code Jam questions. I have been stuck for a while on the "Trouble Sort" question from the Qualifier Rounds in 2018. My code produces the expected output with the example input in my console, but the online judge return "Wrong Answer".
Apparently Trouble sort is just like bubble sort, except instead of comparing the ith and i+1th elements, it compares the ith and i+2th elements and if the former is greater than the latter then the elements are swapped. The question says that this algorithm is flawed as arrays like 897 after trouble sort will return 798, which isn't sorted either. The task is to check if for a given list of integers, trouble sort is able to successfully sort the array or if it isn't then which is the index value of the first element that is out of place.
My code inputs the number of tests t and the size of integer list. Then I make a copy of it and put one copy through bubble sort and the other through trouble sort. Then I compare them element wise and if an index which has the two elements as different integers is found, it is outputted. I'm not sure what I am doing wrong here.
#include<iostream>
#include<vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
void swapVal(int& a, int& b)
{
int t = a;
a = b;
b = t;
}
int main()
{
int t;
cin >> t;
for (int i = 1; i <= t; i++)
{
int n;
cin >> n;
vector<int> bs(n);
vector<int> ts(n);
for (int i = 0; i < n; i++)
{
cin >> bs[i];
ts[i] = bs[i];
}
//bubbleSort(bs, n);
{
bool bsSorted = false;
while (!bsSorted)
{
bsSorted = true;
for (int i = 0; i < n - 1; i++)
{
if (bs[i] > bs[i + 1])
{
swapVal(bs[i], bs[i + 1]);
bsSorted = false;
}
}
}
}
//troubleSort(ts, n);
{
bool tsSorted = false;
while (!tsSorted)
{
tsSorted = true;
for (int i = 0; i < n - 2; i++)
{
if (ts[i] > ts[i + 2])
{
swapVal(ts[i], ts[i + 2]);
tsSorted = false;
}
}
}
}
bool same = true;
int minidx = 0;
for (int i = 0; i < n; i++)
{
if (bs[i] != ts[i])
{
same = false;
minidx = i;
break;
}
}
if (same == true)
{
cout << "Case #" << i << ": OK" << endl;
}
else if (same == false)
{
cout << "Case #" << i << ": " << minidx;
}
}
}
I am expecting the judge to give me a tick of approval, but instead it is repeatedly returning "Wrong Answer". What am I doing wrong here?
The algorithm looks correct to me. I noticed that in the false case you seem to be missing the newline. So two consecutive false statements will be on the same line.
cout << "Case #" << i << ": " << minidx<<'\n';
Might solve your problem.
Few remarks:
if (same == true) is equivalent to if(same) and if (same == false) to if(!same).
There's already std::swap.
Some people might not like nested for loops having equally named variables - the nested variable will hide the outer one.

Not able to find the reason for undefined behavior

In the following program, I declare a global variable (adj_matrix) for the purpose of using it in different functions. It is defined in another function (init_matrix).
I tested the program with the test case 3 1 2 and received a segmentation fault.
3 1 2
YES
Segmentation fault: 11
The surprising part is, that when I uncomment the cout line in the construct_matrix function, the segmentation fault disappears.
This looks like the case of undefined behavior to me but I'm unable to figure out why and where it occurs. Please help.
Following is the program:
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int> > adj_matrix;
void init_matrix(int size, int val)
{
adj_matrix.reserve(size);
for (int i = 0; i < size; ++i)
{
adj_matrix[i].reserve(size);
for (int j = 0; j < size; ++j)
{
if(i == j)
adj_matrix[i][i] = 0;
else
adj_matrix[i][j] = val;
}
}
}
void construct_matrix(int size, int k, int val)
{
// k denotes how many components we want
for (int i = k - 1; i < size - 1; ++i)
{
adj_matrix[i][i + 1] = val;
adj_matrix[i + 1][i] = val;
// Uncommenting the following line resolves the seg-fault error
// cout << i << endl;
}
}
void print_matrix(int size)
{
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
cout << adj_matrix[i][j];
cout << endl;
}
}
int main()
{
int n, a, b;
cin >> n >> a >> b;
/*
The solution uses the fact that atleast one of G or G complement is always connected.
In cases where we have to show both are connected (not possible when n is 2 or 3),
we draw a simple graph connected v1 v2 v3...vn. The complement will be also connected (n != 2 and 3)
*/
if(a == 1 && b == 1)
{
if(n == 2 || n == 3)
cout << "NO" << endl;
else
{
cout << "YES" << endl;
init_matrix(n, 0);
construct_matrix(n, 1, 1);
print_matrix(n);
}
}
else if(a == 1)
{
cout << "YES" << endl;
init_matrix(n, 1);
construct_matrix(n, b, 0);
print_matrix(n);
}
else if(b == 1)
{
cout << "YES" << endl;
init_matrix(n, 0);
construct_matrix(n, a, 1);
print_matrix(n);
}
else
cout << "NO" << endl;
return 0;
}
For ones interested in the problem this is a solution to, visit here.
PS: I've checked the bounds in the for loop in my functions, and they are correct. If this wasn't the case, the program will throw a segmentation fault regardless of the cout line.
The reason / one of reasons of undefined behavior in this code is using operator[] to access elements of vector that are not yet created.
From http://www.cplusplus.com/reference/vector/vector/operator[]/:
A similar member function, vector::at, has the same behavior as this operator function, except that vector::at is bound-checked and signals if the requested position is out of range by throwing an out_of_range exception.
Portable programs should never call this function with an argument n that is out of range, since this causes undefined behavior.
reserve doesn't create new elements of the vector. It just ensures that the vector has allocated enough memory for them. If you want to create new elements which you can access, use resize. (https://stackoverflow.com/a/7397862/3052438)
I also recommend to double check all you vector accesses for out of bound indexes, after you fix the first problem.
adj_matrix.reserve(size); Does not create any elements, but just reserves the size of the vector. As such adj_matrix[i].reserve(size); is undefined behaviour when i is greater than adj_matrix.size()

Run-time check: stack around variable was corrupted

I am creating a program that rewrites an array with values from a file. I have linked the code below. When running the file I get the error "Run-time check failure, stack around 'arr' variable was corrupted.
Also, the output of the program returns all the array locations with the same number,
arr[0] = -858993460
The numbers in the file, separated by a line are:
12
13
15
#include<iostream>;
#include<fstream>;
using namespace std;
template <class T>
void init(T * a, int size, T v)//done
{
for (int i = 0; i < size; i++)
{
a[size] = v;
}
}
bool getNumbers(char * file, int * a, int & size)//not done
{
int count = 0;
ifstream f(file);
while (f.good() == true && count < 1)
{
f >> a[count];
count++;
}
if (size > count)
{
return true;
}
else if (size < count)
{
return false;
}
}
void testGetNumbers()
{
int arr[5];
int size = 5;
cout << "Testing init and getNumbers." << endl;
init(arr, 5, -1);
cout << "Before getNumbers: " << endl;
for (int i = 0; i < size; i++)
{
cout << "arr[" << i << "] = " << arr[i] << endl;
}
if (getNumbers("nums.txt", arr, size))
{
cout << size << " numbers read from file" << endl;
}
else
{
cout << "Array not large enough" << endl;
}
cout << "After getNumbers: " << endl;
for (int i = 0; i < size; i++)
{
cout << "arr[" << i << "] = " << arr[i] << endl;
}
cout << endl;
}
int main()
{
testGetNumbers();
return 0;
}
This line in the first loop looks like having error.
a[size] = v;
It causes out of array bound access and memory/stack corruption. It should be
a[i] = v;
Starting with the main function, the line
return 0;
... is not necessary because that's the default return value for main. I would remove it, some people insist on having it, I think most people don't care. But it's always a good idea to be fully aware of what the code expresses, implicitly or explicitly, so: returning 0 expresses that the program succeeded.
For an explicit main return value I recommend using the names EXIT_SUCCESS and EXIT_FAILURE from the <stdlib.h> header.
Then it's much more clear.
main calls testGetNumbers, which, except for an output statement, starts like this:
int arr[5];
int size = 5;
init(arr, 5, -1);
As it happens the init function is has Undefined Behavior and doesn't fill the array with -1 values as intended, but disregard. For now, look only at the verbosity above. Consider writing this instead:
vector<int> arr( 5, -1 );
Using std::vector from the <vector> header.
Following the call chain down into init, one finds
a[size] = v;
That attempts to assign value v to the item just beyond the end of the array.
That has Undefined Behavior.
Should probably be
a[i] = v;
But as noted, this whole function is redundant when you use std::vector, as you should unless strictly forbidden by your teacher.
Back up in testGetNumbers it proceeds to call getNumbers, in that function we find
ifstream f(file);
while (f.good() == true && count < 1)
{
f >> a[count];
count++;
}
Generally one should never use f.good() or f.eof() in a loop condition: use f.fail(). Also, ~never compare a boolean to true or false, just use it directly. Then the loop can look like this:
ifstream f(file);
while (!f.fail() && count < 1)
{
f >> a[count];
count++;
}
Tip: in standard C++ you can write ! as not and && as and. With the Visual C++ compiler you have to include the <iso646.h> header to do that.
Disclaimer: the fixes noted here do not guarantee that the loop is correct for your intended purpose. Indeed the increment of count also when the input operation fails, looks probably unintended. Ditto for the loop limit.
The function continues (or rather, ends) with
if (size > count)
{
return true;
}
else if (size < count)
{
return false;
}
This has a big problem: what if size == count? Then the execution continues to fall off the end of the function without returning a value. This is again Undefined Behavior.
I leave it to you to decide what you want the function to return in that case, and ensure that it does that.
In your init function...
template <class T>
void init(T * a, int size, T v)//done
{
for (int i = 0; i < size; i++)
{
a[size] = v;
}
}
Nope:
a[size] = v;
Yup:
a[i] = v;

how to insert values into middle of array [duplicate]

This question already has answers here:
Inserting an element into an array
(4 answers)
Closed 9 years ago.
So I have an array something like this [1,2,3,4,5,6,7,8,9] the max for this array is 15 values. What I want to do is insert an int if i call a numbers index. So say I call 5 which is index 4 from there everything shifts over and the new value is inserted [,1,2,3,4,0,5,6,7,8,9] How would I go about this?
I tried this but i can't seem to get it right it overrides the value.
int xxx;
cin >> num;
if (num >= 0 && num <= 15) {
for (int i = num; i < MAX; i++) {
values[i] = values[i+1];
cout << values[i+1] << endl;
}
viewVal(values, position);
cout << endl << endl;
}
The problem is that values[i] = values[i+1]; shifts a value one step to the left (index 4 now has the value of index 6), but you want to shift all values one step to the right. Thus, you have to reverse the assignment.
This creates the problem that once you have moved a value to the right, the previous value on the position to the right is lost. To prevent this, you can start from the back of the array.
Changing the size of plain arrays is not possible in C++. I can suggest use std::list, it supports constant time insertion.
#include <iostream>
#include <list>
#include <algorithm>
int main()
{
std::list<int> l{1, 2, 3, 4, 5, 6, 7, 8, 9};
int n;
std::cin >> n;
auto it = std::find(l.begin(), l.end(), n);
if(it != l.end())
{
l.insert(it, 0);
for(const auto& elem: l)
{
std::cout << elem << ' ';
}
std::cout << std::endl;
}
else
{
std::cout << "No such element" << std::endl;
}
return 0;
}
hope this will help, here all the elements are first shifted to the right, then the new number is inserted into array.
for(int i=(num-1);i<MAX;i++)
{
int temp=values[i];
values[i+1]=temp;
}
values[num-1]=0;