Looking at this code which passes values to functions the usual way (by value, not by reference/pointer):
funky(x)
{
if (x > 0) {
x -= 1
funky(x)
}
printf("%d," x)
}
int tester()
{
funky(x passed in as 5)
return 0
}
What will the displayed output be?
Is int tester being passed in as the value for x at the top, the funky(x) -= 1 code? If it is then would that just print 4? Nothing is being declared as an int or string so I am not sure what will print.
I decided to help you with your learning by providing you with actually compilable code which, I am convinced, will further exactly the same learning goals as what you are currently studying. I will of course not provide you with the output of the shown code (or the shown code changed to be compilable). For two reasons. One: I don't want to do the quiz for you. Two: I want to help you learn, not hinder you.
So this code, if compiled and run:
#include <stdio.h>
int funky(int x)
{
printf("in %d, ", x);
if (x > 0)
{
x -= 1;
printf("mid %d, ", x);
funky(x);
}
printf("out %d, ", x);
}
int main()
{
funky(/* x passed in as */ 5);
return 0;
}
will get you the hopefully enlightening output:
in 5, mid 4, in 4, mid 3, in 3, mid 2, in 2, mid 1, in 1, mid 0, in 0,
out 0, out 0, out 1, out 2, out 3, out 4,
It supports your understanding by making obvious which output is caused by which code part. I added a second and third output to help you understand the recursion trickery used in the quiz code. And I added a newline to the output, simply for readability here. (Side effect of intentionally not giving the character precise output here...)
With the syntax fixes in the code I intend to answer the side questions in your post, while the real puzzle is clarified by the visualisation of the relevant values before and after the recursive call.
Related
There is this Mario problem in the CS50 course and it's easy using the recursion method, except that when I try to add any arithmetic operation it shows (invalid operands to binary expression ('void' and 'int')). It's just for the sake of me to understand what I can do using recursion and what I can't; the problem is this line (sum(n-1)+n;)
Here is the code:
#include <cs50.h>
#include <stdio.h>
void sum(int n);
int main ()
{
int u = get_int("f");
sum (u);
}
void sum(int n)
{
if (n==0)
{
return;
}
sum(n-1)+n;
for(int i = 0 ; i < n; i++)
{
printf( "#");
}
printf("\n");
}
The error you are seeing is from this line:
sum(n-1)+n;
sum is a function that returns void, but you are trying to add it with an integer n.
I am not quite sure what that get_int("f") does, but I assume it's prompting to the user for an int input, and you are trying to sum from 0 to that number. Here is the solution:
int sum(int n) // Here is the critical change to your code, now it returns an int
{
if (n == 1) // Root case that will stop the recursion, otherwise, it's endless
return 1; // 1 = 1 + 0;
return sum(n-1) + n; // Recursion
}
Think about what we are trying to achieve here. We want to add from 0 to n, or to say from n to 0 downwards. If n is 3, it's going to be 3+2+1+0, and you'll notice that 3 is just n, and 2 is n - 1, 1 is (n - 1) - 1, etc. To visualize it:
before sum(3) could return anything, it calls sum(2) + 3;
before sum(2) could return anything, it calls sum(1) + 2;
1 is our root case, and there is no more calls, so sum(1) is going to return 1;
that 1 is returned to step 2, so sum(1) + 2 becomes 1 + 2, which is 3, and that is the value sum(2), and it returns its result to step 1, and step 1 becomes 3 + 3, which is 6, and the initial call to sum is then completed.
I hope that makes sense to you. Recursion is not an easy technique to master. Take your time, but you need to understand how function calls work in memory. Here is a video that illustrates how recursive calls in memory look like, Data Structures Using C++: Illustration of Recursive Function Calls (Call Stack).
It is because the return type of the function sum() is void.
You cannot add anything to void.
Anyway the result of the "addition" is thrown away, so you won't need addition.
This mean that sum ( n-1)+n; should be replaced with sum ( n-1);.
I've been looking at examples of recursion (in C) online in an attempt to get a better understanding of it and how it works. Generally speaking, I can trace some basic recursion problems without issue (such as a factorial problem), but I found this one and am completely lost on how to trace it.
The idea is that you have the user enter an amount of change, and by using recursion, you print out the number of ways that amount of change can be made. The code is as follows:
#include <stdio.h>
#define NUM_DENOMS 4
int ways(int amount, int denomination);
int main()
{
//Declarations & initializations
int userChange = 0;
//Get user input
printf("Enter an amount you wish to get change for (in cents):\n");// get the amount of change in from the user
scanf("%d", &userChange);
//Function call... pass user's input and denomination values (ints) as parameters
printf("%d cents can be made in %d different ways\n", userChange, ways(userChange, NUM_DENOMS));
return 0;
}
//Function to find # of ways to make change for user's amount
int ways(int amount, int denomination)
{
static int validAmounts[NUM_DENOMS] = {1, 5, 10, 25};
if(denomination<=0) //if denomination is invalid
{
return 0;
}
if((amount == 1) || (amount == 0)) //base case: only 1 combination
{
return 1;
}
else if(amount < 0) //can't have negative amount of money
{
return 0;
}
else //if denomination is valid and user's change > 1
{
return ways(amount, denomination-1) + ways(amount-validAmounts[denomination-1], denomination);
}
}
Apparently this is a common application of recursion. I can't wrap my head around how this recursion works though. What stands out to me the most is the fact that there are 2 recursive calls on the same line. I have never seen recursion applied in this way.
I did attempt to trace it but my results are definitely wrong:
Say I enter 25 as the amount of change. When I go into the ways function, none of the base cases are satisfied and so the recursion comes into play. For the first call, amount stays the same and denomination is decreased by 1, so we go back into the function with 25 and 3 (4-1) as our new arguments. None of the base cases are met until denomination is reduced to 0 (since amount never changes). At this point, we are returning 0. This is the point where I get lost. I see it that 0 gets sent back through all the previous calls and so the end result is 0, but that doesn't sound right to me. I run into the same problem when trying to trace the second call except instead of 0 getting sent back through the calls, it is 1. Obviously my perception of this recursion is horridly wrong. Can someone explain to me how this instance of recursion actually works?
One way to trace a recursive algorithm is to put a printf at the top of the recursive function. The printf should print out the arguments to the function. It's also a good idea to temporarily add more parameters to give yourself additional information about what the recursion is doing. The most common additional parameter is a depth parameter that shows how many nested calls have been made. And for this particular question (where you have two recursive calls) I would add an additional parameter to identify which call is being traced.
With that in mind, here's the modified code. I suggest starting with a simple input, like 5, to get a feel for how the recursion works.
#include <stdio.h>
#define NUM_DENOMS 4
int ways(int amount, int denomination, int left, int depth);
int main( void )
{
int userChange = 0;
printf("Enter an amount you wish to get change for (in cents):\n");
scanf("%d", &userChange);
printf("%d cents can be made in %d different ways\n", userChange, ways(userChange, NUM_DENOMS, 'M', 0));
return 0;
}
int ways(int amount, int denomination, int left, int depth)
{
static int validAmounts[NUM_DENOMS] = {1, 5, 10, 25};
printf( "%2d %d %c %2d\n", amount, denomination, left, depth );
if(denomination <= 0 || amount < 0)
return 0;
if((amount == 1) || (amount == 0))
return 1;
return ways(amount, denomination-1, 'L', depth+1) + ways(amount-validAmounts[denomination-1], denomination, 'R', depth+1);
}
The code makes two calls because it breaks the problem into two parts and each part is solved the same way. Each part is in some sense simpler than the original problem and the same method is used to solve each individual problem. As pointed out by others, there may be situations in which there are more than two parts.
You have likely seen examples with one call where one part of the problem is solved and the single recursive call solves the 'remainder' of the problem.
I've written a function intended to use the modulus operator to output a random number between 1 and a variable named sum and analyze the value based on the range within which the random number falls. I've been running into trouble with the function, though: I used the following line of code to output the random number.
random = rand()%sum + 1
However, for some reason, I get extremely high numbers that don't fall within the range. I've seeded the function in the main program before calling the function, so I don't understand why it's not working. Any ideas on how to fix this? Thanks!
EDIT: Here's the function in my program:
int comp_output (int row, int array[][3], int sum) {
int random;
random = rand()%sum + 1;
if (random <= array[row][0]) {
return 0;
}
else if (random >= sum - array[row][2] + 1) {
return 2;
}
else {
return 1;
}
}
The array is initialized before the function is called, so that's not the problem. Does anything look wrong with the function as I've presented it? Thanks to everyone who's helped so far!
There is nothing wrong in your program. I tested your function and indeed if I add printf("%d\n", random); to it and if sum is 5, then the value can be either 1, 2, 3, 4 or 5 but nothing else. I don't understand what your problem is, but it is not in the line of code you highlighted. It generates random numbers between 1 (inclusive) and sum (inclusive). However, you didn't provide the full code so it isn't possible to understand from your limited code what the real purpose of the full comp_output function is.
Do note that using the low-order bits of the rand() implementation may not necessarily be a good idea. rand()%2 on many systems provides an alternating sequence 0, 1, 0, 1, 0, 1, 0, 1, ... The real fix is obviously to use a better random number generator such as the Mersenne Twister (http://en.wikipedia.org/wiki/Mersenne_twister) or PCG (http://www.pcg-random.org/).
Hello getting better at C everyday, this is a example problem out of my textbook that generates fibonacci numbers and shows recursive functions. The program works but I just don't understand how... Specifically in parts (looper % 5), the whole functionfib and what printf(", %8ld", fib(looper)); is doing. Is it like saying fib() do x amount of times. If this problem is not easy to explain then could someone show me a easier way to understand how recursive functions work other then "towers of hanoi" example. Thanks.
NOTE: program is meant to handle up to 30 numbers others wise it starts to look ugly.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
long fib (long num);
int main(void)
{
int seriesSize;
printf("This program will print out a Fibonacci series.\n");
printf("How many many numers do you wnat? ");
scanf_s("%d", &seriesSize);
printf("First %d Fib numbers: \n", seriesSize);
for (int looper = 0; looper < seriesSize; looper++)
{
if (looper % 5)
{
printf(", %8ld", fib(looper));
}
else
{
printf("\n%8ld", fib(looper));
}
}
printf("\n");
return 0;
}
long fib(long num)
{
if (num == 0 || num == 1)
{
return num;
}
return (fib(num - 1) + fib(num - 2));
}
The idea behind the long fib(long num) function is that it mirrors the natural definition of the fibonacci sequence in that it is defined in terms of itself. That is, fib(n) is defined by fib(n-1) and fib(n-2). For example, fib(5) is fib(4)+fib(3).
The textbook has written the function in a recursive manner as described above. Note that this is not the most efficient way to implement a fibonacci function but it does logically make sense.
To understand it, it pays to trace through its execution with an example input. Take fib(3) for example. The first if statement doesn't trigger because num is not 0 or 1. Thus, it works out what fib(2) and fib(1) are, and adds them together. We know what fib(1) does - it returns 1 in the first if statement. Trace through fib(2) in a similar manner and you'll see that it returns 1. Thus, fib(3) will return fib(2)+fib(1)=2. You can extend this further - take fib(4). It will return fib(3)+fib(2), which we know are 2 and 1, hence fib(4) = 3.
This approach can be taken for most recursive functions - think of it as creating new instances of the fib() function which continually creates until it "bottoms out" at an end case (num == 1 or num == 0, in this case), and returns back up, filling in the answers until you get back to the function you started with, with the answer.
The output of the below program is 24. But I could not understand the behaviour of the function f1(parameters).
There is a recursive call of f1 in m1 nad m2. Considering m1 and m2 holding the function f1's stack. m1 stack will contain:
1]0,12,a 2]0,6,a 3]0,3,a 4]0,1,a 5]0,0,a
And m2 stack will contain:
1]13,12,a 2]20,6,a 3]24,3,a 4]26,1,a 5]27,0,a
What m1 and m2 values hold? please explain this behaviour of the recursive function.
#include <stdio.h>
main()
{
int i, n, m, b, x[25];
int f1(int, int, int j[25]);
for(i=0;i<25;i++) x[i] = i;
i=0; m = 24;
b=f1(i, m, x);
printf("res %d\n",b);
}
int f1( int p, int q, int a[25])
{
int m1,m2;
if (q==0)
return(a[p]);
else
{
m1 = f1 (p, q/2, a);
m2 = f1(p+q/2+1,q/2,a);
if(m1<m2)
return (m2);
else
return(m1);
}
}
Well, there are two points to understanding the code:
Uncovering the actual algorithm among the heaps of terrible C and
understanding the recursive function itself.
What always helped me when trying to understand such code was to:
Clean up the C code. In this case it means:
Mentally tracing the initialization and rewriting to static initialization, so you see what the values look like:
int x[25] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 };
Getting rid of the useless assignment to i and x so you have the initial call in plain sight.
Rewrite the function to mathematical notation, pseudocode or even human laguage.
f(p, q, array) = larger of f(p, q/2, array) and f(p+q/2+1, q/2, array)
if you continue a little bit further in using human language, you'll clearly see what is was supposed to do.
Now I said "was supposed to do" on purpose. The (p, q/2) and (p+q/2+1, q/2) look like the first and second half... except they are not.
The code is supposed to return 24, but it's totally wrong and the stacks quoted in the question actually prove it. The m2 stack contains as last point "f1(27, 0, a)" and that invocation is going to do a[27], but the array only has 25 elements! (by pure chance the memory above was probably 0-initialized, so it did return the 24, but if it was initialized by some debug pattern instead (I've seen 0xdeadbeef, 0xa5a5a5a5 and 0xcccccccc), it would return that).
In C it's by design (and C++ uses them everywhere) easiest to use half-open intervals. [start, one-past-end) or start+length, which convert to each other nicely. However here the function gets (start, length-1) and treats it inconsistently inside.
As a student, you have to be able to understand such code, because you'll meet lots of crappy unreadable bug ridden code that only works by accident in the wild. But if you ever present something like this, you will rightfully fail the exam.
Here you can't think of an m1 stack and an m2 stack as non-terminating calls to f1 result in an m1 and an m2 recursive call.
To analyze what's happening try it for a small value of p and q.
f1( 0, 1, a)
m1 = f1( 0, 0, a); /* q/2 == 1/2 == 0 */
/* q now 0 so return a[0] */
m2 = f1( 1, 0, a);
/* q now 0 so return a[1] */
overall result the larger of a[0] and a[1].
Now try it for f1( 0, 2, a) and so on, till you see what's happening.