Divide and Conquer in C, may reach end of non-void function - c

I am trying to get this divide and conquer to work, but the compiler is giving me:
control may reach end of non-void function
I have read through similar scenarios, and understand the error implies the program might run forever without a return. I have reviewed some scenarios, which were resolved by using "else" instead of "if else" (as you should to begin with). However, that didn't help.
I am aware that using a do while loop and return in this scenario is redundant, I was fiddling with it in hopes to trick the compiler.
Where is the error?
bool search(int value, int values[], int n)
{
int sorted = 0;
int min = 0;
int max = n;
int mid = n / 2;
do
{
//mid is value
if (value == values[mid])
{
printf("value found!");
sorted = 1;
return 1;
}
//search right
else if (values[mid] < value)
{
min = mid + 1;
mid = (max - mid) / 2 ;
}
//search left
else if (values[mid] > value)
{
max = mid - 1;
mid = (max - mid) / 2;
}
// DNE
else
{
printf("value not found");
sorted = 1;
return 0;
}
}
while(sorted == 0);
}

Every branch of code should have a return if function suppose to return a value.
In your case after while you have to put a return. How ever, Your logic is also slightly wrong. In your code there is not any need of sorted variable and the terminating condition is also wrong as well as the way of calculating mid is also wrong. Don't worry here is your updated code:
bool search(int value, int values[], int n)
{
//int sorted = 0;
int min = 0;
int max = n;
int mid = n / 2; // S1
do
{
//mid=(max+min)/2; // S2
//mid is value
if (value == values[mid])
{
//printf("value found!");
//sorted = 1;
return 1;
}
//search right
else if (values[mid] < value)
{
min = mid + 1;
mid = (max + min) / 2 ; // S3
}
//search left
else if (values[mid] > value)
{
max = mid - 1;
mid = (max + min) / 2; //S4
}
// DNE
else
{
//printf("value not found");
//sorted = 1;
return 0;
}
}
while(min!=max);
return 0;
}
So if your function is returning 1 it mean value found otherwise value doesn't found.
you also can comment S1, S3 and S4 and uncomment S2 for minimum line of code.
And the way of finding mid will be mid=(max+min)/2.

