Segmentation fault issue with isdigit - c++

I have a function that will check if a string has any non-digit chars in it and returns a bool. But when I run it thru a debugger I get a segmentation fault.
Here is the function in question.
bool checkInt(string myString){
for (int i=0; i<myString.length; i++){
if (!isdigit(myString[i])){
return false;
};
return true;
}
I get the segfault on lines two and three on the for and if statements
if it helps here is the build log as well.
C:\Users\conner\Desktop\programing\for dummes\main.cpp: In function 'bool checkInt(std::string)':
C:\Users\conner\Desktop\programing\for dummes\main.cpp:78:30: error: invalid use of member function (did you forget the '()' ?)
C:\Users\conner\Desktop\programing\for dummes\main.cpp:84:1: warning: control reaches end of non-void function [-Wreturn-type]

A compiler error is not a "segfault". The error messages are telling you that there is a mistake in your source code, and the compiler can't finish compiling your program.
In your case, the error appears to be in the use of myString.length. This should be myString.length() because length is a member function and must be called (with ()).

i is being compared as greater than, not less than, in the for loop. This is causing access outside of the string buffer inside of myString[i] and a segmentation fault. Also, myString.length() should be used instead of myString.length. (As per manlio's comment).

Change to i < myString.length();

Your code misses a curly bracket. You should test whether i is less than myString.length, rather than greater. The semicolon after closing the if branch isn't needed.
bool checkInt(string myString)
{
for (int i=0; i < myString.length(); i++)
if(isdigit(myString[i]))
return false;
return true;
}

You got the segmentation fault because it seems you run an object module that was built with compilation errors. For example MS VC++ allows to do so.
Your function has a compilation error. Instead of correct syntax of calling member function length as
myString.length()
you wrote
myString.length
Also the condition in the loop statement is invalid
Instead of
for (int i=0; i>myString.length; i++){
there should be at least
for (int i=0; i < myString.length; i++){
The correct function could look as
bool checkInt( const string &myString )
{
string::size_type i = 0;
while ( i < myString.length() && isdigit( myString[i] ) ) ++i;
return ( i == myString.length() );
}
Also you could use standard algorithm std::all_of declared in header <algorithm>
For example
inline bool checkInt( const string &myString )
{
return std::all_of( myString.begin(), myString.end(),
[]( char c ) { return ::isdigit( c ); } );
}

Related

Why does a for loop invoke a warning when using identical code?

I think that following two codes are identical. but upper one has C4715 "not all control paths return a value" problem and other doesn't.
Why this warning happens?
int func(int n){
for(int i=0; i<1; i++){
if(n == 0){
return 0;
}
else {
return -1;
}
}
}
int func(int n){
if(n == 0){
return 0;
}
else {
return -1;
}
}
The compiler is trying to be helpful, and failing. Pretend for a moment that the code inside the loop was just if (n == 0) return 0;. Clearly, when n is not 0, the loop will execute once and then execution will move on to the next statement after the loop. There's no return statement there, and that's what the compiler is warning you about. It just isn't smart enough to see that the code inside the loop always returns.
So, possibly, add a return 0; statement after the loop. That might make the compiler happy. But it also might make the compiler (or some other compiler) give a different warning about "unreachable code", because that new return statement can't actually be reached. This stuff is hard to analyze, and compilers often get it wrong.
Because warnings don't promise to only flag incorrect code. Nor do they promise to flag all incorrect code. It's not possible to be completely accurate.
It seems like the part of the compiler that issues C4715 assumes that a for loop with an end condition ends in some cases, and doesn't try to calculate if it will always return early.
My first thought is that the loop cannot act.
You initialize the for loop with int i = 0 then give bounds of i < 1 with an action if i++
Given i is type int with step of 1, it can never loop.

vector pop_back causing heap-buffer-overflow error

I'm trying to make a function to validate the parenthesis problem, this function runs well on my machine, but it causing "heap-buffer-overflow" error on leetcode machine when I call vector.pop_back(). Here's the code:
int isValid(string s){
vector<char> st;
for(int i = 0; i < s.length(); i++){
if(s[i] == '(') st.push_back(s[i]);
else{
if(st.back() == '(') st.pop_back(); //this line triggered the error
else return 0;
}
}
return (st.size() == 0);
}
I already solved this by changing the vector into string, but I'm still wondering how can this happened, any explanation anyone?
Calling std::vector::back() on an empty vector is undefined behavior.
Calling back on an empty container causes undefined behavior.
(The same holds for std::vector::pop(), but at that point your program is already in an invalid state if the container was empty).
Therefore, the expression st.back() == '(' on your code might lead to an invalid program state because the container st is not sure being not empty.
Your code path needs to check the emptiness of the container before calling std::vector::back(); something like:
if (!st.empty() && st.back() == '(')
st.pop_back();
else
return 0;
Bonus Note: the code above exploits logical operators short circuit evaluation. It means that the second operand (i.e., the expression st.back()) will not be invoked if the container is empty.
maybe because you didn't assign any element in the vector before checking on the if condition. Try putting :
if(st.size()!=0)
{
if(st.back() == '(') st.pop_back();
else return 0;
}
on that piece of code

When to return from a function?

Sorry in advance if the question sounds naive. I am writing a simple bool function to check if all digits of a number are same. The following works, however the one after, gives me an error of
17:1: warning: control reaches end of non-void function [-Wreturn-type]
What I am doing wrong with the second one?
Working:
# include <iostream>
# include <string>
using namespace std;
bool samedigits (int number){
bool result = true;
std::string snumber = to_string (number);
for (int i=0; i < snumber.size(); i++){
if (snumber[i] != snumber[0]){
result = result and false;
break;
}
}
return result;
}
int main()
{
cout << samedigits (666);
return 0;
}
Non working:
# include <iostream>
# include <string>
using namespace std;
bool samedigits (int number){
std::string snumber = to_string (number);
for (int i=0; i < snumber.size(); i++){
if (snumber[i] != snumber[0]){
return false;
break;
}
return true;
}
}
int main()
{
cout << samedigits (666);
return 0;
}
Your algorithm is incorrect, you are only checking if the first character is equal to itself, and returning true for every input. Instead, you should move the return true outside the loop, so that you check all the characters first.
Unfortunately, the warning is a false positive. The compiler fails to realize that std::to_string is guaranteed to return a non-empty string when passed an int. This means that the for loop body will be entered, and the function will return a value.
The compiler is right. There is a code path in your second snippet that won't return.
for (int i=0; i < snumber.size(); i++){
Here, the std::string size function can return 0 according to its contract. When it does happen, then your function won't enter the loop. After that, you exit the function without returning.
The second version of your function (combined with some information obtained via comments) indicates a misunderstanding of what return does. The second version would work (here is the misunderstanding) if a return statement were to simply store the indicated value for use when the function eventually ends. However, this is not how return works. A return statement stores the indicated value for use when the function ends and immediately ends the function. In the second version of your function, the for statement might as well be an if and the break is never executed as it comes right after a return.
To demonstrate, let's do a code walk-through for a call to samedigits(123).
bool samedigits (int number){
As we enter the function, number is set to 123.
std::string snumber = to_string (number);
The string snumber is set to "123".
for (int i=0; i < snumber.size(); i++){
The loop initializes by setting i to 0 then checks if 0 < 3 (the size of snumber is 3). This is true, so we enter the loop. Note that the result of entering the loop depends only on snumber not being empty.
if (snumber[i] != snumber[0]){
We check to see if snumber[0] does not equal snumber[0]. This is a bit trivial, but the computer is willing to do it. The result, of course, is false (independent of what the input was – this part might be more interesting if the loop started at 1 instead of 0). So skip to the statement after the if.
return true;
The function immediately ends, returning true.
And that's it. There is no second iteration of the loop. No other code is executed during this function call. Since to_string never returns an empty string, the second version of your function is functionally equivalent to the following:
bool samedigits (int /*number*/){
return true;
// Execution ends with the return statement, so nothing after
// this comment ever executes.
std::cout << "This is dead code. It will never execute.\n";
std::cout << "You will never see this output.\n";
}
To fix the second version, you need to return inside the loop only when the if condition is true. Move return true; to be after the loop so that the loop can iterate multiple times. You do not want to end the function and tell the caller that all the digits are the same (which is what return true; does) until after you've checked all the digits. (If your loop finds a mismatch, execution will reach the return false; inside the loop. At that point, the function ends, so code after the loop has no effect on that function call.)
A smaller (cosmetic) fix is to get rid of the break. Suppose the loop did iterate enough times to find a mismatch. Execution would go into the if statement body and encounter return false. At that point, not only is the loop stopped, but the function as a whole ends, before the break statement is seen. The break statement is dead code, meaning code that can never be executed. In order to get to the break, execution has to go through a return. Execution may arrive at a return statement, but it never goes through one.
Also, be sure to thank your compiler for finding this error, as it does point to a bug in your code. It's not the exact bug the compiler reported, but then again, compilers are not exactly the best thinkers in the world. :)

c++ for loop: 'i' was not declared in this scope

bool linear_search(const string A[], int n, string colour, int &count)
{
for (int i = 0; i < n; i++);
{
if (colour == A[i])
{
return true;
}
}
return false;
}
Compiling the above code results in the error 'i' was not declared in this scope for the if statement if (colour == A[i]).
This is really similar to many other for loops I have written, and I don't understand why it is not declared in the scope. Wasn't it declared in the previous line? How do I fix this?
You have a semi colon after your for loop declaration, remove it and you will be fine.
As others have pointed out, the problem is an extra semicolon that prevents your intended loop body from actually being part of the loop. But I want to provide more information on how to catch and avoid this kind of error.
First of all, when I compile the code with the formatting you show, my compiler produces a warning:
main.cpp:130:32: warning: for loop has empty body [-Wempty-body]
for (int i = 0; i < n; i++);
^
You should check to see if you're already getting this or some similar warning, and if so you should make sure to pay attention to warnings in the future. If you're not getting this warning, see if you can increase your compiler's warning level in some way to cause it to produce a warning like this. Enabling and paying attention to compiler warnings can save you a lot of trouble.
Next, I notice that your code is poorly formatted. Poor formatting can hide this sort of error. When I auto-format the code it becomes:
bool linear_search(const string A[], int n, string colour, int &count) {
for (int i = 0; i < n; i++)
;
{
if (colour == A[i]) {
return true;
}
}
return false;
}
This formatting makes the extraneous semicolon much more obvious. (It also suppresses my compiler's warning about the empty body, since the compiler assumes that if you put the empty body on a separate line then you really mean for it to be empty.) Using automatic formatting avoids the problems of inconsistent formatting and ensures that the formatting is consistent with the actual meaning of the code. See if your editor provides formatting support or see if you can integrate an external formatter like clang-format.
Are you sure you need ; in this line? for (int i = 0; i < n; i++);
you ended for loops block by adding a ; after for loop
for (int i = 0; i < n; i++);
remove this semicolon.
I had a similar problem but there was an "if" statement before my variable declaration in front of a "for" loop, the error was the same. Just in case that somebody googled it and didn't mention something like that:
if (someVar!=1) // an "if" statement that reduces the scope of "var"
//some comment line
//some other comment line
double var = 0.0;
for (size_t i = 0; i < length; i++) {
var *= 0.5; // Error appeared here
}

Invalid use of auto

In this code:
for ( ;(auto i = std::find(some_string.begin(),some_string.end(),'%')) != some_string.end();)
{
}
I'm getting error from gcc 4.7.1:
error: invalid use of 'auto'|
any ideas why? shouldn't that be correctly compiled?
I think it has nothing to do with auto. You just cannot declare variables in random places, for example this will not compile either - an equivalent of what you were trying to do, but without auto:
int main() {
for ( ; (int i = 0) != 1; ++i)
;
return 0;
}
If this is in a loop, you'll only ever find the first '%'. You need to resume searching from i, not some_string.begin() to find subsequent '%'.
auto i = std::find(some_string.begin(), some_string.end(), '%'));
while (i != some_string.end()) {
// Your code here.
i = std::find(i, some_string.end(), '%')); // Find next '%'.
}