How does recursion work in C? - c

I'm trying to understand how recursion works in C. Can anyone give me an explanation of the control flow?
#include <stdio.h>
/* printd: print n in decimal */
void printd(int n)
{
if (n < 0)
{
putchar('-');
n = -n;
}
if (n / 10) printd(n / 10);
putchar(n % 10 + '0');
}
int main()
{
printd(123);
return 0;
}

The control flow looks like this (where -> is a function call)
main()
└─> printd(123)
├─> printd(12)
│ ├─> printd(1)
│ │ └─> putchar('1')
│ └─> putchar('2')
└─> putchar('3')

Call printd(123)
(123 / 10) != 0, so Call printd(12)
(12 / 10) != 0, so Call printd(1)
(1 / 10) == 0, so Call putchar "1"
Call putchar "2"
Call putchar "3"
return 0 (from main())

To understand recursion, you need to understand the storage model. Though there are several variations, basically "automatic" storage, the storage used to contain automatic variables, parameters, compiler temps, and call/return information, is arranged as a "stack". This is a storage structure starting at some location in process storage and "growing" either "up" (increasing addresses) or "down" (decreasing addresses) as procedures are called.
One might start out with a couple of variables:
00 -- Variable A -- 27
01 -- Variable B -- 45
Then we decide to call procedure X, so we generate a parameter of A+B:
02 -- Parameter -- 72
We need to save the location where we want control to return. Say instruction 104 is the call, so we'll make 105 the return address:
03 -- Return address -- 105
We also need to save the size of the above "stack frame" -- four words, 5 with the frame size itself:
04 -- Frame size -- 5
Now we begin executing in X. It needs a variable C:
05 -- Variable C -- 123
And it needs to reference the parameter. But how does it do that? Well, on entry a stack pointer was set to point at the "bottom" of X's "stack frame". We could make the "bottom" be any of several places, but let's make it the first variable in X's frame.
05 -- Variable C -- 123 <=== (Stack frame pointer = 5)
But we still need to reference the parameter. We know that "below" our frame (where the stack frame pointer is pointing) are (in decreasing address order) the frame size, return address, and then our parameter. So if we subtract 3 (for those 3 values) from 5 we get 2, which is the location of the parameter.
Note that at this point we don't really care if our frame pointer is 5 or 55555 -- we just subtract to reference parameters, add to reference our local variables. If we want to make a call we "stack" parameters, return address, and frame size, as we did with the first call. We could make call after call after call and just continue "pushing" stack frames.
To return we, load the frame size and the return address into registers. Subtract frame size from the stack frame pointer and put the return address into the instruction counter and we're back in the calling procedure.
Now this is an over-simplification, and there are numerous different ways to handle the stack frame pointer, parameter passing, and keeping track of frame size. But the basics apply regardless.

You have recursion in C (or any other programming language) by breaking a problem into 2 smaller problems.
Your example: print a number can be broken in these 2 parts
print the first part if it exists
print the last digit
To print "123", the simpler problems are then to print "12" (12 is 123 / 10) and to print "3".
To print "12", the simpler problems are then to print "1" (1 is 12 / 10) and to print "2".
To print "1", ... just print "1".

#include <stdio.h>
#define putd(d) (printf("%d", d))
#define RECURSIVE
void rprint(int n)
{
#ifndef RECURSIVE
int i = n < 0 ? -n : n;
for (; i / 10; i /= 10)
putd(i % 10);
putd(i % 10);
if (n < 0)
putchar('-');
/* Don't forget to reverse :D */
#else
if (n < 0) {
n = -n;
putchar('-');
}
int i = n / 10;
if (i)
rprint(i);
putd(n % 10);
#endif
}
int main()
{
rprint(-321);
return 0;
}

Recursion works on stack i.e, first in last out.
Recursion is a process of calling itself with different parameters until a base condition is achieved. Stack overflow occurs when too many recursive calls are performed.

Code:
main()
{print f ("stat");
main();
print f ("end") ;
}
Code:
main()
{int n, res;
pf("enter n value");
sf("%d",&n);
=fact(n);
}
int fact(int n)
{int res;
if(n==0)
{
res=1;
}
else
{
res = n*fact (n-1);
}
return res;
}

