C++ runtime error: addition of unsigned offset? - c++

I wrote the following to check if text is palindrome, I run it on leetcode and I am getting errors:
class Solution {
public:
bool isPalindrome(string s) {
int l=0,r=s.length()-1;
while(l<r)
{
while (!isalpha(s[r]))
{
--r;
}
while (!isalpha(s[l]))
{
++l;
}
if (tolower(s[r])!=tolower(s[l]))
return false;
--r;
++l;
}
return true;
}
};
Line 1061: Char 9: runtime error: addition of unsigned offset to
0x7ffc7cc10880 overflowed to 0x7ffc7cc1087f (basic_string.h) SUMMARY:
UndefinedBehaviorSanitizer: undefined-behavior
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_string.h:1070:9
what's the problem with my code?

You're going out of bounds here:
while (!isalpha(s[r]))
and here
while (!isalpha(s[l]))
r can became negative and l can become >= s.length().
You should add some checks like
while (l < r && !isalpha(s[r]))
and
while (l < r && !isalpha(s[l]))
The same problem in this line
if (tolower(s[r])!=tolower(s[l]))
This should be
if (l < r && tolower(s[r])!=tolower(s[l]))
Different approach (C++20)
A different approach is to erase all non-alpha characters from s with
std::erase_if(s, [](char c) { return !isalpha(c); });
and remove the inner while loops.

I think you were very close to the solution. The pitfall here are that:
you are modifying the loop control variable more than once in the loop
(as consequence) you are using the loop control variable after changing their values without further checks.
The easy way to fix this kind of issue is to do one single action for every iteration. you can achieve this just using "else".
class Solution {
public:
bool isPalindrome(string s) {
int l=0,r=s.length()-1;
while(l<r)
{
if(!isalpha(s[r]))
{
--r;
}
else if(!isalpha(s[l]))
{
++l;
}
else if (tolower(s[r])!=tolower(s[l]))
{
return false;
}
else
{
--r;
++l;
}
}
return true;
}
};

Related

Difference between flow of if....if block and if....else block