Ignoring other problems in your code (the loop will never terminate under certain conditions although I didn't study it too closely), let's just look at why the compiler complains, because it's quite interesting.
Your compiler complains about that you don't have a return at the end of the function (pretty much what we can read from the warning message) after the while loop. You loop runs:
while(sorted == 0);
And everywhere you change sorted, you do this:
sorted = 1;
return X;
So it is pretty obvious to you and me that the while condition will always be true and you won't fall out of the while loop and need a return after it. Every time you make the while condition not true, you also return immediately. But the compiler doesn't know that. It probably could figure it out with a little bit more effort, but it can never be written to know in all cases and you wouldn't accept a compiler that slow anyway. The problem of fully analyzing any arbitrary bit of code to know what you and I know (that we'll never fall out of the loop) is pretty much the halting problem (if you don't know what it is, you should, google it).
In situations like this we need to work with the compiler and help it understand. I would add a return sorted; at the end of the function, change the loop condition to while (1) and replace sorted = 1; return X; with sorted = X; break; to break out of the loop and have the function return from just one place (it is much easier to read functions that have just one or very few return statements). Or just remove the sorted variable, do the returns properly and loop forever.

I think your compiler doesn't like your understanding of Control Flow. As a beginner this is one of the most cringing problems.
Your error explained: Control may reach end of non-void function. Whenever you branch your code (i.e. use loops, if, switch etc) you have to explicitly write what each branch will do. So in your code, you must return a bool by any means necessary.
I am unable to discern where the error might be, it would be great if someone can show me.
See we have two return x; statements, one in if block and second in else block. Now we think that control should return from either of these blocks conveniently. But your compiler is "concerned" about what will happen if control didn't enter either of these blocks and loop ends. Moreover, what will happen after the loop, how can control ever return to main? Hence the error.
Now what we can do to fix the problem is add a return 0; just before the end of the function. That will surely make the error disappear. However, there are better ways to solve this problem:
bool search(int value, int values[], int n) {
int min = 0, max = n;
int mid = n / 2;
bool is_found = 0;
while (min != max) {
if (value == values[mid]) {
is_found = 1;
break;
}
else if (value > values[mid]) {
min = mid + 1;
mid = (max + min) / 2;
}
else if (value < values[mid]) {
max = mid - 1;
mid = (max + min) / 2;
}
else break;
}
return is_found;
}

Related

why is this recursive function doesn't return 'counter' value?

int rec(int k)
{
static int temp = 0, counter = 0;
if(!k) return counter;
if(k%2 == 0){
counter++;
temp = rec(k/2);
}
if(k%2){
counter++;
temp = rec(k-1);
}
}
This function is supposed to get a number k and check how many operations are needed to get k to 0 only by multiplying by 2 or by adding 1.
this function works fine but returns zero instead of the last value in the counter. I tried to debug it, and I saw the counter value increasing, but after getting to the value it is supposed to return, the function goes back to complete all the calls, and returns 0.
I fixed it by making counter global and returning nothing, but my questions are:
Is there a way to fix it as it is with the counter inside the function?
Why is this function returning zero at the end?
Here's a nice recursive function that doesn't declare any variables at all, it's purely recursive!
int get_steps_to_zero(int n)
{
// Deal with negative values
if (n < 0) n *= -1;
if (n == 0) {
// Base case: we have reached zero
return 0;
} else if (n % 2 == 0) {
// Recursive case 1: we can divide by 2
return 1 + get_steps_to_zero(n / 2);
} else {
// Recursive case 2: we can subtract by 1
return 1 + get_steps_to_zero(n - 1);
}
}
get_steps_to_zero(457);
> 13
Others have addressed the general recursion issue, yet there remains a ...
Corner case
"this function works fine" --> Not quite.
The algorithm is an infinite loop for rec(-1) as it attempts -1 --> -2 --> -1 --> -2 ...
A better approach would sometimes add 1.
if(k%2) {
counter++;
// temp = rec(k-1);
temp = rec(k + (k < 0 ? 1 : -1));
}
This also well handles non-2's complement issue.
I will try to show a new side to this discussion,
Recursion is like a chain,
This means that any function can receive a value from its child and return a value to its parent.
In your program you are trying to return a value from the last child to the first parent,
So your program must have all links in the chain receive and send value in order.
But in your code you return a value only in the last call, and all other calls do not return this value back.
Your stop condition is here:
if(!k) return counter;
Only the last call enters this scope, but other calls do not reach any return statement.
they get to here:
if(k%2 == 0){
counter++;
temp = rec(k/2);
}
if(k%2){
counter++;
temp = rec(k-1);
here there is no return statement.
your compiler will warning you like this:
"warning: control reaches end of non-void function".
but your program will compile so it return zero like all non-void functions without return.
So if you want this program to work make it like Randomblock1, or like this:
int rec(int k)
{
static int counter = 0;
if(!k){
return counter;
}
else if(k%2 == 0){
counter ++;
counter += rec(k/2);
}
else{
counter++;
counter += rec(k-1);
}
return counter;
}
But this program also do not work well, what is the reason?
The reason is because you used by static variable.
It's a little hard to explain, but you can't use this recursion with a static variable, so add a patch to this line:
static int counter = 0;
like this
int counter = 0;
I hope what I wrote will be understandable

Control may reach end of non-void function ...Error in implementing binary search

I am trying to implement binary search on an array. I tried to get rid of this error that I get while compiling but could not. This is the function that I made for binary search:
bool BinSearch(int key, int Array[], int min, int max)
{
if (max < min)
return false;
else
{
int mid = (min + max)/2 ;
if (key > Array[mid])
BinSearch(key, Array, mid+1, max);
else if (key < Array[mid])
BinSearch(key, Array, min, mid-1);
else
return true;
}
}
Your main mistake is you are missing a return statement for your recursive calls to BinSearch. To make this explanation easier to understand I have added some parenthesis in your code to make everything more explicit. Note the code below is the same as your code, just with some (redundant) parentheses and more appropriate indentation.
Now lets assume we have a code path where max < min is false followed by key > Array[mid] being true. Therefore we have the following program execution, annotated in the code:
bool BinSearch(int key, int Array[], int min, int max)
{
if (max < min) { // Step 1, false
return false;
}
else {
// Step 2, start the else block
int mid = (min + max)/2 ;
if (key > Array[mid]) { // Step 3, true
BinSearch(key, Array, mid+1, max); // Step 4 call BinSearch
// Step 5, finished with call to BinSearch
}
else if (key < Array[mid]) {
BinSearch(key, Array, min, mid-1);
}
else {
return true;
}
// Step 6, Done with else block
}
// Step 7, Done with function, no return statement
}
A similar thing would happen if key > Array[mid] is false and key < Array[mid] is true. This should make it clear why your compiler correctly thinks there are code paths that do not have a return. The solution, as previously pointed out in the comments is to do return BinSearch(...).

Binary Search...Is something wrong with this code

I have only included the function. I am trying to implement binary search but for some reason it is not working. What I am really trying to determine is whether the algorithm is correct. It appears fine to me....but may be I am wrong. I know that the algorithm has to be sorted first but that will be taken care of in another function. Is the algorithm wrong or right? For some unknown reason the programme hangs...I have taken care of all the headers etc....i am off target or what? Thanks. Function is in C.
bool search(int value, int values[], int n)
{
int i;
int begin = 0;
int end = n-1;
int middle = (begin + end)/2;
for ( i = 0; middle <=end; i++)
if (value == values[middle])
{
return true;
break;
}
else if (value > values[middle])
{
begin = values[middle +1];
}
else
{
end = values[middle -1];
}
return false;
}
You do not need the loop on i.
Your loop would be on begin and end, such as while( begin < end )
Depending on how values[middle] compare with values[begin] and values[end], you have to adjust begin (begin = middle + 1;) or end (end = middle - 1;). Beware of the boundary cases!
(begin + end) / 2 may caused integer overflow in C. Try to use begin + (end - begin) / 2 instead.
What is the algorithm you have in mind ? I would suggest to go through the algorithm first .
http://en.wikipedia.org/wiki/Binary_search
Your middle is calculating to the end. It should be middle = (end - begin) / 2

Why is this binary search giving me an infinite loop?

I am trying to do a binary search. I really can't think of why I am getting an infinite loop? Is is because I ignored the null value somewhere? The value, values[], and n are being provided by a different file, and they are written by someone else, and are, for the purposes of this question, perfectly coded.
bool search(int value, int values[], int n)
{
int upper_bound = n - 1;
int lower_bound = 0;
int middle = (upper_bound + lower_bound) / 2;
while (lower_bound <= upper_bound)
{
if (values[middle] == value)
{
return true;
}
else if (values[middle] > value)
{
upper_bound = middle - 1;
}
else if (values[middle] < value)
{
lower_bound = middle + 1;
}
else
{
return false;
}
}
return false;
}
Thank you all so much.
You need to calculate the value of middle inside the while loop:
while (lower_bound <= upper_bound){
int middle = (upper_bound + lower_bound) / 2;
...
}
As the value of middle should change every time you are changing the value of either lower_bound or upper_bound.
the middle value is fixed. It is not changing as the values of upper_bound and lower_bound are changing.

Simplify/Neatify this two-way loop?

I've got my wires crossed somewhere (or I had not enough sleep). I need a two-way loop, and my current code is just plain ugly.
Problem: I am running along a linear datastructre using an index. I have an starting index, lets say 120. I want to run alternating into both directions.
Example:
120,121,119,122,118,123,117,...
I have a stopping criterion which needs to be met for each direction separately. If it is met for one direction, I only want to run into the other direction, if both are met I need to exit the loop. In addition I need to stop if the next index is invalid (end of data structure, say smaller than 0 or bigger than 200).
Example: Stopping execution at 116 backwards and 130 forward:
120,121,119,122,118,123,117,124,116,(break),125,126,127,128,129,130.
Running into one direction first, then the other one is unfortunately not an option.
My current code is plain ugly. It is a lot of lines without containing any "productive" code. Only iteration logic:
int start_idx = 120;
int forward_idx = start_idx;
int backward_idx = start_idx;
bool next_step_forward = true; //should next step be forward or backward?
int cur_idx;
while(backward_idx >= 0 || forward_idx >= 0)
{
if(next_step_forward //if we should step forward
&& forward_idx >= 0) //and we still can step forward
{
cur_idx = ++forward_idx;
if(forward_idx >= 200) //200 is fictive "max index"
{
next_step_forward = false;
forward_idx = -1; //end of data reached, no more stepping forward
continue;
}
if(backward_idx >= 0)
{
next_step_forward = false;
}
}
else if(!next_step_forward
&& backward_idx >= 0)
{
cur_idx = --backward_idx;
if(backward_idx < 0) //beginning of data reached, no more stepping backward
{
next_step_forward = true;
continue;
}
if(forward_idx >= 0)
{
next_step_forward = true;
}
}
else
{
next_step_forward = !next_step_forward; //ever hit?, just security case
continue;
}
//loop body
//do something with cur_idx here
if(stoppingCriterionMet())
{
if(cur_idx > start_idx)
{ //this was a forward step, stop forward stepping
forward_idx = -1;
}
else
{ //this was backward step, stop backward stepping
backward_idx = -1;
}
}
}
Am I missing anything? Any hints appreciated. Thanks.
Edit 1: There are lots of very nice answers, which put "do something with cur_idx" into a separate function. While this is a perfect idea for the way my question was asked, I prefer putting the iterating code somewhere else and leave the productive code there. I have a long algorithm and want to split it up after it is finished to minimize rearangement work.
How about this?
void do_loop(SomeType *arr, int start, int low, int high, int arr_max)
{
int downwardIndex, upwardIndex;
downwardIndex = upwardIndex = start;
while (downwardIndex > 0 && upwardIndex < arr_max) {
if (downwardIndex < low && upwardIndex > high) {
break;
}
if (downwardIndex > low) {
processElement(arr[downwardIndex]);
downwardIndex--;
}
if (upwardIndex < high) {
processElement(arr[upwardIndex]);
upwardIndex++;
}
}
}
It so happened that I coded almost this problem today. And I used a C# iterator function to do it. But I think you want a more generic solution.
If you use a language where you can build your own iterators (C++,Java,C#), it's easy. You just make a custom iterator that initially spits out numbers starting from the center. Then you give the iterator an extra function to tell it to stop running in the current direction.
If you're doing something like this in C (it looks C to me), you can mimic this with a struct containing the iterator state, and functions that you call to step it forward or stop it.
First pass at hacking this (assuming C - adaptations needed for other languages, but the concepts are basically language neutral):
void pass1(int start_x, int lo_limit, int hi_limit)
{
assert(start_x >= lo_limit && start_x <= hi_limit);
int lo_x = start_x - 1;
int hi_x = start_x + 1;
Process(start_x);
if (StopCriterion(start_x))
return; // Is that correct?
while (lo_x >= lo_limit && hi_x <= hi_limit)
{
Process(lo_x);
if (StopCriterion(lo_x))
lo_x = lo_limit - 1;
else
lo_x--;
Process(hi_x);
if (StopCriterion(hi_x))
hi_x = hi_limit + 1;
else
hi_x++;
}
while (lo_x >= lo_limit)
{
Process(lo_x);
if (StopCriterion(lo_x))
lo_x = lo_limit - 1;
else
lo_x--;
}
while (hi_x <= hi_limit)
{
Process(hi_x);
if (StopCriterion(hi_x))
hi_x = hi_limit + 1;
else
hi_x++;
}
}
It is not clear what should happen if the starting position matches the stop criterion. Should the search stop altogether, or should it continue upwards, or downwards, or both ways. I chose 'stop altogether', but a case could be made for any of the options listed. In the case of 'both', you would not even bother to run the stop criterion check.
I also chose to do the lower before the upper direction; it is clearly trivially reversed. The order of the final two loops doesn't matter because if both directions terminate in the same iteration, neither trailing loop is executed; if only one direction is terminated, the corresponding loop won't execute at all - only the other will.
Since there is still repeated code in there:
void pass2(int start_x, int lo_limit, int hi_limit)
{
assert(start_x >= lo_limit && start_x <= hi_limit);
int lo_x = start_x - 1;
int hi_x = start_x + 1;
Process(start_x);
if (StopCriterion(start_x))
return; // Is that correct?
while (lo_x >= lo_limit && hi_x <= hi_limit)
{
Process_lo(&lo_x, lo_limit);
Process_hi(&hi_x, hi_limit);
}
while (lo_x >= lo_limit)
Process_lo(&lo_x, lo_limit);
while (hi_x <= hi_limit)
Process_hi(&hi_x, hi_limit);
}
void Process_lo(int *lo_x, int lo_limit)
{
Process(*lo_x);
if (StopCriterion(*lo_x))
*lo_x = lo_limit - 1;
else
*lo_x--;
}
void Process_hi(int *hi_x, int hi_limit)
{
Process(*hi_x);
if (StopCriterion(*hi_x))
*hi_x = hi_limit + 1;
else
*hi_x++;
}
Visibility controls (static functions) etc left out as details of the implementation language.
This is how I'd approach it in C#:
const int UPPER_BOUND = 200;
const int LOWER_BOUND = 0;
const int START = 120;
bool foundlower = false, foundupper = false;
int upper, lower;
upper = lower = START;
while (!foundlower || !foundupper) {
if (!foundlower) {
if (--lower <= LOWER_BOUND) foundlower = true;
if (stoppingCriterionMet(lower)) foundlower = true;
}
if (!foundupper) {
if (++upper >= UPPER_BOUND) foundupper = true;
if (stoppingCriterionMet(upper)) foundupper = true;
}
}

Resources