Related

sum of N natural Number Using Recursion in c

#include<conio.h>
#include<math.h>
int sum(int n);
int main()
{
printf("sum is %d", sum(5));
return 0;
}
//recursive function
int sum(int n)
{
if(n==1)
{
return 1;
}
int sumNm1=sum(n-1); //sum of 1 to n
int sumN=sumNm1+n;
}
Here i didn't understand how this code works when n==1 becomes true,
How this code backtracks itself afterwards..?
The code needs a return statement in the case where n is not 1:
int sum(int n)
{
if(n==1)
{
return 1;
}
int sumNm1=sum(n-1); //sum of 1 to n
int sumN=sumNm1+n;
return sumN;
}
or more simply:
int sum(int n)
{
if(n==1)
{
return 1;
}
return n + sum(n-1);
}
How this code backtracks itself afterwards..?
When a function is called, the program saves information about hwo to get back to the calling context. When return statement is executed, the program uses the saved information to return to the calling context.
This is usually implemented via a hardware stack, a region of memory set aside for this purpose. There is a stack pointer that points to the active portion of the stack memory. When main calls sum(5), a return address into main is pushed onto the stack, and the stack pointer is adjusted to point to memory that is then used for the local variables in sum. When sum calls sum(n-1), which is sum(4), a return address into sum is pushed onto the stack, and the stack pointer is adjusted again. This continues for sum(3), sum(2), and sum(1). For sum(1), the function returns 1, and the saved return address is used to go back to the previous execution of sum, for sum(2), and the stack pointer is adjusted in the reverse direction. Then the returned value 1 is added to its n, and 3 is returned. The saved address is used to go back to the previous execution, and the stack pointer is again adjusted in the reverse direction. This continues until the original sum(5) is executing again. It returns 15 and uses the saved address to go back to main.
How this code backtracks itself afterwards..?
It doesn't certainly work.
Any success is due to undefined behavior (UB).
The biggest mistake is not compiling with a well enabled compiler.
int sum(int n)
{
if(n==1)
{
return 1;
}
int sumNm1=sum(n-1); //sum of 1 to n
int sumN=sumNm1+n; // !! What, no warning?
} // !! What, no warning?
A well enabled compiler generates warnings something like the below.
warning: unused variable 'sumN' [-Wunused-variable]
warning: control reaches end of non-void function [-Wreturn-type]
Save time and enable all compiler warnings. You get faster feedback to code troubles than posting on SO.
int sumN=sumNm1+n;
return sumN; // Add
}
Like pointed in comments, the problem is that you don't return the value you compute from within the function (Undefined Behavior). You calculate it correctly (but in a clumsy way, using 2 unneeded variables). If you add a return sumN; statement at the end of the function, things should be fine.
Also, the type chosen for the return value is not the best one. You should choose:
An unsigned type (as we are talking about natural numbers), otherwise half of its interval would be simply wasted (on negative values which won't be used)
One that's as large as possible (uint64_t). Note that this only allows larger values to be computed, but does not eliminate the possibility of an overflow, so you should also be careful when choosing the input type (uint32_t)
More details on recursion: [Wikipedia]: Recursion (it also contains an example very close to yours: factorial).
Example:
main00.c:
#include <stdint.h>
#include <stdio.h>
#if defined(_WIN32)
# define PC064U_FMT "%llu"
# define PC064UX_FMT "0x%016llX"
#else
# define PC064U_FMT "%lu"
# define PC064UX_FMT "0x%016lX"
#endif
uint64_t sum(uint32_t n) // Just 3 lines of code
{
if (n < 2)
return n;
return n + sum(n - 1);
}
uint64_t sum_gauss(uint32_t n)
{
if (n == (uint32_t)-1)
return (uint64_t)(n - 1) / 2 * n + n;
return n % 2 ? (uint64_t)(n + 1) / 2 * n : (uint64_t)n / 2 * (n + 1);
}
uint64_t sum_acc(uint32_t n, uint64_t acc)
{
if (n == 0)
return acc;
return sum_acc(n - 1, acc + n);
}
int main()
{
uint32_t numbers[] = { 0, 1, 2, 3, 5, 10, 254, 255, 1000, 100000, (uint32_t)-2, (uint32_t)-1 };
for (size_t i = 0; i < sizeof(numbers) / sizeof(numbers[0]); ++i) {
uint64_t res = sum_gauss(numbers[i]);
printf("\nsum_gauss(%u): "PC064U_FMT" ("PC064UX_FMT")\n", numbers[i], res, res);
res = sum_acc(numbers[i], 0);
printf(" sum_acc(%u): "PC064U_FMT" ("PC064UX_FMT")\n", numbers[i], res, res);
res = sum(numbers[i]);
printf(" sum(%u): "PC064U_FMT" ("PC064UX_FMT")\n", numbers[i], res, res);
}
printf("\nDone.\n\n");
return 0;
}
Notes:
I added Gauss's formula (sum_gauss) to calculate the same thing using just simple arithmetic operations (and thus is waaay faster)
Another thing about recursion: although it's a nice technique (very useful for learning), it's not so practical (because each function call eats up stack), and if function calls itself many times, the stack will eventually run out (StackOverflow). A recurrent call can be worked around that using an optimization - with the help of an accumulator (check [Wikipedia]: Tail call or [SO]: What is tail call optimization?). I added sum_acc to illustrate this
Didn't consider necessary to also add the iterative variant (as it would only be a simple for loop)
Output:
(qaic-env) [cfati#cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q074798666]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[064bit prompt]> ls
main00.c vs2022
[064bit prompt]> gcc -O2 -o exe main00.c
[064bit prompt]> ./exe
sum_gauss(0): 0 (0x0000000000000000)
sum_acc(0): 0 (0x0000000000000000)
sum(0): 0 (0x0000000000000000)
sum_gauss(1): 1 (0x0000000000000001)
sum_acc(1): 1 (0x0000000000000001)
sum(1): 1 (0x0000000000000001)
sum_gauss(2): 3 (0x0000000000000003)
sum_acc(2): 3 (0x0000000000000003)
sum(2): 3 (0x0000000000000003)
sum_gauss(3): 6 (0x0000000000000006)
sum_acc(3): 6 (0x0000000000000006)
sum(3): 6 (0x0000000000000006)
sum_gauss(5): 15 (0x000000000000000F)
sum_acc(5): 15 (0x000000000000000F)
sum(5): 15 (0x000000000000000F)
sum_gauss(10): 55 (0x0000000000000037)
sum_acc(10): 55 (0x0000000000000037)
sum(10): 55 (0x0000000000000037)
sum_gauss(254): 32385 (0x0000000000007E81)
sum_acc(254): 32385 (0x0000000000007E81)
sum(254): 32385 (0x0000000000007E81)
sum_gauss(255): 32640 (0x0000000000007F80)
sum_acc(255): 32640 (0x0000000000007F80)
sum(255): 32640 (0x0000000000007F80)
sum_gauss(1000): 500500 (0x000000000007A314)
sum_acc(1000): 500500 (0x000000000007A314)
sum(1000): 500500 (0x000000000007A314)
sum_gauss(100000): 5000050000 (0x000000012A06B550)
sum_acc(100000): 5000050000 (0x000000012A06B550)
sum(100000): 5000050000 (0x000000012A06B550)
sum_gauss(4294967294): 9223372030412324865 (0x7FFFFFFE80000001)
sum_acc(4294967294): 9223372030412324865 (0x7FFFFFFE80000001)
sum(4294967294): 9223372030412324865 (0x7FFFFFFE80000001)
sum_gauss(4294967295): 9223372034707292160 (0x7FFFFFFF80000000)
sum_acc(4294967295): 9223372034707292160 (0x7FFFFFFF80000000)
sum(4294967295): 9223372034707292160 (0x7FFFFFFF80000000)
Done.
As seen in the image above, the simple implementation (sum) failed while the other 2 passed (for a certain (big) input value). Not sure though why it didn't also fail on Linux (WSL), most likely one of the optimizations (from -O2) enabled tail-end-recursion (or increased the stack?).
If I understand your question correctly, you're more interested in how recursion actually works, than in the error produced by the missing return statement (see any of the other answers).
So here's my personal guide to understanding recurive functions.
If you know about Mathematical Induction, this might help understand how recursion works (a least it did for me). You prove a base case(, make an assumption about a fixed value) and prove the statement for a following number. In programming we do a very similar thing.
Firstly, identify your base cases, i.e. some input to the function that you know what the output is. In your example this is
if(n==1)
{
return 1;
}
Now, we need to find a way to compute the value for any given input from "smaller" inputs; in this case sum(n) = sum(n-1) +n.
How does backtracking work after the base case has been reached?
To understand this, picture the function call sum(2).
We first find that 2 does not match our base case, so we recursively call the function with sum(2-1). You can imagine this recursive call as the function called with sum(2) halting until sum(1) has returned a result. Now sum(1) is the "active" function, and we find that it matches our base case, so we return 1. This is now returned to where sum(2) has waited for the result, and this function now can compute 2 + sum(1), because we got the result from the recursive call.
This goes on like this for every recursive call, that is made.
Interested in a bit more low-level explanation?
In assembly (MIPS), your code would look something like this:
sum:
addi $t1, $0, 1 # store '1' in $t0
beq $a0, $t0, base # IF n == 1: GOTO base
# ELSE:
# prepare for recursive call:
sw $a0, 4($sp) # write n on top of the stack
sw %ra, 8($sp) # write the line of the caller on top of stack
addi $sp, $sp, 8 # advance stack pointer
addi $a0, $a0, -1 # n = n-1
jal sum # call sum with reduced n
# this is executed AFTER the recursive call
addi $sp, $sp, -8 # reset stack pointer
lw %ra, 8($sp) # load where to exit the function
lw %a0, 4($sp) # load the original n this instance of sum got
add %v0, %a0, %v0 # add our n to the result of sum(n-1)
jr %ra # return to wherever sum() was called
base: # this is only executed when base case is reached
add %v0, %0, %t1 # write '1' as return statement of base case
jr %ra # reutrn to caller
Anytime the recursive function is called, we temporarily store the argument the current function got ($a0) and the calling function ($ra) on the stack. That's basically a LIFO storage, and we can access the top of it using the stack pointer $sp. So when we enter recursion, we want to make room on the stack for whatever we need to store there by advancing the stack pointer(addi $sp, $sp, 8); we can now store whatever we need there.
When this is done, we manipulate the argument we got (function arguments are always stored in $a0 in MIPS so we need to overwrite the argument we got). We write n-1 as argument for our recursive call and proceed to 'jump and lin' (jal) to the beginning of the function. This jumps to the provided label (start of our function) and saves the current line of code in $ra so we can return here after the function call. For every recursive call we make, the stack grows, because we store our data there, so we need to remember to reset it lateron.
Once a function call gets the argument 1, the programm jumps to base, we can simply write 1 into the designated return register ($v0), and jump back to the line of code we were called from.
This is the line where we used jal to jump back to the beginning. Since the called function provided the result of the base case in $v0,we can simply add our argument to $v0and return. However we first need to recover the argument and the return address from the stack. We also decrement the stack pointer, so that it is in the exact position where it was when the function was called. Therefore all recursive calls work together to compute the overall result; every idividual call has it's own storage on the stack, but it also ensures to tidy up before exiting, so that all the other calls can access their respective data.
The takeaway is: When calling a function recursively, execution jumps back to the beginning of the function with altered arguments. However, every individual function call handles their own set of variables (temporarily store on the stack). After a recursive call returns a value, the next most-inner recursive call becomes active, re-loads all their variables and computes the next result.
If this program were implemented correctly, it would work like this: When n is 1, the function returns 1. When n is 2, the function calls itself for n is 1, so it gets 1, and then adds n (i.e., 2) to it. When n is 3, the function calls itself for n is 2, so it gets 3, and then adds n (i.e., 3) to it. And so on.

Question regarding tail call optimization

As far as I know, there is a prerequisite for performing tail call optimization is that the recursion point should be the last sentence in the function, and the result of the recursive call should be returned immediately. But why?
Here is a valid example for TCO:
int factorial(int num) {
if (num == 1 || num == 0)
return 1;
return num * factorial(num - 1);
}
So, with the rule, can the below code be optimized too? Why not?
#include <stdio.h>
int factorial(int num) {
if (num == 1 || num == 0)
return 1;
int temp = num * factorial(num - 1);
printf("%d", temp);
return temp;
}
I want to know how should I explain to others why the above rule is necessary for having a TCO. But not just simply follow.
the result of the recursive call should be returned immediately. But why?
That's because in order to optimize a tail call you need to convert the final recursive call into a simple "jump" instruction. When you do this, you are merely "replacing" function arguments and then re-starting the function.
This is only possible if you can "throw away" the current stack frame and re-use it for the same function again, possibly overwriting it. If you need to remember a value to do more calculations and then return, you cannot use the same stack frame for the recursive call (i.e. cannot turn the "call" into a "jump"), as it could possibly erase/modify the value you wanted to remember before returning.
Furthermore, if your function is very simple (like yours) chances are that it could be written without using the stack at all (except for the return address maybe), and only store data in registers. Even in this case, you don't want to make a jump to the same function (that uses the same registers) if you need to remember one of the values before returning.
Here is a valid example for TCO:
int factorial(int num) {
if (num == 1 || num == 0)
return 1;
return num * factorial(num - 1);
}
This is not valid for TCO! You are doing return num * <recursive-call>. The recursive call is not the last thing that the function does, there is a multiplication before returning. It's the same as writing:
int factorial(int num) {
if (num == 1 || num == 0)
return 1;
int tmp = factorial(num - 1);
tmp *= num;
return tmp;
}
can the below code be optimized too?
Nope! Again there simply is no tail call there, and it's even more obvious. You are first doing the recursive call, then some other stuff (multiplication and printf), and then returning. This cannot be optimized as a tail call by the compiler.
On the other hand, the following code can be optimized as a tail call:
int factorial(int n, int x) {
if (n == 1)
return x;
int tmp = factorial(n - 1, n * x);
return tmp;
}
You don't necessarily have to make the recursive call right on the last line of the function. The important thing is that you don't do work in the middle (between the recursive call and the return statement), like for example calling other functions or doing additional calculations.
IMPORTANT: note that just the fact that a classical TCO cannot be performed does not mean that the compiler will not be able to optimize your code in some other way. In fact, your first function is so simple that when compiled with GCC on x86-64 with at least -O2 it just gets converted from recursive to iterative (it basically becomes a single loop). The same goes for my example above, the compiler just doesn't care to do TCO, it sees an even better optimization to make in this case.
Here's the assembler dump of your first function generated by GCC 11 on x86-64 (Godbolt link if you want to play with it). In case you are not familiar with x86: the num argument is in edi, and eax is used for the return value.
factorial:
mov eax, 1
cmp edi, 1
jbe .L1
.L2:
mov edx, edi
sub edi, 1
imul eax, edx
cmp edi, 1
jne .L2
.L1:
ret
Each invocation of a function creates a stack frame with any data passed into that function via arguments. If a function calls another function (including itself) a new stack frame is pushed onto the stack. When a function is completely finished, its frame is popped off the stack.
Stack memory is limited. If we try to push too many frames onto the stack, we get a stack overflow error.
Where tail call optimization comes into play is to recognize that a function is complete if there is no work left to be done after the tail call.
Consider a way of recursively summing a range of numbers.
int sum(int start, int stop) {
if (start == stop) {
return start;
}
else {
return start + sum(start + 1, stop);
}
}
If we call sum(1, 5) the recursion looks something like:
sum(1, 5)
1 + sum(2, 5)
1 + 2 + sum(3, 5)
1 + 2 + 3 + sum(4, 5)
1 + 2 + 3 + 4 + sum(5, 5)
1 + 2 + 3 + 4 + 5
Several stack frames have to be created to hold this.
Typically tail-call optimization for something that requires building up a value involves an accumulator argument passed to the function.
int sum_tco(int start, int stop, int acc) {
if (start == stop) {
return start + acc;
}
else {
return sum_tco(start + 1, stop, start + acc);
}
}
Now consider what the recursion looks like:
sum_tco(1, 5, 0)
sum_tco(2, 5, 1 + 0)
sum_tco(3, 5, 2 + 1 + 0)
sum_tco(4, 5, 3 + 2 + 0)
sum_tco(5, 5, 5 + 4 + 3 + 2 + 1 + 0)
5 + 4 + 3 + 2 + 1 + 0
We don't need to know what the result of sum(1, 5, 0) or sum(3, 5, 2 + 1 + 0) is to know what the result of sum(5, 5, 5 + 4 + 3 + 2 + 1 + 0) is, and neither does your computer.
A smart compiler realizes this and removes all of those previous stack frames as it goes. With TCO, no matter how many times this function recursively calls itself, it will never overflow the stack.
(Descriptions of how the stack behaves have been generalized and are not intended to be technically in-depth but rather to demonstrate the generalized concept of TCO.)

How to read and change value from memory in Linux?

The code inside main.c
#include <stdio.h>
#include <unistd.h>
int main() {
int c_variable = 0; // the target
for(int x = 0; x < 100; x++) {
c_variable += 5; // increase by 5 to change the value of the int
printf("%i\n", c_variable); // print current value
sleep(8); // sleep so I have time to scan memory
}
return 0;
}
What I am trying to achieve is to read the integer c_variable and then to modify it inside another .c program. I am on linux so I did ps -A | grep main and got the PID of the running program. I then did sudo scanmem PID and entered the current value of c_variable a few times. I was left with three memory addresses and executing the command set 500 changed the value the program printed, effectively changing the memory address' value to 500 instead of 35 or whatever the program was currently at. I then executed the following code
#include <stdio.h>
int main() {
const long unsigned addr = 0x772d85fa1008; // one of the three addresses from scanmem
printf("%lu\n", addr);
return 0;
}
but I got some random long string of numbers, not the current number. The tutorials and answers I have read on how to read and write memory on linux does not have to use long unsigned but can use char* or just int* instead. My memory address seems to be a bit long, I have not see memory addresses that long before. Anyhow, how do I read and write the memory address of the integer c_variable?
Edit: the output of scanmem looks something like this
info: we currently have 3 matches.
3> list
[ 0] 7771ff64b090, 6 + 1e090, stack, 20, [I64 I32 I16 I8 ]
[ 1] 7771ff64b5d8, 6 + 1e5d8, stack, 20, [I64 I32 I16 I8 ]
[ 2] 7771ff64b698, 6 + 1e698, stack, 20, [I32 I16 I8 ]
3> set 50
info: setting *0x7771ff64b090 to 0x32...
info: setting *0x7771ff64b5d8 to 0x32...
info: setting *0x7771ff64b698 to 0x32...
output
...
150
155
160
165
170
175
55
60
65
...
You're printing the actual address number, but in in decimal notation, not what is at the address.
const int *addr = (int *) 0x772d85fa1008;
printf("%d\n", *addr);
You have to declare addr as a pointer type. More specifically a pointer to an integer. Its value (0x772d85fa1008) holds the address of the integer.
Then, in the printf call you dereference it to obtain the actual integer stored at the address.
Although in practice I can't vouch for whether this is going to work, since memory in modern operating systems isn't as simple as you make it out to be. But I don't have enough knowledge to assess that.
Processes running under Linux generally have their own virtualized memory space. If you want to access memory space of another process, arrangements have been made in the Linux API, see shmctl, shmget, shmat, shmdt.

How do i find the second largest element among given collection of numbers?

Without using an array, I am trying to do this. what is wrong with my code?
n is the number of elements,a is the first element(assumed to be maximum initially), b stores new element every time and sec variable stores the second-largest element. Numbers are all positive. This is from an online contest.
#include<stdio.h>
int main() {
int i,a,b,max,n,sec;
scanf("%d",&n);
scanf("%d",&a);
max=a;
while(n-1!=0) {
scanf("%d",&b);
if(b>max) {
sec=max;
max=b;
}
else if(b<max && b>sec)
sec=b;
else{}
n--;
}
printf("%d",sec);
return 0;
}
getting wrong answers in some test cases( i don't know )
Consider sequence 2, 12, 10 (leaving out surrounding code):
int sec; // unitialised!!!
max = a; // 12
if(b > max) // b got 10, so false!
{
sec = max; // this code is not hit! (b remains uninitalised)
max = b;
}
else if(b < max && b > sec)
// ^ comparing against uninitialised
// -> UNDEFINED BEHAVIOUR
You need to initialise sec appropriately, e. g. with INT_MIN (defined in <limits.h>); this is the minimal allowed value, with 32-bit int that would be a value of -232 - 1, i. e. -2 147 483 648. Pretty unlikely anybody would enter that value, so you could use it as sentinel.
You even could initialise max with that value, then you woudn't need special handling for the first value:
int sec = INT_MIN, max = INT_MIN;
int n;
scanf("%d", &n); // you should check the return value, which is number of
// successfully scanned values, i. e. 1 in given case,
// to catch invalid user input!
// you might check value of n for being out of valid range, at very least < 0
while(n--) // you can do the decrement inside loop header already...
{
// keep scope of variables as local as possible:
int a;
// scanf and comparisons as you had already
// again don't forget to check scanf's return value
}
if(sec == INT_MAX)
{
// likely hasn't been modified -> error, no second largest element
}
else
{
// ...
}
Now what if you do expect user to give you the value of INT_MIN as input?
You could have a separate counter, initialised to 0, you increment in both of the two if branches inside the loop; if this counter is < 2 after the loop, you didn't get at least two distinct numbers...
Lets look at the input
2 4 3
Two is the number of inputs.
4 ends up in max.
3 ends up in b.
b is not greater than max, the if does not do anything.
b is less than max, but b is not necessarily greater than sec,
because sec at this point can be anything - whatever currently is inside that non-initialised variable. sec at this point is for example not guaranteed to be 0. So the else if does not trigger and we end up in else {}.
So we end up executing the printf() at the end of the program with a still uninitialised sec. And that is unlikely to satisfy the judge.
To solve the problem, you need to initialise sec. Initialising to 0 might work, but actually you need to use the lowest possible input value.
Since you chose int, instead of unsigned int, I assume that 0 is NOT the lowest possible value. But you would have to quote the assignment/challenge to allow determining the lowest possible value. So you need to find that out yourself in order to make a solution code.
Alernatively, you can analyse the first input values to initialise max and sec (need to watch them coming in until you get two distinct values; credits to Aconcagua).
Usually it is however easier to determine the lowest possible value from requirements or the lowest possible int value from your environment.
At some level of nitpicking, you need to know the lowest possible value anyway, in order to select the correct data type for your implementation. I.e. even with analysing the first two values, you might fail for selecting the most narrow data type.
In case you "successfully" (as judged by the challenge) use 0 to initialise sec, try the input 2 1 -1.
It should fail.
Then try to find in your challenge/assignment description a reason why using 0 is allowed. It should be there, otherwise find a different challenge site to improve your coding skills.
I liked how OP initialized max with the first input value.
This brought me to the idea that the same can be done for sec.
(The value of max is a nice indicator that sec could not be determined whatever max contains. In regular case, max and sec can never be equal.)
Hence, one possibility is to initialize max and sec with the first input
and use max != sec as indicator whether sec has been written afterwards at all.
Demo:
#include <stdio.h>
int main()
{
/* read number of inputs */
int n;
if (scanf("%d", &n) != 1 || n < 1) {
fprintf(stderr, "ERROR!\n");
return -1;
}
/* read 1st input */
int max;
if (scanf("%d", &max) != 1) {
fprintf(stderr, "ERROR!\n");
return -1;
}
--n;
int sec = max;
/* read other input */
while (n--) {
int a;
if (scanf("%d", &a) != 1) {
fprintf(stderr, "ERROR!\n");
return -1;
}
if (max < a) { sec = max; max = a; }
else if (sec == max || (sec < a && a < max)) sec = a;
}
/* evaluate result */
if (sec == max) {
puts("No second largest value occurred!\n");
} else printf("%d\n", sec);
/* done */
return 0;
}
Output:
$ gcc -std=c11 -O2 -Wall -pedantic main.c
$ echo -e "3 3 4 5" | ./a.out
4
$ echo -e "3 3 5 4" | ./a.out
4
$ echo -e "3 4 3 5" | ./a.out
4
$ echo -e "3 4 5 3" | ./a.out
4
$ echo -e "3 5 3 4" | ./a.out
4
$ echo -e "3 5 4 3" | ./a.out
4
$ # edge case:
$ echo -e "2 3 3" | ./a.out
No second largest value occurred!
Live Demo on coliru

Count number of digits recursively

In order to learn recursion, I want to count the number of decimal digits that compose an integer. For didactic purposes, hence, I would like to not use the functions from math.h, as presented in:
Finding the length of an integer in C
How do I determine the number of digits of an integer in C? .
I tried two ways, based on the assumption that the division of an integer by 10 will, at a certain point, result in 0.
The first works correctly. count2(1514, 1) returns 4:
int count2(int n, int i){
if(n == 0)
return 0;
else
return i + count2(n / 10, i);
}
But I would like to comprehend the behavior of this one:
int count3(int n, int i){
if(n / 10 != 0)
return i + count3(n / 10, i);
}
For example, from count3(1514, 1); I expect this:
1514 / 10 = 151; # i = 1 + 1
151 / 10 = 15; # i = 2 + 1
15 / 10 = 1; # i = 3 + 1
1 / 10 = 0; # Stop!
Unexpectedly, the function returns 13 instead of 4. Should not the function recurse only 3 times? What is the actual necessity of a base case of the same kind of count2()?
If you do not provide a return statement the result is indeterminate.
On most architectures that mean your function returns random data that happens to be present on the stack or service registers.
So, your count3() function is returning random data when n / 10 == 0 because there is no corresponding return statement.
Edit: it must be stressed that most modern compilers are able to warn when a typed function does not cover all exit points with a return statement.
For example, GCC 4.9.2 will silently accept the missing return. But if you provide it the -Wreturn-type compiler switch you will get a 'warning: control reaches end of non-void function [-Wreturn-type]' warning message. Clang 3.5.0, by comparison, will by default give you a similar warning message: 'warning: control may reach end of non-void function [-Wreturn-type]'. Personally I try to work using -Wall -pedantic unless some required 3rd party forces me to disable some specific switch.
In recursion there should be base conditions which is the building block of recursive solution. Your recursion base doesn't return any value when n==0 — so the returned value is indeterminate. So your recursion count3 fails.
Not returning value in a value-returning function is Undefined behavior. You should be warned on this behavior
Your logic is also wrong. You must return 1 when `(n >= 0 && n / 10 == 0) and
if(n / 10 != 0)
return i + count3(n / 10, i);
else if (n >= 0) return 1;
else return 0;
I don't think you need that i+count() in the recursion. Just 1+count() can work fine...
#include <stdio.h>
#include <stdlib.h>
static int count(), BASE=(10);
int main ( int argc, char *argv[] ) {
int num = (argc>1?atoi(argv[1]):9999);
BASE= (argc>2?atoi(argv[2]):BASE);
printf(" #digits in %d(base%d) is %d\n", num,BASE,count(num)); }
int count ( int num ) { return ( num>0? 1+count(num/BASE) : 0 ); }
...seems to work fine for me. For example,
bash-4.3$ ./count 987654
#digits in 987654(base10) is 6
bash-4.3$ ./count 123454321
#digits in 123454321(base10) is 9
bash-4.3$ ./count 1024 2
#digits in 1024(base2) is 11
bash-4.3$ ./count 512 2
#digits in 512(base2) is 10

Resources