Trying to debug an EXEC_BAD_ACCESS error on a C++ program. The program is taking as input numbers which are converted to strings. I then want to return the ordering of the ints that would generate the largest possible number.
The main is
int main() {
// Number of ints to input
int n;
std::cin >> n;
vector<string> a(n);
// Input numbers as strings
for (size_t i = 0; i < a.size(); i++) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end(), is_greater_than_or_equal);
std::cout << largest_number(a);
std::cout << std::endl;
return 0;
}
Using lldb, it looks like the error is coming from the sort / is_greater_than_or_equal functions.
is_greater_than_or_equal is
bool is_greater_than_or_equal(string n1, string n2) {
int l1 = n1.length();
int l2 = n2.length();
int min = (l1 < l2) ? l1 : l2;
for (int i = 0; i < min; i++) {
// First digit is strictly larger
if (n1[i] > n2[i]) {
return true;
// First digit is strictly lower
} else if (n1[i] < n2[i]) {
return false;
// First digits are the same
} else {
// If first is single digit
if (l1 == 1) {
return true;
// If the second is single digit
} else if (l2 == 1) {
return false;
// If they're both multiple digits
} else {
int j = i + 1;
// Keep checking until hitting min
while (j < min) {
if (n1[j] > n2[j]) {
return true;
} else if (n1[j] < n2[j]) {
return false;
} else {
j++;
}
}
// If min was hit and nothing was returned
// choose integer with lowest length
if (l1 > l2) {
return false;
}
return true;
}
}
}
return false;
}
After checking with lldb, it seems like the sort function keeps going way past a.end() - I believe this is what's causing the error but I'm not sure why this would happen. The reason for this is that examining the calls to is_greater_than_or_equal reveal calls like
(lldb) fr v
(std::__1::string) n1 = "9"
(std::__1::string) n2 = "2"
(int) l1 = 0
(int) l2 = 0
(int) min = 0
at first but then, after a while, they become
(lldb) fr v
(std::__1::string) n1 = ""
(std::__1::string) n2 = ""
(int) l1 = 0
(int) l2 = 0
(int) min = 0
which clearly should not happen (btw, I'm setting the breakpoint before l1 and l2 are assigned which is why the length is not matching above - the point is really just to see n1 and n2).
The output from lldb is
(lldb) r
Process 7405 launched: '/Users/etc' (x86_64)
100
2 8 2 3 6 4 1 1 10 6 3 3 6 1 3 8 4 6 1 10 8 4 10 4 1 3 2 3 2 6 1 5 2 9 8 5 10 8 7 9 6 4 2 6 3 8 8 9 8 2 9 10 3 10 7 5 7 1 7 5 1 4 7 6 1 10 5 4 8 4 2 7 8 1 1 7 4 1 1 9 8 6 5 9 9 3 7 6 3 10 8 10 7 2 5 1 1 9 9 5
Process 7405 stopped
* thread #1: tid = 0x2f2a6, 0x00007fff97c82051 libsystem_platform.dylib`_platform_memmove$VARIANT$Ivybridge + 49, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x00007fff97c82051 libsystem_platform.dylib`_platform_memmove$VARIANT$Ivybridge + 49
libsystem_platform.dylib`_platform_memmove$VARIANT$Ivybridge:
-> 0x7fff97c82051 <+49>: rep
0x7fff97c82052 <+50>: movsb (%rsi), %es:(%rdi)
0x7fff97c82053 <+51>: popq %rbp
0x7fff97c82054 <+52>: retq
I'm not really sure how to interpret this output nor am I entirely aware of the inner workings of the sort.
Related
I am trying to sort strings according to a rule. The c++ code works in most cases but in some cases gives an error:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
I have seen this error before, it happens when we try to initialize a string as null pointer or 0 (which is internally converted as a null pointer). I have checked that error is happening during sorting and only when I use the custom function for comparison. Once again, I don't know why it is happening only in certain cases.
The code is:
#include <algorithm>
#include <sstream>
#include <iostream>
#include <vector>
#include <string>
using std::vector;
using std::string;
bool greater(string a, string b) {
int i = 0;
a = a + a[0];
b = b + b[0];
while(i<a.size() && i<b.size()) {
if(a[i] != b[i]) {
if(a[i] - '0' > b[i] - '0')
return true;
else return false;
}
i++;
}
}
string largest_number(vector<string> a) {
std::sort(a.begin(), a.end(), greater);
std::stringstream ret;
for (size_t i = 0; i < a.size(); i++) {
ret << a[i];
}
string result;
ret >> result;
return result;
}
int main() {
int n;
std::cin >> n;
vector<string> a(n);
for (size_t i = 0; i < a.size(); i++) {
std::cin >> a[i];
}
std::cout << largest_number(a);
return 0;
}
One of the cases where it gives error is:
100
2 8 2 3 6 4 1 1 10 6 3 3 6 1 3 8 4 6 1 10 8 4 10 4 1 3 2 3 2 6 1 5 2 9 8 5 10 8 7 9 6 4 2 6 3 8 8 9 8 2 9 10 3 10 7 5 7 1 7 5 1 4 7 6 1 10 5 4 8 4 2 7 8 1 1 7 4 1 1 9 8 6 5 9 9 3 7 6 3 10 8 10 7 2 5 1 1 9 9 5
SOLUTION:
Thanks for help. The error was occurring as the compare function was not returning anything once it goes out of the loop. Here is the updated function that works.
bool greater(string a, string b) {
int i = 0;
a = a + a[0];
b = b + b[0];
while(i<a.size() && i<b.size()) {
if(a[i] > b[i])
return true;
i++;
}
return false;
}
The only problem I can see with the code (actually I tried in an online compiler and it gave me this warning) is that you don't return anything from greater if the two strings are equal:
bool greater(string a, string b) {
int i = 0;
a = a;
b = b;
while(i<a.size() && i<b.size()) {
if(a[i] != b[i]) {
if(a[i] - '0' > b[i] - '0')
return true;
else return false;
}
i++;
}
// <---- what about here?
}
Try inserting a return statement. (Of course, if two things are equal then neither is greater than the other, so specifically it is a return false you want.) Falling off the end of a function without a return statement is undefined behaviour (except for int main() or any function returning void), so you could expect to see anything at all when this happens, including the type of crash you got.
[Edit: as gst says, you also get to that point if one string is a prefix of the other e.g. "1" and "10". So you'll need a bit more code to test which is which, rather than just a return false. But you could see if that one line would fix the crash: it would be logically wrong but at least not undefined behaviour.]
I have written this quick sort algorithm but it doesn't work properly for some reason, I need some help to find out the error.
I tried not to use built-in swap function however it didn't work out.
FindPivot function returns the median of three elements (start, half, end) of the array after swapping them so that the smallest one is at the start, the greatest at the middle and the median at the end of the array
#include <bits/stdc++.h>
using namespace std;
int pivotIdx, pivot, n;
int partitn(int* arr, int first, int last)
{
pivot = FindPivot(arr,first,last-1);
// pivot = arr[last-1];
cout << "Pivot: " << pivot << endl;
int L = first;
int R = last-2;
while(L<R)
{
while(arr[L]<=pivot)
L++;
while(arr[R]>=pivot)
R--;
swap(arr[L++],arr[R--]);
}
swap(arr[L],arr[last-1]);
return L;
}
void QuickSort(int* arr,int first,int last)
{
if(last-first < 6){
InsertionSort(arr,first,last);
}else{
pivotIdx = partitn(arr, first, last);
QuickSort(arr, first, pivotIdx);
QuickSort(arr, pivotIdx+1, last);
}
}
int main()
{
cin >> n;
int arr[100];
for(int i=0;i<n;i++)
cin>>arr[i];
QuickSort(arr,0,n);
for(int i=0;i<n;i++){
cout << arr[i] << " ";
}
return 0;
}
Input:
8
5 1 6 2 7 3 8 4
Output:
Pivot: 4
1 2 3 5 4 6 7 8
There may be other issues, but the current partition code could scan past the boundaries of the sub-array. Assuming the pivot is not at either end of the sub-array, the code can < instead of <= and > instead of >= and the scans will not run past the boundaries.
while(arr[L]<pivot) // not <=
L++;
while(arr[R]>pivot) // not >=
R--;
Input:
5 1 6 2 7 3 8 4
This becomes:
QuickSort([5 1 6 2 7 3 8 4], 0, 8)
partitn([5 1 6 2 7 3 8 4], 0, 8)
pivot = 4
L = 0 R = 6 [5 1 6 2 7 3 8 4]
// Enter Loop
L = 0 R = 5 swap [3 1 6 2 7 5 8 4]
L = 2 R = 3 swap [3 1 2 6 7 5 8 4]
L = 3 R = 2 swap [3 1 6 2 7 5 8 4]
// Exit Loop
L = 3 swap [3 1 6 4 7 5 8 2] This looks wrong.
The 2 and 6 are in the wrong place.
I am trying to generate a list of subsets from a set. For example, if I had n = 6, and r = 4, I would have 15 possible combinations which would be the following:
0 1 2 3
0 1 2 4
0 1 2 5
0 1 3 4
0 1 3 5
0 1 4 5
0 2 3 4
0 2 3 5
0 2 4 5
0 3 4 5
1 2 3 4
1 2 3 5
1 2 4 5
1 3 4 5
2 3 4 5
My current code does work with the above subsets if n = 6 & r = 4. It also works if any other combination of n-r=2. It does not work for anything else and I'm having a bit of trouble debugging since my code makes perfect sense to me. The code I have is the following:
int array[r];
int difference = n-r;
for(int i = 0; i < r; i++){
array[i] = i;
}
while (array[0] < difference){
print (array, r);
for(int i = r-1; i >= 0; i--){
if ((array[i] - i) == 0){
array[i] = array[i] + 1;
for (int j = i+1; j < r; j++){
array[j] = j + 1;
}
i = r;
}
else{
array[i] = array[i] + 1;
}
print (array, r);
}
}
}
To give some context, when I plug in n=6 and r=3, I am supposed to have 20 combinations as the output. Only 14 are printed, however:
0 1 2
0 1 3
0 1 4
0 2 3
0 2 4
0 3 4
1 2 3
1 2 4
1 3 4
2 3 4
2 3 4
2 3 5
2 4 5
3 4 5
It does print the first and last output correctly, however I need to have all the outputs printed out and correct. I can see after the 3rd iteration, the code starts failing as it goes from 0 1 4 to 0 2 3 when it should go to 0 1 5 instead. Any suggestions as to what I'm doing wrong?
Here's what I think you are trying to do. As far as I can tell, your main problem is that the main for loop should start over after incrementing an array element to a valid value, rather than continuing.
So this version only calls print in one place and uses break to get out of the main for loop. It also counts the combinations found.
#include <iostream>
void print(int array[], int r) {
for(int i=0; i<r; ++i) {
std::cout << array[i] << ' ';
}
std::cout << '\n';
}
int main() {
static const int n = 6;
static const int r = 3;
static const int difference = n-r;
int array[r];
for(int i = 0; i < r; i++) {
array[i] = i;
}
int count = 0;
while(array[0] <= difference) {
++count;
print(array, r);
for(int i=r-1; i>=0; --i) {
++array[i];
if(array[i] <= difference + i) {
for(int j=i+1; j<r; ++j) {
array[j] = array[j-1] + 1;
}
break;
} } }
std::cout << "count: " << count << '\n';
}
Outputs
0 1 2
0 1 3
0 1 4
0 1 5
0 2 3
0 2 4
0 2 5
0 3 4
0 3 5
0 4 5
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
count: 20
Hi guys i've to calculate the longest sequence of numbers without any repetitions and return the size of the sub-segment.
The point is that im missing something at some point but I don't know where.
int resolverCaso() {
int num;
int cont = 0;
cin >> num;
int var;
TreeMap<int,int> a;
int aux;
int max = 0;
for (int i = 0; i < num; i++) {
cin >> var;
if (!a.contains(var)) {
a[var] = i;
aux = var;
cont++;
}
else {
if (a[aux]==i-1 && var==aux) {
cont = 1;
a = TreeMap<int, int>();
a[var] = i;
}
else {
a.erase(var);
a[var] = i;
}
}
if (cont > max) {
max = cont;
}
}
return max;
}
I've tried the following cases with this outputs and everything seems to be ok.
E:1 2 3 1 2 3 O:3
E:2 2 2 2 O:1
E:4 5 6 7 6 O:4
E:7 8 9 10 7 8 9 11 2 O:6
E:7 8 9 10 10 10 1 2 3 4 O:5
E:3 4 2 3 4 2 8 9 10 11 O:7
E:0 O:0 ( empty vector ).
E:1 O:1
So basically im looking for some sequence that doesn't work with my code.
Thanks.
The problem is with
else {
a.erase(var);
a[var] = i;
}
You need to do more here. Try the sequence 1 3 4 2 3 4 2 8 9 10 11.
"Number pong" is what I am trying to do. Ex:
0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 etc
I have tried several different things, incrementing one number, modal operators. I could not figure this out, and I could not figure out correct search words.
So:
int offset = 0;
int number = 0;
while(true) {
offset++;
number = offset%5; // idea 1
number = (offset%5)-5 // idea 2
number = (offset/5)%5 // idea 3
number = 5 - (offset%5) // idea 4
}
None of those work, obviously. I get patterns like 0 1 2 3 4 5 0 1 2 3 4 5 or just continuous numbers.
I would wrap this in an if(offset % 10 <= 5) { ... } else { ... } and use your existing ideas.
Regardless you're going to want to work % 10 since that's how long your cycle is.
Hint These sequences are very closely related:
0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 ...
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 ...
#include <iostream>
int main()
{
int i = 0;
bool plus = true;
while(true) {
std::cout << i << std::endl;
if (plus) i++; else i--;
if (i == 5 || i == 0) plus = !plus;
}
}
Is there a requirement to generate the numbers in a single statement with variables and operators?
If not, then use an bool variable which switches its value (true means increasing, false means decreasing) from true to false and vice versa.
i.e.
int start = 0 ;
bool which_way = true ;
int loop_times = 100 ;
while(--loop_times) {
std::cout << start ;
start += which_way ? 1 : -1 ;
if(start % 5 == 0)
which_way = !which_way ;
}
Here is a crazy way of outputting the number pong (with set limit)
#include <stdio.h>
int main()
{
bool bFlip = false; //Decides if number will increase or decrease
int nLimit = 5; //How far up the number will count.
//Start at 0, keep going as long as number never reaches past the limit
//And increase/decrease depending on bFlip
for(int nNum = 0; nNum <= nLimit; (bFlip ? nNum++ : nNum--))
{
printf("%d ", nNum);
//When number reaches either end, do a barrel roll!
if (nNum % nLimit == 0)
{
bFlip = !bFlip;
}
}
return 0;
}
Be warned that this loop will go on forever so if you are going to go with this approach then you will need to set a limit on how many numbers you want to display.
Yet another crack at generating the sequence you're after:
#include <iostream>
#include <list>
#include <iterator>
int main() {
std::list<int> nums = {{0, 1, 2, 3, 4, 5}};
auto begin = nums.begin();
auto iterator = nums.begin();
auto end = nums.end();
auto loop_times = 100;
while (--loop_times) {
while (iterator != end) {
std::cout << *iterator++;
}
iterator--;
while (iterator != begin) {
std::cout<< *--iterator;
}
iterator++;
}
}
Thanks for the tips. I got it working with a single statement.
int count = 0;
int num = 0;
int out = 0;
while (count++ < 100) {
cout << abs( (num%10) - 5 ) << endl;
num++;
}
// Output: 5 4 3 2 1 0 1 2 3 4 5 4 etc
I'd probably do something like this:
// If you want in the range -val to val
//#define PONG(val, i) (abs(val%(i*4)-i*2) - i)
// If you want the range 0 to val
#define PONG(val, i) (abs(val%(i*2)-i))
int main() {
for(int i = 0; i < 100; i++) {
cout << PONG(i, 5) << endl;
}
}
Prints:
5 4 3 2 1 0 1 2 3 4 5 4 3 2 1 0 1 2 ...