When to return from a function? - c++

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. :)

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.

Difference in while and do-while loops

Can someone explain the purpose of having two different types of while loops? I am new to programming. Also supply example situations with the proper while loop if possible.
I understand how to use a while loop. This is what I made:
bool myBool = true;
int i = 0;
while (myBool) {
if (i > 10) {
myBool = false;
}
i = i + 1;
}
A while loop will only execute when the boolean condition is true.
while (true) {
// INSERT CODE HERE
std::cout << "boolean condition is true - inside my while loop";
}
A do while whill check the boolean condition after the loop executes once.
do {
// INSERT CODE HERE
std::cout << "inside my while loop regardless of boolean condition";
} while (true);
Explicitly: the do while loop is guaranteed to execute at least once, whereas the while loop is not guaranteed to execute at all.
Similarly,
while (false) {
// INSERT CODE HERE
std::cout << "this will never execute";
}
will never execute and
do {
// INSERT CODE HERE
std::cout << "this will execute only once";
} while (false);
will execute once.
The do while loops are control flow statements, they execute a block of code at least once and then the iteration of loops depends on the condition which is checked at the bottom of the loop, They are best to use when you want at least once the loop to be executed, for ex
#include <stdio.h>
int main () {
int c = 50;
/* The do will be executed */
do {
printf("value of c: %d\n", c);
c = c + 1;
}while( c < 20 );//It will depend on the condition
printf("any string");
return 0;
}
Here is a Flow diagram of do while loop
Simple answer is while loop will execute only if condition inside of while statement is true.
do while loop will execute once regardless of the while statement condition.
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
int i = 1;
while( i < 1){ // this loop will never execute as 1 is not smaller then 1
i++; // if the loop was working we would get print 2 here
cout << i << endl;
}
cout << i << endl; // this one will print outside of loop value 1
do{
i++; // increase i to 2
cout << i << endl; // this will print 2
} while (i < 1); // This loop will execute at least once and as the condition of 2 is not smaller then 1 it will exit after one execution
return 0;
}
The difference between while and do-while is that in
while (<condition>)
{
//statements
}
we can control whether to enter the loop by using the test condition.
Whereas in
do
{
//statements
} while (<condition>);
the code has to enter the loop at least once before it can exit by using the condition.
So if we want to enter the loop at least once we should use do-while whereas if we want to test and decide whether to enter the loop or not, we have to use while.
To explicitly answer your first question:
Why does C++ have different kinds of loops? -> Legacy. Other languages (in particular, C) before C++ had this feature, so C++ chose to have it.
Why did other languages have it? -> This gets muddy, but a good explanation is that early languages often did not have optimizing compilers, so your code mapped quite directly to machine code. Providing various loop syntaxes allowed programmers to write structured code that still generates good machine code for their particular case.
In practice, it is rare to see a true do {} while () loop. This may be because for (or range-based for) and while () {} have strictly greater capabilities than do {} while (): An unconditional first loop iteration is possible with every loop, but the reverse is not true. In the very common case of iterating over a (possibly empty) sequence, having a guaranteed loop body execution like do {} while () is actually wrong.
There are plenty of answers with examples and explanations about the loops, so I won't bother repeating this here. I will add though that the most that I personally have seen do {} while () used is, ironically, not for looping but for this.
do-while loop performs the task before the condition in while(). It is for situations when you are trying to prompt the same thing for every wrong action (i.e., user authentication, wrong menu entry). On the other hand, a simple while loop performs till a condition is true (Note: In most cases people use for loops instead of while to define counter, initialize, set condition and increment/decrement - all in the same line).

bool method inside a class ''Control may reach end o non-void function''

So, i have a class called Vuelo, it has a method in which i can add a passenger to an airplane flight, i must check that the passenger id is not already in the array (the array is at first with all zeros), i must also check that there is enough space for another passenger to be added (max 10)
bool Vuelo :: agregarPasajero(int id)
{
int i = 0;
for(int iC = 0; iC < 10; iC++)
{
if (listaPasajeros[iC] == id)
{
i++;
return false;
}
}
if(i == 0)
{
if(cantidadPasajeros >= 10)
{
return false;
}
else
{
return true;
cantidadPasajeros++;
}
}
}
If i is not zero, you get to the end of the function without any kind of return statement. Since you declared the function to always return a bool, you should provide one for that case.
Now, you may know that i will never be zero at that spot, but the logic for that is fairly complex (I missed it on the first reading), and a compiler cannot be expected to realize that there is in fact no chance of control flow ever getting to the end of the function without encountering a return. In this case it's best to add a dummy return.
You can probably get away with not having a dummy return if you remove the bogus i == 0 test. i will necessarily always be zero at that point, since if it were ever increased, the function immediately returns false.
The statement cantidadPasajeros++; will never be executed since it is located after a return statement. Any halfway decent compiler also warns on that.

C++ Function will not execute more than once

I've tried looking around but I can't find anything about this anywhere.
I'm writing a custom array class with a "push" function to add a value to the array.
It seems to work perfectly fine but won't execute more than once.
Take the main method below for example:
int main()
{
Array<int> test(4,5);
test.push(4);
test.writeOrdered("Output.txt");
return 0;
}
This will put the int value 4 into the array at the first available position and execute the writeOrdered function.
The following main method, on the other hand:
int main()
{
Array<int> test(4,5);
test.push(4);
test.push(5);
test.writeOrdered("Output.txt");
return 0;
}
This will put the number 4 into the array at the first available point as above and then stop. It won't execute any further lines of code.
Here's the push function for reference:
void push(Datatype p_item)
{
bool inserted = false;
int i = 0;
while (inserted == false)
{
if (m_array[i] < 0)
{
m_array[i] = p_item;
i++;
inserted = true;
cout << p_item << " saved to array" << endl;
system("pause");
}
}
}
You have an infinite loop. After the first insert m_array[0] >= 0 and i never grows. You would have found it out, had you debugged the code somehow.
Basically I don't understand your push function but the way it is, after you insert a non-negative value into the first position any further call to your push function results in a tight loop.
I imagine that you want the i++ outside the if statement.
Without seeing the full implementation of the Array class I would guess that the array m_array contains negative numbers by default. This will allow the first call to the push method to succeed. The next call to the method contains a value of 4 at index 0 and will be stuck in an infinite loop because inserted will never be set to true nor will the value of i be incremented.

