I recently wrote my Grad school Admission test few days back and the following question appeared in the test.
When the below function is invoked with any positive integer as argument, does it terminate? Also does it print anything?
void convert (int n)
{
if (n < 0)
printf ("%d", n);
else
{
convert (n/2);
printf ("%d", n%2);
}
}
According to me, nothing will be printed as the control never reaches inside the if statement and also since the printf statement is placed after the function call under else block. The value of n never reaches below 0 and the function calls itself again and again till the stack overflows. My question is whether the code will abnormally terminate because of stack overflow?
The code will not terminate with a positive integer argument since the base condition n < 0 will never be met.
The recursive call to convert calls it with the argument n / 2, which, as integer division, will inevitably reach zero, but never less than it.
For example, with the argument 10:
call convert(10)
10 < 0 is false; enter the else branch
call convert(10 / 2)
5 < 0 is false; enter the else branch
call convert(5 / 2)
2 < 0 is false; enter the else branch
call convert(2 / 2)
1 < 0 is false; enter the else branch
call convert(1 / 2)
0 < 0 is false; enter the else branch
call convert(0 / 2)
0 < 0 is false; enter the else branch
call convert(0 / 2)
0 < 0 is false; enter the else branch
call convert(0 / 2)
0 < 0 is false; enter the else branch
It will never enter the base case.
Yes, unless your compiler's optimizer does something unusual, this program will abnormally terminate because of stack overflow.
The reason is that the convert() function is recursively called infinitely many times. You knew that already, but the point is this: each recursive entry to convert() pushes a new frame onto the stack. Each frame includes a return address to the previous frame and a local value of n.
Compilers have optimizers but it would take an unusual optimizer to intuit that this function (a) has no side effects and (b) returns no value. It is unlikely therefore that the optimizer would save this code from abnormal termination.
I believe that you have answered this question right.
Meanwhile, a commenter has reminded us of a special case, tail recursion. If the recursive call had ended the function, as return convert(n/2); for example, then the compiler could have reused a single stack frame for all recursive invocations. Reason: by the time the recursive call occurs, the current invocation no longer requires its storage; the object n could safely be overwritten by the new n for the recursive call; only the return address to the original caller would need to be retained. If tail recursion applied, the stack would not grow and, therefore, the program would not terminate, neither abnormally nor otherwise. However, tail recursion does not apply here.
The code will terminate with a stackoverflow or not depending on the compiler output.
There will be no output. because n will never be smaller than 0.
With a naive compiler that does compile the recursion without optimisation, you will get a stackoverflow on most (if not all) implementations.
Related
#include <stdio.h>
void fun(int a) {
if (a > 0) {
fun(a / 10);
printf("%d", a % 10);
fun(a / 10);
}
}
int main() {
fun(12345);
return 0;
}
Here, as the function is calling itself at the start of the if block, shouldn't it print nothing, it will keep calling itself until the function argument becomes zero?
But instead, the output is 1213121412131215121312141213121
shouldn't it print nothing, it will keep calling itself until the
function argument becomes zero?
If I have understood correctly then you are right. The function will not output anything until a is equal to 0.
void fun(int a){
if(a > 0){
fun(a/10); // calls itself.
printf("%d",a % 10);
//...
Thus for this number 12345 the first output will be the most significant digit 1.
As the function calls itself twice
void fun(int a){
if(a > 0){
fun(a/10);
printf("%d",a % 10);
fun(a/10);
}
}
then for each digit of the number except the most significant digit the previous and next digits will be outputted twice on the left and on the right sides. For example
1 2 1
1 2 1 3 1 2 1
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
and so on.
I used embedded spaces for make the output more clear.
After the inner most function of the recursion has been finished (a>0) is evaluating to false it will execute the print statement and returns to the calling function.
The caller will print it's a%10 value and so on.
Not sure why you call fun(a/10) twice but this is why the output is printed twice.
Yuo do not need the second call
void fun(int a)
{
if(a)
{
fun(a/10);
printf("%d", a % 10);
}
}
https://godbolt.org/z/zWf64jjWe
Remember that it will not work for negative numbers.
The function attempts to print the decimal conversion of a but the second recursive call produces extra output.
The function will indeed produce no output for values below 10, which might not be the expected behavior. Without the second recursive call the output would be 1234.
You should use this instead:
void fun(int a) {
if (a >= 10)
fun(a / 10);
printf("%d", a % 10);
}
Note however that the above function only works for positive values.
You can implement this is 3 different ways:
Either make the recursive call before you start printing. If so the printing starts from the deepest level of recursion. This is very inefficient but ensures that you get the expected order 1,2,3... Generally, a recursive function that doesn't have the recursive call at the very end is an incorrect solution to any problem.
Or make the recursive calls after you print. This would lead to everything getting printed backwards as you've currently written the function. However, a recursive function with the call at the end, so-called "tail call", can sometimes get optimized into nearly as efficient code as a loop. You could probably do this here too, if you come up with a different algorithm.
Or you can implement it as a loop. Super-fast, super-readable, no risk of excessive stacking, no overhead. This is the correct solution in some 99% of all cases and the correct solution in 100% of all cases a beginner might be facing.
I am running this below 'C' program which has an infinite loop. I see the CPU reaching almost 99% using the 'top' command. Then suddenly the program stops. I was curious to know what rule in the system is causing it to stop.
I am running this under a docker image alpine:3.1 (+ some modules) and I just simply start its ash (alpine's bash).
Also, I can not find ulimit.
#include <stdio.h>
int main() {
int marks[10],i,n,sum=0;
printf("Enter number of students: ");
scanf("%d",&n);
for(i = 0; i < n; --i) {
//printf("Enter marks of student%d: ",i+1);
int c;
c = 5;
int a;
a = c;
}
return 0;
}
As you mention, you could expect this to produce an infinite loop, at least if n is positive.
The behaviour you're seeing instead is caused by your counter wrapping around: when it reaches INT_MIN, the result of --i is INT_MAX (at least, with GCC's default settings on Intel-style CPUs — this is not defined in C, see below) and i<n fails.
So your program uses 100% of one CPU while it counts down from 0 to INT_MIN, then wraps around to INT_MAX and stops.
You can add
printf("%d\n", i);
just before the return line to see the value of i when the loop exits.
Note that this is undefined behaviour in C... If you compile this with -O2, at least with GCC 5.3, the program never exits the loop, because the optimiser decides that the exit condition will never be reached, and compiles the loop as a tight infinite loop if n is positive (.L4: jmp .L4).
Your loop is not infinite per se. YOu have a termnation condition which can be reached - in principle. The CPU load occurs, just because the loop runs for (likely) >2000000000 iterations before it ends.
First of all, you don't check the result of scanf. If it failed, n is unspecified.
Worse, your code invokes undefined behaviour (UB) due to signed integer over-/underflow. You decrement i past the minimum representable int value INT_MIN. Note that C does not have arbitrary length integers like Python.
Undefined behaviour means anything can happen, all bets are off. In your case, it might wrap to the max. positive int INT_MAX, thus the comparison fails and the loop is exited. But this is nothing you can rely on!
From the text and rest of the code, you likely don't want to decrement i, but increment: i++, so it counts from 0 to n - 1. Note that you also should check n for a valid range and ask the use to enter a valid value again. For the example, a negative upper limit is useless (but it does also no harm).
i have written a small function which calculates factorial for a number in C
as follows:
int factNnumbers(int n)
{
if(n == 1)
return 1;
else
return (n*factNnumbers(--n));
}
I call the function shown above as:
factNnumbers(takeInputN());
where the function to take the input (takeInputN) is defined as:
int takeInputN()
{
int n;
printf("\n\nHow many numbers ?? \n ");
scanf("%d", &n);
return n;
}
If I change one line in my factorial code as shown below , my program works perfectly. Otherwise with the above code it prints the factorial of the number input -1 (example if number input is 5, it will print the factorial of 4). Why is this happening?.
int factNnumbers(int n)
{
if(n != 1)
return (n * factNnumbers(--n));
}
The problem is that you're both reading and modifying n in the same expression:
n * factNumbers(--n)
The evaluation of the n argument to * and of the --n subexpression are unsequenced, which gives your code Undefined Behaviour.
The easiest solution (and also, IMO, more expressive), is to say n - 1 where you mean it:
n * factNumbers(n - 1)
Your "improved" code in the bottom of the question is actually even more wrong. There, you have a control path which will return an unspecified value: a clear no-no.
Note: This answer was written while the question still had a C++ tag, and uses C++ terminology. The end effect in C is the same, but the terminology might be different.
You are invoking undefined behaviour, that it works in one version is just an accident:
return (n*factNnumbers(--n));
Do you use n first and then decrement it or the other way around? I don't know and neither does the compiler, it's free to do either of them or format your hard drive. Just use n * f(n - 1).
Also, your "working" version does not return for the n==1 case, which is illegal.
There are two causes of undefined behavior in your code:
Whether n or --n in n * factNnumbers(--n) will be evaluated first is unspecified.See this. You want just n * factNnumbers(n - 1), why decrement? You're not using decremented n afterwards (at least you didn't want to).
You're not returning a value on all control paths, what's going to be returned on n == 1? An indeterminate value that will mess up the whole result.
the rule of decrement:
X = Y-- first passes the value of I to X and decrements after
X = --I first pass and decrements the value decremented X
for your case, you decrement the value of parameter passed as argument to the function factNnumbers. Therefore remedy this error, I invite you to put (n-1) instead of (--n).
I think it’s better to use the tgamma function from math.h for double precision calculations involving factorials (such as Poisson distribution etc.): tgamma(n+1) will give you factorial(n).
Factorial function is increasing very fast, and this will work also for values too big to fit an integer type.
When n<=1 (or == 1 in your code), the factorial function has to return 1. Futhermore the your --n in you code is false and sould be n-1 as:
function factorial(n)
{
if (n<=1)
return 1;
else
return n * factorial(n-1);
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is really happening in this code?
I have a code which includes a recursive function. I have wasted a lot of time on recursion, but i still couldn't get it, really:
#include<stdio.h>
count(int);
main(){
int x=10,z;
z=count(x);
}
count(int m){
if(m>0)
return count(m-1);
}
When count is called for the first time with argument 10, it fulfils the condition and the recursion starts. What happens really when a function calls itself? I dont get it. What does the statement return count(m-1) mean? Where does it tranfer the control?
The return value of the function count is undefined, because there is no default return if (m <= 0) is true.
C11, § 6.9.1 Function definitions
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behavior is undefined.
Besides, to understand how a recursive function works, you have to take a paper and try to execute the code by yourself (see also here).
You need count to return something when m <= 0. You should declare the return type of count and compile with -Wall so the compiler will help you find mistakes in your code.
recursion means that the function will call itself, mostly at the end of itself, if it's tail recursion.
So your count function checks that the input argument is > 0 and then if it is, it will call count(m-1). Now it starts at the top of count with m=9. It does the same thing, and then calls count with m=8, etc.
Until the end condition is reached, which should normally be explicitly catered for in your function, such as if (m == 0) return m; or some such thing. At that point the recursion ends and the function terminates.
Also, count should have a return type, such as int count (int m)
what does the statement return count(m-1) mean ? where does it tranfer the control?
That seems to be your only question.
it means that it is calling "count" with the value m-1. So if m was 10, then it is calling "count" with 9.
It is transferring the control recursively to the count method.
You also don't have a return for the every possible path in the "count" method.
What happens if m is <= 0?
When I use a debugger I can tell the exit is not exiting the function. Am I using the exit function wrong? (i must be) how do I fix this?
int is_prime(int x,char array[]){
int divider = (x-1);
float test;
while(x>-1){
test = isdigit((x % divider)); //isdigit returns !0 if digit
if(divider == '1'){
return(1); //if divider reaches 1 then the number is prime
exit;
}
if(test == '0'){
return (0);//not prime
exit;
}
divider--;
}
}
The name of a function by itself (with no parenthesis after it) just gives you the address of a function without calling it. In C the most basic statement is an expression which is evaluated for its side effects, with the resulting value of the expression ignored. So a statement like exit; or 3; which has no side effects is legal but doesn't actually do anything and might as well be deleted. Some compilers will give you warnings about such meaningless statements, though you may have to turn on extra diagnostic warnings to get them. Using such options (such as -Wall for gcc) is a very good idea and will help you avoid some pitfalls like this.
You must call it:
exit(0);
Also, if you put it after return, it will never be called, since return returns from the function.
EDIT: And, as others have said, exit exits the program, so you probably don't want to use exit here.
Besides the bugs of returnand exit you have a bug also in the way you use ints and characters. isdigit is a function that is only applied to characters, giving true if a character is between '0' and '9', but one should know that the character notation in C is only a fancy way of writing a codepoint (ASCII most of the time). So when you write '1' in a C program, the compiler will see 49, if you write 'a' the compiler sees in reality 97. This means that isdigit return true for the values 48 to 57, probably not what you intended. In the line where you compare divider with '1', in reality you're comparing it with 49 (except on IBM mainframe, where '1' is 241)
Your loop is infinite, it depends on the value of x, but x isn't changed in the loop, so the condition in the while can never change.
EDIT: Here the corrected code
int is_prime(uint_t x)
{
uint_t divider;
if(x <= 3)
return 1;
for(divider = x-1; ; divider--) {
if(x % divider == 0)
return 0; //not prime
if(divider == 1)
return 1; //if divider reaches 1 then the number is prime
}
}
Read exit(3)'s manual.
The statement:
exit;
gives the following warning with GCC:
C:\temp\test.c:71: warning: statement with no effect
What happening is that you have an expression that evaluates to the address of the exit() function - but that expression doesn't actually do anything with that address. it's similar to if you had a statement like:
1 + 2;
It's valid C, but it has no effect on anything.
To call the function, as Thomas Padron-McCarth said, you have to have the argument list (even if they're empty for some functions):
exit(0);
exit exits the process, not the function. You want return.