Multiple return statements inside recursive function - c

I'm currently reading "Practical C Programming 3rd Edition" by Steve Oualline.
Currently I'm on the Chapter 2 reading about Recursion, in this chapter the author proposes an exercise where the reader must try to write a recursive function that counts the number of times a number appears in an array.
Please consider the following code:
#include <stdio.h>
size_t count(const int [], size_t, int);
enum {ARRAY_LEN = 11};
int main()
{
const int num_array[ARRAY_LEN] = {1, 2, 3, 4, 5, 5, 6, 7, 3, 9, 0};
int number = 0;
puts("Type a number: (0-9)");
scanf("%d", &number);
printf("Number of appearances: %lu\n", count(num_array, ARRAY_LEN, number));
return 0;
}
size_t count(const int n_array[], size_t arr_len, int num)
{
return arr_len == 0 ? 0 : ( n_array[arr_len - 1] == num ) + count( n_array, arr_len - 1, num );
}
My questions are:
How does C know which return to take back to the main function? Because, in this example we have 3 returns, and all of them in a certain time their conditions become true, so, how does C know that with a return 0; it must exit the recursive function and not continue in search for another return inside the count() function?
Thanks.

When you have recursive function calls, you have multiple "instances" of a function active, calling and returning to each other. To visualize this, I find it useful to imagine that, instead of a C program running on a computer, you have a bunch of people in a room, and you all give them an identical set of instructions, and then you ask them to start solving a problem for you. For the code in your question it would go something like this.
You pick a person and say, "Hey, John, here's an array of size 3: [1, 2, 3]. Can you tell me how many times the number 2 appears in it?"
John takes the array from you, and he looks at his instructions. The array is not of size 0, so he doesn't tell you 0. The last element of his array is not 2, so he doesn't do the second thing, either. But to do the third thing, he needs to make a recursive call, so he picks someone else in the room and he says, "Hey, Mary, here's an array of size 2: [1, 2]. Can you tell me how many times the number 2 appears in it?"
Mary takes the array from John, and she looks at her instructions. The array is not of size 0, so she doesn't tell John 0. But the last element of her array is 2, so she does do the second thing. But to do the second thing, she also needs to make a recursive call, so she picks someone else in the room and she says, "Hey, Fred, here's an array of size 1: [1]. Can you tell me how many times the number 2 appears in it?"
Fred looks at his instructions. The array is not of size 0, so he doesn't tell Mary 0. The last element of his array is not 2, so he doesn't do the second thing. He, too, needs to make a recursive call to do the third thing, so he picks someone else in the room and says, "Hey, Jane, here's an array of size 0: []. Can you tell me how many times the number 2 appears in it?"
Jane looks at her array, and the size is 0. So she says, "Fred, the number of times that 2 appears in that array is: 0".
That's what Fred was waiting for. Fred was working on the third return statement, so whatever he hears from Jane is his answer, too. He says, "Mary, the number of times that 2 appears in that array is: 0".
That's what Mary was waiting for. But she was working on the second return statement, so she adds 1 to whatever she hears from Fred. She says, "John, the number of times that 2 appears in that array is: 1".
That's what John was waiting for. John was working on the third return statement, so whatever he hears from Mary is his answer, too. He says to you, "The number of times that 2 appears in that array is: 1".
And now you have your answer!
I used to teach a C programming class, and one day I gave everyone in the class a handout which was some human-readable instructions on how to do a recursive, in-order traversal of a binary tree. Then I handed a "binary tree" -- a piece of cardboard with a bunch of yellow stickies arranged on it in a tree-like structure -- to a random student in the front row, to start traversing. It was absolute pandemonium, but also great fun. (I think. I thought it was fun, anyway!)

CPUs have a stack. This is a very important data structure, which describes execution context. A stack may look like this:
count(4, {10, 20, 30}, 3)
count(4, {10, 99, 33, 22}, 4)
count(4, {10, 99, 33, 22, 44}, 5)
main(1)
When a CPU calls a function, it adds another stack frame on top (actually, some people or debuggers visualize it upside-down, so it may be at the bottom).
When a CPU returns from a function, it removes a stack frame from the top, and continues from an execution point which is now at the top.
If you visualize this stack, you will see that each return statement doesn't have any definite destination - it's the stack which tells CPU where to continue execution. If main calls count, it returns to main, but if count calls count, it returns to count. But not only that - it remembers which invocation to return to.
A stack frame contains a copy of all the parameters with which a function was called, and a copy of the function's local variables (it's not always a copy, but the simplest and most important case is when it's really a copy).

