I am iterating a map in C++ using a for loop but it is stucking in an infinite loop. I have searched for other similar questions and the closest one is this question, but answer to that question doesn't answer my query because in that question the author is making changes to the map object but I am not making any changes to the map object during the for loop.
My code is follows (I tried commenting different lines and figured out that infinite loop is caused by 11th line (else statement) but I couldn't figure out the exact problem ):
int main(){
map<int,int> dic; //dic is the relevant map object
dic[0]=1; dic[1]=1; dic[2]=1; dic[3]=1; //dic = {0:1, 1:1, 2:1, 3:1}
int k=1;
int sol=0;
for(map<int,int>::iterator iter=dic.begin(); iter!=dic.end(); iter++){
int a=iter->first; int b=iter->second;
if(k==0) sol+=b*(b-1)/2;
else sol+=b*dic[a+k]; //after some trials, I found that problem is in this line but I couldn't figure out the problem
}
return sol;
}
This line:
sol+=b*dic[a+k];
does add a new element to the map if the key a+k doesn't exist.
a here is a key, so dic[a] would work fine. However, when k is not 0, you run the risk of accessing an element of the map that doesn't exist.
Use map::find if you want to check whether a particular key exists.
Also, your observation that this code results in an infinite loop, is valid, but technically incorrect. There are only a finite number of values that the key type can have, so eventually the loop will terminate. It might take quite a while though. This assumes that you are only ever using keys that don't overflow an int.
Related
#include<bits/stdc++.h>
using namespace std;
int issubseset(vector<int> subset,int size,int sum,vector<vector<int>>&memo){
// if(sum<0)return 0;
if(sum==0) return 1;
if(size<0) return 0;
if(subset[size]>sum) issubseset(subset,size-1,sum,memo);
if(memo[size][sum]>=0) return memo[size][sum];
memo[size][sum] = issubseset(subset,size-1,sum-subset[size],memo)||issubseset(subset,size-1,sum,memo);
return memo[size][sum];
}
int main(){
vector<int> subset{3, 34, 4, 12, 5, 2};
int sum=9;
std::cout << subset.size() << std::endl;
vector<vector<int>> memo(subset.size(),vector<int>(sum+1,INT_MIN));
printf("%s",issubseset(subset,subset.size()-1,sum,memo)?"true":"false");
}
Question:
Given a set of non-negative integers, and a value sum, determine if there is a subset of the given set with sum equal to given sum.
When I am interchanging the memo 2d array from memo[size][sum] to memo[sum][size], I have to uncomment the the first line in issubseset function . If I am just changing the shape of memo it should not have any effect since the array will be filled as per recursion and I am already covering base cases. If memo[size][sum] can work without the if(sum<0) line, why can't memo[sum][size]?
Your code exhibits undefined behaviour thanks to sum being used as an index even though it is sometimes negative. This is true of the code you posted as well as the equivalent with the shape of memo changed.
To find out why this happens, we'll have to look closely at your code. I'll reproduce it here with a couple of helpful labels:
#include<bits/stdc++.h>
using namespace std;
int issubseset(vector<int> subset,int size,int sum,vector<vector<int>>&memo){
// (1)
if(sum==0) return 1;
if(size<0) return 0;
// (2)
if(subset[size]>sum) issubseset(subset,size-1,sum,memo);
// (3)
if(memo[size][sum]>=0) return memo[size][sum];
memo[size][sum] = issubseset(subset,size-1,sum-subset[size],memo)||issubseset(subset,size-1,sum,memo);
return memo[size][sum];
}
Now let's walk through the code, assuming sum is negative and size is non-negative. If we get to (3), we've encountered undefined behaviour.
The checks for base cases at (1) do not trigger in this case, so execution carries on.
Now we're at (2), which is a very important line. It is the last line before the potentially troublesome (3), so there's a lot riding on it. We had better be sure it doesn't let execution go to (3). Unfortunately, even without looking deeply, we can tell that it's not up to the task: there isn't any control flow in this line (aside from the branching for the if of course). There's no question about it now: execution will definitely go ahead to (3), resulting in undefined behaviour.
Thankfully the fix is easy. Add a return for the recursive call in (2):
// (2)
if(subset[size]>sum) return issubseset(subset,size-1,sum,memo);
This will prevent execution from continuing to (3) whenever sum is negative: since subset[size] is non-negative and sum is negative, subset[size] > sum will be true and the return path will be taken. I'll leave it to you to determine whether this is the correct thing to do for your given problem.
The same analysis holds when the shape of memo is changed. The fact that you only noticed a problem with one shape and not the other is luck of the draw, really. There is no "why", it just happens to be that way. Either version of the code could literally have done (or not done) anything else (we don't call it undefined behaviour for nothing). I'll avoid going on a tangent about best practices, but I will give one piece of advice: use .at() instead of [], at least until you've proven the code correct (and even then, keeping .at() around may not be a bad idea). .at() will check each index and will scream at you (throw an exception) if it is invalid. Unlike [], .at() will not silently break your code when given a bad index, making much nicer from a debugging standpoint.
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000114 at pc 0x000000406d27 bp 0x7ffc88f07560 sp 0x7ffc88f07558
READ of size 4 at 0x602000000114 thread T0
LeetCode No.1
I get this when I give this code
The code below works for some other inputs, but for [3,2,4]\n6, it shows the above error.
vector<int> twoSum(vector<int>& nums, int target) {
int first = 0,last = nums.size() - 1;
vector<int> ref = nums;
while(first < last){
if(ref[first]+ref[last] > target) last--;
else if(ref[first]+ref[last] < target) first++;
else break;
}
vector<int> result;
for(int i=0;i<nums.size();i++){
if(ref[first]==nums[i]) result.push_back(i);
else if(ref[last]==nums[i]) result.push_back(i);
}
if(result[0] > result[1])
swap(result[0],result[1]);
return result;
}
The expected output is [1,2], indexes of values in the array adding up to the value 6.
Consider this while loop.
while(first < last){
if(ref[first]+ref[last] > target) last--;
else if(ref[first]+ref[last] < target) first++;
else break;
}
It seems that the intent was to break and exit when the sum is exactly equal to the target number. However, it is not guaranteed that this will become true. You can also exit the loop when the while condition fails, which happens whenever you reach first == last without yet finding any exact match. That actually happens in the particular case you mention. Follow the logic through and you will find this yourself. The search process misses the desired answer. The logic will not find [1,2]. It will first consider [0,2] and when that fails as too big, it will permanently decrement last and never again consider any combination that involves position 2.
(Likewise, if it fails for being too small it would increment the first position and never again consider combinations with the first value. So there are other failure cases that would happen similarly with that scenario.)
Since you exit without finding the matching combination and first == last, only one number will be pushed into the results. Therefore, when you just assume there are two numbers (false), things blow up as you try to reference the second result number.
General Observation:
You need to plan for the case where no exact match is found and code with that possibility in mind. In that case, what would a correct return result look like to signify no solution was found?
Plus, you could think about how the algorithm could be better at not missing a solution when it is actually present. However, that doesn't change the first requirement. If the target cannot be matched by any sum, you need to be ready for that possibility.
Side Notes:
Rather than repeat the sum of two in if statements, when the sum isn't changing I would suggest that you could create and use an auto local variable once that is
auto sum(ref[first]+ref[last]);
If you want to ensure that argument vector nums is not changed, and communicate that clearly to anyone looking at the declaration of the function, a better choice would be the pass it as a const reference, e.g.
(const vector<int>& nums, ...)
Why does the code create a local copy called ref of the argument vector nums? What is the point of making the effort to make the copy?
Regarding...
last = nums.size() - 1
...notice that if the vector passed in is empty, the value of last goes negative. That might not cause a problem for some code, but it has a dangerous smell in that it looks like code that is just assuming that the vector passed in would never be empty. Practice defensive coding that can be seen to guard against the possibility of unusual input values.
p.s. Part of what saves that last initialization from being broken is the use of int. Since size() returns size_t (unsigned), a common problem is to handle it as unsigned size_t. Then instead of going negative, the result wraps around to the maximum value and the looping may try to work with that as if that was a valid position in the vector. It's hazardous to get into habits that invite those kinds of bugs.
I have a question on std::readline(istream, string, delimiter). I am trying to read in a file and store the data in a struct and add it to a map. That I have gotten to work. However my while loop iterates one loop too many causing my vector to have no data stored in it which causes an assertion failure for out of bounds.
I have read every stack overflow question on readline and none seem to give me any idea as to why this behavior occurs. Perhaps someone here can enlighten me.
if (myReadFile.is_open()) {
while(getline(myReadFile, temp, ':')){//loops through and splits the line one delimiter at a time
stringVector.push_back(temp);//add to vector
ItemInfo tempItem = ItemInfo(stringVector[1], stod(stringVector[2]), stod(stringVector[3]));//create the struct
catalog.insert(pair<string,ItemInfo>(stringVector[0], tempItem));//add to map
stringVector.clear();
}
}
myReadFile.close();
Thanks for any help
The present code should break at first iteration.
Assuming you strart with an empty vection, you read first line of file in tmp, fine. Then you push_back tmp into your vector, still fine. Vector contains exactly one element of index 0.
But on next line you try to use elements of index 1, 2 and 3 from the vector that contains only one element => index out of bound exception guaranteed.
I am using boost 1.56 and have an unordered_map. When I insert a key value of zero as follows:
boost::unordered_map<int, int> map;
for(int i=0; i < size; i++)
{
int value = another_array[j];
map.insert(i, value);
}
I get a crash when accessing the map using
map.at(0);
I've tested that the insert works by looking at the
std::pairiterator, bool>
that the insert returns and the bool is true, indicating that it was successfully inserted
I am creating a local to global numbering map so my keys are all 0:N-1. I know N and so should be able to loop over (count == 0:N-1) as follows:
for(int j=0; j < count; j++)
{
if(map.count(j))
printf("Value at index %d is %d\n", j, map.at(j));
}
but the count of k is zero. If I don't perform the check I get an out of bounds error. How can this be happening? If I switch to using 1-N as keys there is no such problem.
I do realise btw that in this example a map is slight overkill, but I have my reasons.
Note that I can not use std::unordered map as we are cross platform and our linux compiler doesn't currently support it.
Before edit: Most likely your hash<> specialization or equality comparison for key_type is broken.
You don't show it, but only this kind of invariant-breaking error can explain the behaviour you describe (in a self-contained minimal example), as far as I can tell.
After edit: You should create a self-contained example that shows the error for you, for us to be able to come up with better diagnostics
Answer found thanks to sehe forcing me to write self contained code. This showed up an under allocation of an array further up, overwrites past the end of this were causing the normal memory wierdness and this was just a symptom.
at doesn't take index as a parameter. It takes a key as parameter. If there is no item inserted with key "0", boost will throw exception which results in crash.
http://www.boost.org/doc/libs/1_48_0/doc/html/boost/unordered_map.html#id1601722-bb
It's my first time dealing with recursion as an assignment in a low level course. I've looked around the internet and I can't seem to find anybody using a method similar to the one I've come up with (which probably says something about why this isn't working). The error is a segmentation fault in std::__copy_move... which I'm assuming is something in the c++ STL.
Anywho, my code is as follows:
bool sudoku::valid(int x, int y, int value)
{
if (x < 0) {cerr << "No valid values exist./n";}
if (binary_search(row(x).begin(), row(x).end(), value))
{return false;} //if found in row x, exit, otherwise:
else if (binary_search(col(y).begin(), col(y).end(), value))
{return false;} //if found in col y, exit, otherwise:
else if (binary_search(box((x/3), (y/3)).begin(), box((x/3), (y/3)).end(), value))
{return false;} //if found in box x,y, exit, otherwise:
else
{return true;} //the value is valid at this index
}
int sudoku::setval(int x, int y, int val)
{
if (y < 0 && x > 0) {x--; y = 9;} //if y gets decremented past 0 go to previous row.
if (y > 8) {y %= 9; x++;} //if y get incremented past 8 go to next row.
if (x == 9) {return 0;} //base case, puzzle done.
else {
if (valid(x,y,val)){ //if the input is valid
matrix[x][y] = val; //set the element equal to val
setval(x,y++,val); //go to next element
}
else {
setval(x,y,val++); //otherwise increment val
if(val > 9) {val = value(x,y--); setval(x,y--,val++); }
} //if val gets above 9, set val to prev element,
} //and increment the last element until valid and start over
}
I've been trying to wrap my head around this thing for a while and I can't seem to figure out what's going wrong. Any suggestions are highly appreciated! :)
sudoku::setval is supposed to return an int but there are at least two paths where it returns nothing at all. You should figure out what it needs to return in those other paths because otherwise you'll be getting random undefined behavior.
Without more information, it's impossible to tell. Things like the data
structures involved, and what row and col return, for example.
Still, there are a number of obvious problems:
In sudoku::valid, you check for what is apparently an error
condition (x < 0), but you don't return; you still continue your
tests, using the negative value of x.
Also in sudoku:valid: do row and col really return references to
sorted values? If the values aren't sorted, then binary_search will
have undefined behavior (and if they are, the names are somewhat
misleading). And if they return values (copies of something), rather
than a reference to the same object, then the begin() and end()
functions will refer to different objects—again, undefined
behavior.
Finally, I don't see any backtracking in your algorithm, and I don't
see how it progresses to a solution.
FWIW: when I wrote something similar, I used a simple array of 81
elements for the board, then created static arrays which mapped the
index (0–80) to the appropriate row, column and box. And for each of
the nine rows, columns and boxes, I kept a set of used values (a
bitmap); this made checking for legality very trivial, and it meant that
I could increment to the next square to test just by incrementing the
index. The resulting code was extremely simple.
Independently of the data representation used, you'll need: some
"global" (probably a member of sudoku) means of knowing whether you've
found the solution or not; a loop somewhere trying each of the nine
possible values for a square (stopping when the solution has been
found), and the recursion. If you're not using a simple array for the
board, as I did, I'd suggest a class or a struct for the index, with a
function which takes care of the incrementation once and for all.
All of the following is for Unix not Windows.
std::__copy_move... is STL alright. But STL doesn't do anything by itself, some function call from your code would've invoked it with wrong arguments or in wrong state. You need to figure that out.
If you have a core dump from teh seg-fault then just do a pstack <core file name>, you will see the full call stack of the crash. Then just see which part of your code was involved in it and start debugging (add traces/couts/...) from there.
Usually you'll get this core file with nice readable names, but in case you don't you can use nm or c++filt etc to dismangle the names.
Finally, pstack is just a small cmd line utility, you can always load the binary (that produced the core) and the core file into a debugger like gdb, Sun Studio or debugger built into your IDE and see the same thing along with lots of other info and options.
HTH
It seems like your algorithm is a bit "brute forcy". This is generally not a good tactic with Constraint Satisfaction Problems (CSPs). I wrote a sudoku solver a while back (wish I still had the source code, it was before I discovered github) and the fastest algorithm that I could find was Simulated Annealing:
http://en.wikipedia.org/wiki/Simulated_annealing
It's probabilistic, but it was generally orders of magnitude faster than other methods for this problem IIRC.
HTH!
segmentation fault may (and will) happen if you enter a function recursively too many times.
I noted one scenario which lead to it. But I'm pretty sure there are more.
Tip: write in your words the purpose of any function - if it is too complicated to write - the function should probably be split...