So I was just solving this question the previous day
https://leetcode.com/problems/search-a-2d-matrix-ii/
I was able to solve the problem....but was confused in the execution of if...else block vs if...if block.
The if...else block didn't give me any error while the if....if block gave me an error of IndexOutOfBoundException for length = 1.
Can someone please tell me what's the difference in Layman's term and what am I doing wrong here?
Here is my code ---->
class Solution {
public boolean searchMatrix(int[][] m, int target) {
int x =m.length;
int n= m[0].length;
int i = 0 , j=n-1;
while(i<x && j>=0){
if(m[i][j]==target){
return true;
}
if(m[i][j]>target){
j--;
}
if(m[i][j]<target) {
i++;
}
}
return false;
}
}
************************************* VS ******************************************
class Solution {
public boolean searchMatrix(int[][] m, int target) {
int x =m.length;
int n= m[0].length;
int i = 0 , j=n-1;
while(i<x && j>=0){
if(m[i][j]==target){
return true;
}
if(m[i][j]>target){
j--;
}
else {
i++;
}
}
return false;
}
}
One issue is that this can take you off the bottom of your matrix if j=0.
if(m[i][j]>target){
j--;
}
if(m[i][j]<target) {
i++;
Let's say m[3][0] > target, and you subtract 1 from j, giving j=-1. In your if-else solution, the else is skipped, the while loop then sees that j<0, and the loop exits. Fine.
But in your if-if solution, it then executes if(m[3][-1]<target), which causes the IndexOutOfBoundException
There may be other scenarios too - I haven't checked.

Increment a variable in C++ with a void function

I wanted to make one of my code more concise so I wrote this:
while(m <= r)
nums[m] ? nums[m] == 1 ? m++ : swap(nums[m], nums[r--]) : swap(nums[m++], nums[l++]);
But it's not working because 'swap' is a void function but 'm++' returns int. ('right operand to ? is void, but left operand is of type int' error). So I'd like to know how can I replace m++ so it's of type void.
I know that I can create a new void function (for example void increase(int &x){x++;}) but I want to keep my code as an one liner.
The best working variant I made is 'swap(nums[m], nums[m++])', which does nothing to my array, but it looks awful. What other functions can I use?
I wanted to make one of my code more concise
Baking in a number of side effects into a single expression of nested non-parenthesized ternary operators (making use of implicit conversion to bool) does, if anything, make your code more complex, more bug-prone and may hide the fact that the original code should actually have been broken up and re-factored into something simpler.
Why not favour clarity over over-complex brevity? E.g. starting with the straight-forward approach:
while(m <= r) {
if (nums[m] != 0) {
if (nums[m] == 1) {
++m;
}
else {
swap(nums[m], nums[r--]);
}
}
else {
swap(nums[m++], nums[l++]);
}
}
which can be re-factored into:
while(m <= r) {
if (nums[m] != 0) {
if (nums[m] == 1) {
++m;
}
else {
swap(nums[m], nums[r]);
--r;
}
}
else {
swap(nums[m], nums[l]);
++m;
++l;
}
}
which can be re-factored into:
while(m <= r) {
const std::size_t swap_from_idx = m;
std::size_t swap_with_idx = m; // default: no swapping.
if (nums[m] == 1) {
++m;
continue;
}
else if (nums[m] == 0) {
swap_with_idx = l;
++l;
}
else {
swap_with_idx = r;
--r;
++m;
}
swap(nums[swap_from_idx], nums[swap_with_idx]);
}
or e.g.:
while(m <= r) {
// No swapping.
if (nums[m] == 1) {
++m;
}
// Swapping.
else {
const std::size_t swap_from_idx = m;
std::size_t swap_with_idx = l;
if (nums[m] == 0) {
++l;
}
else {
swap_with_idx = r;
--r;
++m;
}
swap(nums[swap_from_idx], nums[swap_with_idx]);
}
}
At this point you may ask yourself is the original loop design is overly complex, and/or if you should break out part of the loop body into a separate utility function.
If your if/else if/else logic is reaching a too high cyclomatic complexity, the answer is seldom to try to hide it by means of a highly complex tenary operator expression, but rather by re-factoring and, if applicable, breaking out some parts in separate functions.
If you want the expression m++ to have a side-effect, and have a void type, you can simply cast the expression like this:
(void)m++
which will evaluate the m++ first, and then cast it to void.
Here's a demo.

Can somebody tell me how this code working with no curly braces between two if?

If I am enclosing the code after first if upto second return in curly braces it is not giving me desired output.
static int comparator(Player a, Player b) {
if(a.score == b.score)
if(a.name == b.name)
return 0;
else
return (a.name > b.name)? -1:1;
return (a.score < b.score)? -1:1;
}
Your code has if() and else statements. Each will execute one line of code that comes after them. This means that it will only execute a single statement and end after the first ; that it finds.
for() loops, while() loops, if-else blocks can be used without curly braces if the statement you want to execute consists of only one line of code following them.
Your code works as -
static int comparator(Player a, Player b) {
// if statement without braces- means just one statement executes
if(a.score == b.score)
// Remember if-else will be considered as a single code block so both will run
if(a.name == b.name)
return 0;
else
return (a.name > b.name)? -1:1;
// This statement will run only when the above if condition is not satisfied
return (a.score < b.score)? -1:1;
}
This can be considered to be same as -
static int comparator(Player a, Player b) {
if(a.score == b.score) {
if(a.name == b.name) {
return 0;
} else {
return (a.name > b.name) ? -1 : 1;
}
}
return (a.score < b.score) ? -1 : 1;
}
NOTE : It is generally better if you use the braces as it will be good for readability as well as maintainability of the code. There can actually be two way of parsing it - Dangling else(though most compiler will associate the else with closest if).
In this coding style, there's no way to differentiate between below two code -
if(condition1)
if(condition2)
foo1();
else
foo2();
and,
if(condition1)
if(condition2)
foo1();
else
foo2();
Since, in C/C++, it doesn't consider the indentation in code, so it might create ambiguity while reading the code. So its always better to use curly braces instead of doing it like above. Drop them only when you have a single line and it won't create any confusion reading the code later on...
Hope this helps !
Without curly braces, only the next statement is executed. With proper indentation it becomes easier to see what's going on:
static int comparator(Player a, Player b) {
if(a.score == b.score)
if(a.name == b.name)
return 0;
else
return (a.name > b.name) ? -1 : 1;
return (a.score < b.score) ? -1 : 1;
}
This is actually the same as:
static int comparator(Player a, Player b) {
if(a.score == b.score) {
if(a.name == b.name) {
return 0;
} else {
return (a.name > b.name) ? -1 : 1;
}
}
return (a.score < b.score) ? -1 : 1;
}
You have maybe used the braceless else variant without noticing it when writing something like:
if(condition) {
//
} else if(another_condition) {
//
} else {
//
}
Which is actually the same as
if(condition) {
//
} else {
if(another_condition) {
//
} else {
//
}
}
Without curly braces, the if guard only applies to the immediate next statement.
It's just how the language works. :/

Error: control may reach end of non-void function in C++

I cannot figure out why this error is happening: error: "control may reach end of non-void function" even when "else" statement is present at the end.
Here is the code:
bnode* binsert(bnode *h,int k){
bnode *temp=new bnode;
if(h==NULL)
{
temp->num=k;
temp->L=NULL;
temp->R=NULL;
h=temp;
return h;
}
else if(h->L==NULL && k<h->num)
{
temp->num=k;
temp->L=NULL;
temp->R=NULL;
h->L=temp;
return h;
}
else if(h->R==NULL && k>h->num)
{
temp->num=k;
temp->L=NULL;
temp->R=NULL;
h->R=temp;
return h;
}
else if(h->L!=NULL && k<h->num)
{
h->L=binsert(h->L,k);
}
else
{
h->R=binsert(h->R,k);
}
}
You need to return the results of recursive calls, it's not done automatically.
You can also simplify your code a bit by adding a constructor:
bnode::bnode(int v)
: num(v),
L(nullptr),
R(nullptr)
{
}
and since you're already handling the case of a null parameter, you don't need special cases for null children:
bnode* binsert(bnode *h,int k)
{
if(h == nullptr)
{
h = new bnode(k);
}
else if(k < h->num)
{
h->L = binsert(h->L, k);
}
else if(k > h->num)
{
h->R = binsert(h->R, k);
}
return h;
}
because this last 2 conditions:
else if(h->L!=NULL && k<h->num)
{
h->L=binsert(h->L,k);
}
else
{
h->R=binsert(h->R,k);
}
may occur and no return is given...
you need to be sure the function returns a value no matter what the condition evaluates....
else if(h->L!=NULL && k<h->num)
{
h->L=binsert(h->L,k);
}
else
{
h->R=binsert(h->R,k);
}
In the else if and else cases for your code, if you reach here, you do not return a value, and the behavior is undefined if you try to use this value.
You probably want to add a return h; in the two branches.

Error: not all control paths return a value

I am writing two functions in a program to check if a string has an assigned numeric code to its structure array or if the given numeric code has an assigned string in the same structure array. Basically, if I only know one of the two, I can get the other. I wrote the following:
int PrimaryIndex::check_title_pos(std::string title) {
bool findPos = true;
if (findPos) {
for (int s = 1; s <= 25; s++) {
if (my_list[s].title == title) {
return s;
}
}
} else {
return -1;
}
}
std::string PrimaryIndex::check_title_at_pos(int pos) {
bool findTitle = true;
if (findTitle) {
for (int p = 1; p <= 25; p++) {
if (my_list[p].tag == pos) {
return my_list[p].title;
}
}
} else {
return "No title retrievable from " + pos;
}
}
However, it says not all control paths have a return value. I thought the else {} statement would handle that but it's not. Likewise, I added default "return -1;" and "return "";" to the appropriate functions handling int and string, respectively. That just caused it to error out.
Any idea on how I can keep this code, as I'd like to think it works but cant test it, while giving my compiler happiness? I realize through other searches that it sees conditions that could otherwise end in no returning values but theoretically, if I am right, it should work fine. :|
Thanks
In the below snippet, if s iterates to 26 without the inner if ever evaluating to true then a return statement is never reached.
if (findPos) {
for (int s = 1; s <= 25; s++) {
if (my_list[s].title == title) {
return s;
}
}
}