For starters the function definition with multiple return statements is bad.
Moreover the function should be declared like
size_t count( const int [], size_t, int );
The function can be defined the following way
size_t count( const int a[], size_t n, int num )
{
return n == 0 ? 0 : ( a[n-1] == num ) + count( a, n - 1, num );
}
That is the return type of the function shall be size_t. The first parameter of the function shall have the qualifier const because the array passed to the function is not changed within the function.
And in main you should write
printf( "Number of appearances: %zu\n", count( num_array, ARRAY_LEN, number ) );
As for your question then it is clear that the control within the function will be passed to a return statement dependent on used conditions in the if statements.
if the value of arr_len is equal to 0 then the control will be passed to the return statement inside this if statement.
if(arr_len == 0)
return 0;
Pay attention to that in each recursive call of the function the value of the parameter arr_len is decremented.
So it is the base case of the function when arr_len is equal to 0. In this case the function stops its execution.
Otherwise if arr_len is not equal to 0 then if the last element of the array is equal to num then 1 is added the value returned by the next recursive call and the sum is returned. Otherwise if the last element of the array is not equal to num then the value returned by the next recursive call of the function is returned.
if(n_array[arr_len - 1] == num)
return (1 + count(num, n_array, arr_len - 1));
else
return count(num, n_array, arr_len -1);

This is what recursive programming is all about.
The code uses the first return it encounters in the if chain. If that return recursively calls "count" then that return is put on hold until the nested "count" call returns. This continues until everything has returned on arr_len == 0.

Related

could someone tell me what is wrong with this?

Question: wow, you are given two things:
The calling order in which all the processes are called.
The ideal order in which all the processes should have been executed.
Now, let us demonstrate this by an example. Let's say that there are 3 processes, the calling order of the processes is: 3 - 2 - 1. The ideal order is: 1 - 3 - 2, i.e., process number 3 will only be executed after process number 1 has been completed; process number 2 will only be executed after process number 3 has been executed.
Iteration #1:
Since the ideal order has process #1 to be executed firstly, the calling ordered is changed, i.e., the first element has to be pushed to the last place. Changing the position of the element takes 1 unit of time. The new calling order is: 2 - 1 - 3. Time taken in step #1: 1.
Iteration #2: Since the ideal order has process #1 to be executed firstly, the calling ordered has to be changed again, i.e., the first element has to be pushed to the last place. The new calling order is: 1 - 3 - 2. Time taken in step #2: 1.
Iteration #3: Since the first element of the calling order is same as the ideal order, that process will be executed. And it will be thus popped out. Time taken in step #3: 1.
Iteration #4: Since the new first element of the calling order is same as the ideal order, that process will be executed. Time taken in step #4: 1.
Iteration #5: Since the last element of the calling order is same as the ideal order, that process will be executed. Time taken in step #5: 1.
Total time taken: 5 units.
S: Executing a process takes 1 unit of time. Changing the position takes 1 unit of time.
Input format:
The first line a number N, denoting the number of processes. The second line contains the calling order of the processes. The third line contains the ideal order of the processes.
Output format:
Print the total time taken for the entire queue of processes to be executed.
Constraints: 1<=N<=100
SAMPLE INPUT
3
3 2 1
1 3 2
SAMPLE OUTPUT
5
The first method that came to me was to declare a variable and increase it by one after every swap plus 2, but then if we take an array of size 3, there are only two possibilities. Hence I printed those out, and yes guys this is a problem from an online judge, there was no syntax error, but in the site it tells that there was some problem in declaration, I have no clue what to do I am new to programming and can someone suggest a new method which is applicable for arrays of bigger sizes.
#include <stdio.h>
swap(a,b);
long long int a,b;
int main(void) {
long long int n,i;
long long int a[3],b[3];
scanf("%d",&n);
for(i=0;i<=2;i++)
{
scanf("%d",a[i]);
}
for(i=0;i<=2;i++)
{
scanf("%d",&b[i]);
}
if(a[i]=b[i])
{
printf("2");
}
while(a[i]!=b[i])
{
swap(b[0],b[2]);
swap(b[0],b[1]);
{
if(a[i]=b[i])
printf("5");
}
}
return 0;
}
swap(a,b){
long long int temp;
a=temp;
b=a;
temp=b;
return swap(a,b);
}
Your swap() function has multiple issues:
1: It calls itself with return swap(a,b); in the last line of the function. This will result in infinite recursion and a stack overflow.
2: You need to declare the return type of the function. If it takes two long long parameters and returns nothing, then it should be declared as follows:
void swap(long long a, long long b);
3: As written, the function will have no effect anyway. You need to pass pointers to these variables if you want to change their values:
long long swap(long long *a, long long *b);
4: To pass pointers to this function, prefix the parameters with & as follows:
swap(&b[0],&b[2]); /* NOT: swap(b[0],b[2]); */
5: The order of operations in the swap() function is also wrong. You start by irretrievably losing the value of a instead of storing it so that it can be assigned to b. Try this instead:
void swap(long long *a, long long *b) {
long long temp;
temp = *a;
*a = *b;
*b = temp;
}
NOTE: Please learn how to format your code properly. Also, always compile your development code with warnings enabled (e.g., add -Wall -pedantic to the command line). Doing so would have drawn your attention to most if not all of these problems without having to ask here.