C++ Prime factor program 2 problems

Okay so I"m writing a program (in C++) that is supposed to take a number, go through it, find out if it's factors are prime, if so add that to a sum, and then output the sum of all of the imputed number's prime factors.
My program successfully seems to do this however it has 2 problems,
1) The number I am supposed to test to see the sum of the prime factors of this number (600851475143) but it's too big for an int. I'm not sure what other variable type to use, or which variable's types to change. I would really like a clear explanation on this if at all possible.
2) For some reason, when the program checks to see if 1 is a factor of the number, and then checks to see if 1 is prime, it says 1 is prime, even though the first step of the function for checking to see if it's prime is that if it's 1 then it isn't prime. I found a fix for this, by telling it to subtract 1 from the very last value for the sum of all prime factors. However, this is a fix, not really finding the problem. If someone could point out at least where the problem is I would appreciate it!
Here's the code, if you have questions, please ask!
#include <iostream>
using namespace std;
bool prime (int recievedvalue) { //starts a function that returns a boolean with parameters being a factor from a number
int j =1;
int remainderprime = 0;
bool ended = false;
while (ended == false){ //runs loop while primality is undetermined
if (recievedvalue == 1){ //if the recieved value is a 1 it isn't prime
//not prime
break; // breaks loop
return false;
}
remainderprime=recievedvalue%j; //gives a remainder for testing
if ((remainderprime==0 && j>2) && (j!=recievedvalue || j == 4)){ //shows under which conditions it isn't prime
ended=true;
//not prime
return false;
}
else if (j==1){
j++;
}
else if ( recievedvalue==2 || j==recievedvalue ){ // shows what conditions it is prime
ended = true;
//prime
return true;
}
else {
j++;
}
}
}
int multiple(int tbfactor){ //factors and then checks to see if factors are prime, then adds all prime factors together
//parameter is number to be factored
int sum = 0;
bool primetest = false;
int remainderfact;
int i=1;
while (i<=tbfactor){ //checks if a i is a factor of tbfactor
remainderfact=tbfactor%i;
if (remainderfact==0){ //if it is a factor it checks if it is a prime
primetest = prime(i);
}
if (primetest ==true){ //if it is prime it add that to the sum
sum += i;
primetest=false;
}
i++;
}
sum --; // for some reason it always ads 1 as a prime number so this is my fix for it
return sum;
}
int main()
{
int input;
int output;
cout << "Enter number to find the sum of all it's prime factors: ";
cin >> input;
output = multiple(input);
cout << output;
return 0;
}
I'm really new to this, like a few days or so, so I'm very unfamiliar with stuff right now so please explain easily for me! I look forward to your help! Thanks!
For 1), you need to use a larger datatype. A 64-bit integer should be enough here, so change your ints to whatever the 64-bit integer type is called on your platform (probably long, or maybe long long).
For 2), the problem appears to be that you have a break before your return false. The break causes the code to stop the while loop immediately and continues execution immediately after the loop. It doesn't appear that the return value is ever assigned in that case (which your compiler should be warning you about), so the actual value returned is effectively arbitrary.
While others have pointed out a problem with your data types, there's a few problems with the structure of the first function that immediately caught my eye. (BTW, your indentation is enraging.) Look at this stripped-down version:
bool prime (int recievedvalue) {
// ...
bool ended = false;
while (ended == false){
if (...){
break; // jumps _behind_ the loop
return false;
}
// ...
if (...) {
ended=true;
return false; // leaves function returning true
}
else if (...) {
// ...
}
else if (...) {
ended = true;
return true; // leaves function returning false
}
else {
// ...
}
}
// behind the loop
// leaves function returning random value
}
For one, every time you set the loop control variable ended, you leave the loop anyway using some other means, so this variable isn't needed. A while(true) or for(;;) would suffice.
Also, that break jumps behind the loop's body, but there isn't a statement there, so the code leaves the function without explicitly returning anything! That's invoking so-called Undefined Behavior. (According to the C++ standard, your program is, from this point on, free to do whatever it pleases, including returning random values (most implementations will do that), formatting your HD, invoking nasty Nasal Demons on you, or returning exactly what you expected, but only on Sundays.)
Finally, that break occurs right before a return false; which is therefor never reached. Actually your compiler should warn about that. If it doesn't, you're likely not compiling at the highest warning level. (You should turn this on. Always try to cleanly compile your code at the highest warning level.) If it does, learn to pay attention to compiler warnings. They are a very important tool for diagnosing problems during compilation. (Remember: Errors diagnosed during compilation need no testing and never make it to the customer.)
Use either a 64 bits number on a 64 bits system, or use a library that does arbitrary precision arithmetic
Remove the break before the return false. Because of the break, execution is resumed outside the loop and return false is never executed.
To store values larger than 4 bytes (the capacity of an int) you have a variety of options. Refer to this page for those options. As to why you're program is returning true for the check on whether or not 1 is prime, check out this section of code:
if (recievedvalue == 1){ //if the recieved value is a 1 it isn't prime
//not prime
break; // breaks loop
return false;
}
The break statement will exit and return false will never be reached. To solve the problem, remove the break statement.