How does this code that prints 1 to 1000 work in C?

I've seen a C program that prints 1 to 1000 without using any looping structure or conditional statements, but I don't understand how it works. Can anyone go through the code and explain each line?
See live demo here. Why does it result in a runtime error?
#include <stdio.h>
#include <stdlib.h>
int main(int i)
{
printf("%d\n",i);
((void(*[])()){main, exit})[i / 1000](i + 1);
return 0;
}
((void(*[])()){main, exit})[i / 1000](i + 1);
This line create a two-element array of function pointers, with the first element containing the main function, and other element containing the exit function.
It then indexes this array by i / 1000. This either gets the main function if i < 1000 or the exit function when i == 1000.
It then calls the function pointer that it just indexed with i+1 as the argument.
It's a recursive function, with the stopping condition determined with an array index rather than a conditional. I don't think it's valid C however; main's signature is wrong, and the cast to a function pointer removes the return type from the main function.
Breaking down the line that you asked about
((void(*[])()){main, exit})
This is an array literal, which creates an unnamed temp array of two function pointers, and initializes those pointers to point at main and exit
[i / 1000]
This indexes that temp array. Integer division truncates towards 0, so when 0 <= i < 1000, this gets element 0 (the pointer to main) and when 1000 <= i < 1999, it gets element 1 (the pointer to exit)
(i + 1);
This calls the pointed at function with i+1 as an argument.
There are a bunch of things here that are undefined behavior. Declaring main as having a single int argument is illegal according to the standard, though generally will work, getting the number of command line arguments as the single argument. Getting a pointer to main is likewise undefined, as main is a special function that may have a non-standard calling convention.
This code is a good example of how far you can bend C without breaking it. You shouldn't attempt to understand this until you can write understandable C.
Here are the key features and assumptions:
First, assume that the program is called without arguments. The parameter i is in the place usually called argc, so it will have the initial value 1 (the number of elements in the array of arguments, usually called argv).
Next, assume that the single-argument form of main doesn't cause any problems. Officially supported forms of main are with no arguments, 2 arguments (argc, argv), and sometimes 3 arguments (argc, argv, envp).
So the first printf prints 1.
Next we have a compound literal. It might be easier to understand if you look at a simpler one first:
(int[]){10,20}
That's an anonymous array of 2 ints, with values 10 and 20. int[] is the type. It goes in parentheses before a braced list of values. So what's this:
(void(*[])()){main, exit}
void(*[])() is a type. It means array of function pointers with the signature void (*foo)(). The type name in parentheses followed by a braced list is compound literal, just like the (int[]){10,20} example. In this case, it creates an array of 2 function pointers whose elements are main and exit.
Assume that the mismatch between the function pointer type (returns void) and main (returns int) doesn't cause a problem.
This:
((void(*[])()){main, exit})[i / 1000]
is our anonymous array of 2 elements, inside some redundant parentheses, followed by [i / 1000]. That's just normal array indexing syntax. If i/1000 is 0, you get the first element of the array (thearray[0]), which is main. That happens for all i is between 0 and 999. If i/1000 is 1, which happens when i==1000, we're looking at thearray[1], which gets us the second element: exit.
So far, we have an expression taht is equal to main when i<1000 and equal to exit when i==1000.
Now look at the whole statement:
...that_big_thing_that_is_either_main_or_exit...(i + 1)
A function pointer, followed by a parenthesized argument list. That's a function call. Whichever function we chose from the array, now we're going to call it, providing an argument that is equal to the incoming argument (i) plus 1.
So the first call, when i is 1, selects main for the function and i+1 = 1+1 = 2 for the argument. It calls main(2).
main(2) does a printf which prints the 2, and then calls main(3).
main(3) does a printf which prints the 3, and then calls main(4).
...and so on until...
main(999) does a printf which prints the 999, and then calls main(1000).
main(1000) does a printf which prints the 1000, and then calls exit(1001).
None of the calls to main ever return, and the return 0 never happens, because the exit terminates the process. The fact that the process returns an exit code of 1001 rather than 0 appears to be the reason for ideone's "runtime error" message.
The main function is called recursively.
void print_nb(int n)
{
if (n <= 1000)
{
printf("%d\n", n);
print_nb(n + 1);
}
}
Like Sourav Ghosh said, it's prohibited to use with main() recursively, better use another function.

Find steps to find given value of index

I am new to SO - I have a question which I was asked in interview and which for life of me I am not able to wrap my head around. I can solve it with while/for loop but interviewer specifically asked not to use them I even discussed with few friends of mine but unable to solve it. If someone can provide pointers.
Question is:
for given array
s[] = {5,1,0,4,2,3}
length of array is not given.
If length of array is 5 content
is guaranteed to be between 0 to 5.
There is no repetition of
numbers.
Sample example length(s, 3)
- a[3] = 4 , a[4] = 2, a[2] = 0, a[0] = 5, a[5] =3 returns length of 4 .
For given condition write subroutine int length (s, 3) - to find the number of steps it takes to find given value -
Additional conditions
You cannot use any loop statements like for, while and so on -
You cannot use any global or static variables.
You cannot call other routines inside this routine
You cannot modify given function parameters - it stays length (s, n) only
You cannot change original array too
Alternative solution that does not modify the array at all, but hides an extra parameter inside top 16 bits of x:
int length(int *s, int x){
int start = (x >> 16) - 1;
if (start < 0)
start = x;
if (s[x] == start)
return 0;
return 1 + length(s, ((start + 1) << 16) + s[x]);
}
This will fail if there are too many elements in the array, but I suspect any other recursive solution is likely to hit a stack overflow by that point in any case.
I think I found the answer eventually no I didnt crack it but found it online :) .. Here is the solution
int length(int * s, int x){
if(s[x] < 0){
return -1;
}
else{
s[x] = -s[x];
int len = length(s, -s[x]);
s[x] = -s[x];
return len + 1;
}
}
i don't think it contradicts with any of your conditions. i just didn't use the array as a parameter (that isn't a problem actually, you can modify it yourself)
int s[] = {5,1,0,4,2,3};
bool col[100]; ///to check cycle
int rec(int n)
{
if(col[n])return 0;
col[n]=true;
int sum=0;
sum = 1+rec(s[n]);
return sum;
}
The interviewer is probing your understanding of algorithms and programming paradigms, trying to understand your training, background, and depth. The interviewer has a challenging task; identifying capable developers with minimal evidence. Thus the interviewer presents a constructed problem that (they hope) elicits the desired knowledge (does candidate X know how to solve problem Y, or understand concept Z) perhaps because the interviewer believes the desired answer indicates the candidate knows the expected body of knowledge.
Modern languages provide several repetition structures (commands, statements), some which pre-test (check condition before entering statement-block), and some which post-test (check condition after performing statement block at least once). Here are examples,
Pre-test
while(condition) statement-block
for(initializer;condition;step) statement-block
Post-test
do statement-block while(condition)
repeat statement-block until(condition)
do statement-block until(condition)
These can all be written as conditional (choice) structures with branching (goto),
Pre-test
label:
if(condition)
statement-block;
goto label;
else
nil;
endif
Post-test
label:
statement-block;
if(condition)
goto label;
endif
You can also use recursion, where you call the same function as long as condition holds (or until condition met, depending upon positive or negative logic),
Pre-test
function recurse(args)
if(condition)
statement-block
recurse(revised args);
endif
return
end #function
Post-test
function recurse(args)
statement-block
if(condition)
recurse(revised args);
endif
return;
end
You would learn about recursion in an algorithms, or perhaps a computability course. You would learn about conditional branching in a compiler, high performance computing, or systems class. Your compiler course might examine techniques for detecting 'tail-recursion', and how to rewrite the function call into a loop.
Here is the problem, restated,
given array, s[] = {5,1,0,4,2,3}
array length unknown
content between [0 .. length], not repeated, no duplicates
write subroutine which provides the number of steps to find given value
That is,
int length( array s, int member ) --> position
Examine the conditions (constraints) on the problem,
Array length unknown - Solution must work for variable range of inputs
Cannot use loop statements (for, while, etc) - This suggests either the interviewer wants conditional branch or recursion.
Cannot use global or static variables - Does this suggest interviewer wants a recursive/functional-programming solution? Conditional-branch also provides this.
Cannot call other routines inside this routine - Does interviewer mean functions other than same function, or call any function (what does interviewer mean by 'other').
Cannot modify function parameters, stays length(s,n) - Declaring local (stack) variables is allowed. This could mean pass by value, make a local copy, etc. But not destructive modifications.
Cannot change original array - Definitely no destructive modifications. Possible 'hint' (ok to make local copy?), or further indication that you should use conditional-branch?
Here are two solutions, and a test driver (note, I have named them lengthi, iterative, and lengthr, recursive).
#include <stdio.h>
/* conditional branch */
int lengthi( int s[], int member )
{
int position=0;
AGAIN:
if( s[position] == member ) return(position);
++position;
goto AGAIN;
return(-1);
}
/* recursive */
int lengthr( int s[], int member )
{
if( s[0] == member ) return(0);
return( 1+length(s+1,member) );
}
int
main(int argc,char* argv[])
{
int s1[] = {0,1,2,3,4,5,6,7,8,9};
int s2[] = {1,2,3,4,9,8,7,6,0,5};
int s3[] = {2,4,6,8,0,1,3,5,7,9};
printf("%d at %d\n",3,lengthr(s1,3));
printf("%d at %d\n",3,lengthr(s2,3));
printf("%d at %d\n",3,lengthr(s3,3));
printf("%d at %d\n",3,lengthi(s1,3));
printf("%d at %d\n",3,lengthi(s2,3));
printf("%d at %d\n",3,lengthi(s3,3));
}
Since we are supposed to find the number of steps (iterations, function calls), that is asking for the ordinal position in the list, not the C index (zero based) position.
This is an interview question, and not a programming problem (per se), so probably better suited for the Programmers.stackexchange site. I might give the interviewer an entertaining answer, or their desired answer.

difficulty in understanding successive recursive calls

I am trying to understand the following program in which successive recursion function calls are present, but getting confused while tracing how the tack gets loaded.
void func(char*); // function prototype
int main(){
func("123");
return 0;
}
void func(char a[]){
if(a[1]=='\0')
return;
func(a+1);
func(a+1);
printf("%c",a[1]);
}
the output for this is 3 3 2
would appreciate if someone could advise on this one...
does this kind of multiple recursive calls beneficial in any way or find application in specific problem areas..?
Just put yourself in the position of the CPU and step through line-by-line (or use a debugger to help with that task).
The first call is to
func("123")
this call does not satisfy the termination condition a[1] == '\0', so it calls
func("23");
The call to func("23") in turn calls
func("3")
which DOES satisfy the return condition. So, that call returns to the previous caller, func("23").
func("23") proceeds to make another call to func("3") due to the lines
func(a+1);
func(a+1);
Continue this process of executing the program in your mind, and write down what would be in each call to printf. That will explain your output.
UPDATE
Note that the call to printf() happens after the recursive calls, so e.g. a call to
func("123")
would proceed like
Enter func("123")
Termination condition not met
Call func("23")
Call func("23") again
Printf("3") (which is a[1])
Return
Debugging with breakpoints is one way to understand recursion. Another way is to draw the tree of recursive calls.
From the figure, In every level after level0, the printf statement occurs after every two nodes owing to these two lines of code:
func(a+1);
func(a+1);
In general, this becomes a perfect binary tree for any input string of length greater than 0. The total number of nodes is given by this formula:
2^(k+1) - 1 // k is the depth; here k = 2
Total number of printf statements executed can be obtained by this formula:
2^k - 1 // For k=2, there will be 3 printf statements each printing 3,3,2 respectively
the posted code is a rather poorly designed instance of recursion.
The following code has the correct 'tail' form of recursion.
It could be made even better by passing the reversed string back to main and let main print it.
It reverses the order of the string passed to func() by main()
Please, when asking about a runtime problem, post code the compiles, including the necessary #includes for header files so we are not guessing about which headers to include
#include <stdio.h>
void func(char*); // function prototype
int main(){
func("123");
return 0;
}
void func(char a[])
{
if(a[1]=='\0') // check for end of recursive sequence
{
printf( "%c", a[0] ); // last tail action
return;
}
func(a+1); // step+next recursion
printf( "%c", a[0] ); // tail action
return;
}
The recursion can be simply understood as follows.
For example:
Func(int a){
while(a>1)
return a * func(a-1);
}
Suppose a = 5.
What happens is that it returns 5 * func(4).
Now func(4) returns 4 * func(3) and it goes on like this.
Check out this example for use of recursion in fibonacci series.

How to understand a recursive function call for large inputs

The result of the following code is 0,1,2,0, I totally understand after writing explicitly every call. But I wonder whether there is an easier method to understand what the recursive function want to realize and find the result faster? I mean we can't write all the call if a=1000.
#include<stdio.h>
void fun(int);
typedef int (*pf) (int, int);
int proc(pf, int, int);
int main()
{
int a=3;
fun(a);
return 0;
}
void fun(int n)
{
if(n > 0)
{
fun(--n);
printf("%d,", n);
fun(--n);
}
}
Your question isn't "what does this do?" but "how do I understand recursive functions for large values?".
Recursion is a great tool for certain kinds of problems. If, for some reason, you ever had to print that sequence of numbers, the above code would be a good way to solve the problem. Recursion is also used in contexts where you have a recursive structure (like a tree or a list) or are dealing with recursive input, like parsers.
You might see the code for a recursive function and think "what does this do?" but it's more likely that the opposite will happen: you will find a problem that you need to solve by writing a program. With experience you will learn to see which problems require a recursive solution, and that's a skill you must develop as a programmer.
The principle of recursion is that you perform a [usually simple] function repeatedly. So to understand a recursive function you usually need to understand only one step, and how to repeat it.
With the above code you don't necessarily need to answer "what output does this code give" but instead "how does it work, and what process does the code follow". You can do both on paper. By stepping through the algorithm you can usually gain insight into what it does. One factor that complicates this example is that it isn't tail-call recursive. This means you must do more work to understand the program.
To 'understand' any program you don't necessarily need to be able to simulate it and calculate the output, and the same applies here.
All you need to do is add some debug statements to understand it a little better. This is the result of the if statements I added to track through it:
start program
before if, n is = 3
before fun call, n is = 3
before if, n is = 2
before fun call, n is = 2
before if, n is = 1
before fun call, n is = 1
before if, n is = 0
printing = 0
before if, n is = -1
after second fun call, n is = -1
printing = 1
before if, n is = 0
after second fun call, n is = 0
printing = 2
before if, n is = 1
before fun call, n is = 1
before if, n is = 0
printing = 0
before if, n is = -1
after second fun call, n is = -1
after second fun call, n is = 1
end program

Resources