I am learning how to apply recursion to arrays.
For example, I usually read arrays itiratively, this way:
void read_array(int *a, int n){
int i;
for(i = 0; i < n; ++i)
scanf("%d", &a[i]);
return;
}
I would like to read an array recursively. I wrote the following function:
void read_array(int *a, int n){
int i = n - 1;
if (n < 0)
return;
else{
if(scanf("%d", &a[n - 1 - i]) == 1){
read_array(a, n - 1);
return;
}
}
}
It compiles, but when running it trows a segmentation fault error. It confuses me since the function contemplates a base case 0 that should stop it.
Your calculation of the array index is wrong. This line:
if(scanf("%d", &a[n - 1 - i]) == 1){
assumes the initial value of n, but at the same time, you decrease n with every recursion step. That being said, it shouldn't crash but just repeatedly write the first element of a, because with i = n - 1, n - 1 - i is always zero.
The idiomatic way to write such a recursion would be to recurse on i:
void read_array(int *a, int n, int i)
{
if (i < n)
{
if(scanf("%d", &a[i]) == 1)
{
read_array(a, n, i+1);
}
}
}
and call it with the initial value for i, e.g. read_array(a, 10, 0) for reading a 10-element array.
In practice, recursion in C is to be avoided.*
* Functional languages can typically optimize recursion, C just uses the call stack with a lot of overhead.
In this example, the theoretical purpose of recursion for writing a pure function is somewhat defeated with a function returning void. If this is just about learning the principle, the functions actually should return something. You could for example create a functional "list builder":
#include <stdio.h>
#include <stdlib.h>
// place the side effect in a separate function
int getValue(void)
{
// could have `scanf()` here:
return rand();
}
typedef struct List
{
int a[10];
size_t length;
} List;
// non-functional helper to get around limitations of C:
// (if it could initialize result directly with the new values, it would
// be functional)
List listAppend(List list, int val)
{
List result = list;
result.a[result.length++] = val;
return result;
}
// recursive function without side effects:
List buildList(List list, int (*value)())
{
if (list.length >= 10) return list;
return buildList(listAppend(list, value()), value);
}
int main(void)
{
List myList = buildList((List){0}, &getValue);
for (size_t i = 0; i < myList.length; ++i)
{
printf("myList.a[%zu] is %d\n", i, myList.a[i]);
}
}
There is a bug in the function.
As the variable i is initialized the following way
int i = n - 1;
then the second argument in this call
scanf("%d", &a[n - 1 - i])
is evaluated like
scanf("%d", &a[n - 1 - (n - 1)])
that is it is always equal to zero
scanf("%d", &a[0])
As the recursive function is called with the same value of the pointer a then all entered values are assigned to a[0]. All other elements of the array are still uninitialized.
Though this does not serve as a reason for the abnormal execution of the function.
It is possible that there is used a big array and the stack is too small to call the function recursively.
In any case the function can be defined more simply and correctly the following way
size_t read_array( int *a, size_t n )
{
return n && scanf( "%d", a ) == 1 ? 1 + read_array( a + 1, n - 1 ) : 0;
}
Take into account as the input can be interrupted by the user. In this case the function returns the number of initialized elements of the array.
Here is a demonstrative program.
#include <stdio.h>
size_t read_array( int *a, size_t n )
{
return n && scanf( "%d", a ) == 1 ? 1 + read_array( a + 1, n - 1 ) : 0;
}
#define N 10
int main(void)
{
int a[N];
size_t n = read_array( a, N );
for ( size_t i = 0; i < n; i++ ) printf( "%d ", a[i] );
putchar( '\n' );
return 0;
}
If to enter sequence of numbers
0 1 2 3 4 5 6 7 8 9
then the output will be
0 1 2 3 4 5 6 7 8 9
Example:
int read_array_aux(int *i, int *n) {
if (i == n) {
return 0;
}
if (scanf("%d", i) != 1) {
return -1;
}
return read_array_aux(i + 1, n);
}
int read_array_aux2(int *a, size_t i, size_t n) {
if (i == n) {
return 0;
}
if (scanf("%d", a + i) != 1) {
return -1;
}
return read_array_aux2(a, i + 1, n);
}
int read_array(int *a, size_t n) {
return read_array_aux(a, a + n);
// return read_array_aux2(a, 0, n);
}
First, condition n<0 is wrong. Probably this is the cause of segfault.
Also, why even bother about calculating the index? When processing any kind of list recursively it's worth to grasp the concept of head (first element of list) and tail (everything except head) of the list. So, filling an array recursively would be defined as (in pseudo code):
void read_array() {
read_head();
read_tail();
}
What is head? It's the first element of current array. What's the tail? The array starting from next element. So, read_tail is equivalent of read_array, but with the beginning moved forward by one element.
And, finally, to gather everything into one place:
void read_array(int *a, int n) {
if(n<=0) {
return;
} else {
if(scanf("%d", a) == 1) {
read_array(a+1,n-1);
}
}
}
As other answers have mentioned, your handling of n is leading to problems. You can return 0 from the base case of sz == 0, otherwise return the result of the next recursive call, or -1 if scanf() fails. At each recursive call, increment a and decrement sz. The value returned in the calling function should be checked for input errors: 0 on success, -1 on failure.
Note that this is a tail recursion, which should be optimized by most good compilers.
#include <stdio.h>
int read_array(int *a, size_t sz);
int main(void)
{
int arr[5];
puts("Enter array elements:");
if (read_array(arr, 5) != 0) {
fprintf(stderr, "Input error\n");
} else {
for (size_t i = 0; i < 5; i++) {
printf("%8d", arr[i]);
}
putchar('\n');
}
return 0;
}
int read_array(int *a, size_t sz)
{
if (sz == 0 ) {
return 0;
}
if (scanf("%d", a) == 1){
return read_array(a + 1, sz - 1);
} else {
return -1;
}
}
Sample interaction:
Enter array elements:
1 2 3 4 5
1 2 3 4 5
Enter array elements:
1 2 3 x 5
Input error
Related
I want to generate numbers 1 to 4 in a random fashion using C programming.
I have made provision to print a[0] directly in a while loop and for any further element the program checks whether the new number from a[1] to a[3] is same as any of the previous elements. A function has been created for the same. int checkarray(int *x, int y).
The function checks current element with previous elements one by one by reducing the passed address. If it matches the value it exits the loop by assigning value zero to the condition variable (int apply).
return apply;
In the main program it matches with the int check if check==1, the number is printed or else the loop is repeated.
Problem faced: The number of random numbers generated is varying between 2 and 4.
e.g
2 4
2 4 3
1 3 3 4
etc
Also repetition is there sometimes.
#include <stdio.h>
#include <conio.h>
int checkarray(int *x, int y);
void main() {
int a[4], i = 0, check;
srand(time(0));
while (i < 4) {
a[i] = rand() % 4 + 1;
if (i == 0) {
printf("%d ", a[i]);
i++;
continue;
} else {
check = checkarray(&a[i], i);
}
if (check == 1) {
printf("\n%d ", a[i]);
} else {
continue;
}
i++;
}
getch();
}
int checkarray(int *x, int y) {
int arrcnt = y, apply = 1, r = 1;
while (arrcnt > 0) {
if (*x == *(x - 2 * r)) {
apply = 0;
exit(0);
} else {
arrcnt--;
r++;
continue;
}
}
return apply;
}
Let's look at the checkarray function, which is supposed to check if a number is already present in the array.
It is called this way:
check = checkarray(&a[i], i);
Where a is an array of 4 integers and i is the actual index, so it tries to scan the array backwards looking for any occurrences of a[i]
int checkarray(int *x,int y)
{
int arrcnt=y,apply=1,r=1;
while(arrcnt>0)
{
if(*x==*(x-2*r))
// ^^^ Why? This will cause an out of bounds access.
{
apply = 0;
exit(0); // <-- This ends the program. It should be a 'break;'
}
else
{
arrcnt--;
r++;
continue;
}
}
return apply;
}
Without changing the interface (which is error prone, in my opinion) it could be rewritten as
int check_array(int *x, int y)
{
while ( y )
{
if ( *x == *(x - y) )
return 0;
--y;
}
return 1;
}
Testable here.
There are many other issues which should be addressed, though, so please, take a look to these Q&A too.
Does "n * (rand() / RAND_MAX)" make a skewed random number distribution?
Why do people say there is modulo bias when using a random number generator?
Fisher Yates shuffling algorithm in C
int main() vs void main() in C
Why can't I find <conio.h> on Linux?
Your approach is tedious but can be made to work:
there is no need to special case the first number, just make checkarray() return not found for an empty array.
you should pass different arguments to checkarray(): a pointer to the array, the number of entries to check and the value to search.
you should not use exit(0) to return 0 from checkarray(): it causes the program to terminate immediately.
Here is a modified version:
#include <stdio.h>
#include <conio.h>
int checkarray(int *array, int len, int value) {
int i;
for (i = 0; i < len; i++) {
if (array[i] == value)
return 0;
}
return 1;
}
int main() {
int a[4], i = 0, value;
srand(time(0));
while (i < 4) {
value = rand() % 4 + 1;
if (checkarray(a, i, value)) {
printf("%d ", value);
a[i++] = value;
}
}
printf("\n");
getch();
return 0;
}
I am trying to understand how to find the maximum number using a recursive function, but I do not really understand how. Having this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ar[100],n,i;
int *ptr;
printf("Enter size of the list:");
scanf("%d", &n);
printf("Printing the list:\n");
for (i = 0; i < n ; i++)
{
scanf("%d", &ar[i]);
}
ptr=&ar;
int max=maximum(ptr,n);
printf("ma %d",max);
return 0;
}
int maximum(int ar[], int n)
{
int max;
if(n+1==1)
{
return ar[n];
}
max =maximum(ar,n-1);
return ar[n]>max?ar[n]:max;
}
What is it actually doing and how?
Is it correctly using pointers to point the array of integers?
I hope you can help me understand it!
You set aside memory for an array of 100 integers with int ar[100], and you enter n which is set using scanf("%d", &n). If you enter a number greater than 100 at this stage, your program will seg fault because your loop for (i = 0; i < n ; i++) will try to access ar[100] which is a memory access error (the highest array index available is ar[100 - 1], notice that 100 - 1 < 100). Anyways, you fill n indices of ar in the loop. ptr = &ar just assigns the starting address of ar to ptr. By the way ptr = ar will work too, the & is not necessary. Now you can use ptr the same way you were using ar.
The easiest way to understand the recursion is to go straight to the last call of maximum. But first, understand that you passed ptr to the function which is the same as passing ar (remember, they are the same thing in main since ptr = ar.).
So in the last call to maximum, When n + 1 == 1 (same as n == 0), it returns ar[n] which is ar[0], which is first the number you entered for 'Printing the list' (it was stored in ar[0]).
Now in the second last call to maximum, n + 1 == 1 is false because n = 1 so we go to max = maximum(ar, n - 1). That's the result of the last call to maximum that I just explained, so max has the value of ar[0]. Now you have return ar[n] > max ? ar[n] : max, which is the same as return ar[1] > ar[0] ? ar[1] : ar[0]. That is the same as
if (ar[1] > ar[0]) {
return ar[1];
} else {
return ar[0];
}
And you can see that this returns whichever is bigger, ar[0] or ar[1]. Now for the third last call to maximum, max is the result of the second last call to maximum. And you can see the pattern emerge. You will return whichever is greater: max or ar[n] for all the rest of the calls to maximum, and by the time you get to the first call to maximum, you will have compared all the values in ar to find its maximum and return it.
Also, what Ajay said is right, ar[n] is accessing a value that you never initialized in your loop. You should write int max = maximum(ptr, n - 1) in main to fix that.
My solution with tail recursion:
int maximum(int a[], int n)
{
if (n == 1)
return a[0];
--n;
return maximum(a + (a[0] < a[n]), n);
}
Demo on compiler explorer
To understand how maximum works, just try and find some invariants in the maximum function
int maximum(int ar[], int n)
{
int max;
if(n==0)
{
return ar[n];
}
max =maximum(ar,n-1);
/* at this point MAX keeps the maximum of the subarray [0..N-1] and using this
we try to get by induction the maximum of [1..N]. */
return ar[n]>max?ar[n]:max;
}
Consider that definition :
#include <stdio.h>
#include <stdlib.h>
void maximum(int nums[], int size, int index, int * max)
{
if (index != size) {
if (nums[index] > *max)
*max = nums[index];
maximum(nums, size, ++index, max);
}
}
int main()
{
int * nums;
int size, i, max;
fprintf(stderr, "Enter size of the list: "); /* stderr to flush without \n */
if ((scanf("%d", &size) != 1) || (size <= 0)) {
puts("wrong size");
return 0;
}
if ((nums = malloc(size * sizeof(int))) == 0) {
puts("cannot allocate nums");
return 0;
}
for (i = 0; i != size; ++i) {
if (scanf("%d", &nums[i]) != 1) {
puts("invalid number");
return 0;
}
}
max = nums[0];
maximum(nums, size, 1, &max);
free(nums);
printf("max = %d\n", max);
return 0;
}
Execution:
% gcc -O2 -pedantic -Wall m.c
% ./a.out
Enter size of the list: 3
3
1
2
max = 3
maximum is recursive, but this is a terminal recursion, so the compiler can remove it to generate a loop. So maximum seems to be recursive as you request but the stack will not explode even with a large number :
% ( echo 100000000 ; yes 1 ) | ./a.out
Enter size of the list: max = 1
If I remove the option -O2 the generate code uses the recursion and the stack explode :
% gcc -pedantic -Wall m.c
% ( echo 100000000 ; yes 1 ) | ./a.out
Enter size of the list: Segmentation fault
int maxRecursively( arr array, int index){
int max = array.ptr[index];
if ( index == array.length-2 ){
return max= array.ptr[index]> array.ptr[index+1] ? array.ptr[index]:array.ptr[index+1];
}
return max = max > maxRecursively(array,index+1) ? max: maxRecursively(array,index+1);
}
I was wondering how to make a function consider a given parameter as a static variable. For example, i tried, without success, to generate hailstone numbers:
#include<stdio.h>
int hailstone(int);
int n; /* n is an extern variable*/
int main(){
hailstone(n);
return 0;
}
int hailstone(int n){
static int m = n; /*not possible because n is not constant*/
if(m % 2 == 0 && m != 1)
hailstone(m /= 2);
else if(m != 1)
hailstone((m *= 3) + 1);
else
exit(0); /*Is the use of exit() correct, in this case?*/
return 0;
}
I would like to use a static variable to elaborate n. Otherwise, each recursive call would operate on the whole parameter n, thus going on endless, never reaching the case base.
Few questions:
Does this idea represent a feasible approach to the problem?
Does this idea represent a reasonable/effective approach to the problem?
Is exit(0) used correctly, in a similar case?
You don't need a static variable for this. Just pass in the new value to operate on and use that. Also, the value 1 is your base case, so check for that to stop the recursion, and print the value of n so you can actually see what's going on.
void hailstone(int n){
printf("n=%d\n", n);
if(n % 2 == 0 && n > 1) {
hailstone(n/2);
} else if(n > 1) {
hailstone((n*3) + 1);
}
}
Given that this function could go on for quite a few iterations, a recursive solution could end up causing a stack overflow. Better to go with an iterative solution:
void hailstone(int n){
while (n > 1) {
printf("n=%d\n", n);
if(n % 2 == 0) {
n = n/2;
} else {
n = (n*3) + 1;
}
}
}
Here's the recursive algorithm for hailstorm, there's no need for static
#include <assert.h>
#include <stdio.h>
void hailstone(unsigned int n)
{
assert(n>0);
printf("%u\n", n);
if ( n == 1 )
return;
if( n & 1 ) {
hailstone(3*n + 1);
}
else {
hailstone(n >> 1);
}
}
int main() {
hailstone(5);
}
I'm trying to write a recursive function that gets an array by pointer and its size, and returns the length of the longest series of identical adjacent numbers in the array (assume that there is a series),
For example:
array: {1 2 3 3 4 5 6 6 6 6 7 8}
returns-->: 4
but I don't know what's wrong with my function; I think I got it all wrong.
Any ideas on how to fix it?
#include <stdio.h>
#include <stdlib.h>
int LongestSeries(int* arr, int size, int* count, int* maxcount);
int main()
{
int i, size, *arr, count=0, maxcount=0;
// allocation an array (unknow size)
{
printf("Enter Size of the Array-->:");
scanf("%d", &size);
arr = (int*)malloc(size * sizeof(int));
if (arr == NULL)
{
printf("Error!!");
exit(1);
}
printf("Enter Numbers for the Array:\n");
for (i = 0; i < size; i++)
{
printf("Enter a Number-->:");
scanf("%d", &arr[i]);
}
}
for (i = 0; i < size; i++)
printf(" %d ", arr[i]);
printf("\n");
printf(" %d \n", LongestSeries(arr, size, count, maxcount));
free(arr);
return 0;
}
int LongestSeries(int* arr, int size, int* count, int* maxcount)
{
if (arr[size-1] == arr[size-2])
count++;
if (maxcount<count)
maxcount = count;
LongestSeries(arr, size - 1, count, maxcount);
if (*arr==arr[0])
return maxcount;
}
There're some problems in your code:
1 - The function LongestSeries expects a pointer on count and maxcount arguments but you passed the variable's values instead. You need to change the function call to send the address reference, like this: printf(" %d \n", LongestSeries(arr, size, &count, &maxcount));
2 - Your recursion termination condition is placed below the recursion call, causing the recursion never ending. You need to place it above the recursion call, preferably be the first statement in your recursive function.
3 - Since your count and maxcount arguments are pointers, you must use the dereference operator to work with the values instead its addresses:
from this:
if (arr[size-1] == arr[size-2])
count++;
if (maxcount<count)
maxcount = count;
to this:
if (arr[size-1] == arr[size-2])
++*count;
if (*maxcount < *count)
*maxcount = *count;
4 - The same applies in your return statement: you're returing the pointer, but your function expects an int to be returned, so:
from this:
if (*arr==arr[0])
return maxcount;
to this:
if (*arr==arr[0])
return *maxcount;
5 - Since you need the longest series, your count variable needs to start at 1, not 0, since the lowest possible series in a number sequence is 1, and not 0.
Hope it helps.
There are many problems with the posted code, as pointed out by #MarcLaurent. But fundamentally, the approach seems flawed. The point of writing recursive functions is not to make things difficult, but to make things simple. Problems that lend themselves to recursion can be broken down into smaller subproblems.
For the problem at hand, finding the length of the longest sequence of repeated numbers in an array, one recursive approach would acknowledge that this length is either the length of the initial sequence of repeated numbers, or the length of the longest sequence of repeated numbers in the remainder of the array. In code, this might look like:
size_t longest_seq(size_t sz, int *a)
{
if (sz == 0) {
return 0;
}
size_t count = init_seq(sz, a);
return MAX(count, longest_seq(sz - count, a + count));
}
Here, if the array contains no elements (the base case), 0 is returned. Otherwise, the larger of the length of the initial sequence, or the longest sequence in the remainder of the array is returned. MAX is a macro here, easily defined, and we have only to write a function that finds the length of the initial sequence. This can also be recursive, though it need not be.
A recursive function that finds the length of the initial sequence could look like:
size_t init_seq(size_t sz, int *a)
{
if (sz == 0) {
return 0;
}
return 1 + ((sz > 1 && a[0] == a[1]) ? init_seq(sz - 1, a + 1) : 0);
}
Here, if the array contains no elements (the base case), then the length is obviously 0, otherwise the return value is 1 added to the length of the initial sequence of the remainder of the array (if there is a next element, and that element is the same as the first element), or 0.
By breaking the problem down in this way, the solution is simple and easy to understand. Here is a full program implementing the above ideas:
#include <stdio.h>
#define MAX(X, Y) (X) > (Y) ? (X) : (Y)
size_t longest_seq(size_t, int *);
size_t init_seq(size_t, int *);
int main(void)
{
size_t arr_sz;
printf("Enter number of elements: ");
scanf("%zu", &arr_sz);
int arr[arr_sz];
printf("Enter array values:\n");
for (size_t i = 0; i < arr_sz; i++) {
scanf("%d", &arr[i]);
}
printf("Longest sequence of repeats: %zu\n", longest_seq(arr_sz, arr));
return 0;
}
size_t longest_seq(size_t sz, int *a)
{
if (sz == 0) {
return 0;
}
size_t count = init_seq(sz, a);
return MAX(count, longest_seq(sz - count, a + count));
}
size_t init_seq(size_t sz, int *a)
{
if (sz == 0) {
return 0;
}
return 1 + ((sz > 1 && a[0] == a[1]) ? init_seq(sz - 1, a + 1) : 0);
}
Sample program interaction:
Enter number of elements: 12
Enter array values:
1 2 3 3 4 5 6 6 6 6 7 8
Longest sequence of repeats: 4
int LongestSeries(int* arr, int size, int count, int maxcount){
if(size == 0)
return maxcount < count ? count : maxcount;
if(count == 0){
return LongestSeries(arr + 1, size - 1, 1, maxcount);
} else {
if(arr[-1] == *arr){
return LongestSeries(arr + 1, size - 1, count + 1, maxcount);
} else {
if(count > maxcount)
maxcount = count;
return LongestSeries(arr + 1, size - 1, 1, maxcount);
}
}
}
int main(void){
int arr[] = {1, 2, 3, 3, 4, 5, 6, 6, 6, 6, 7, 8};
int size = sizeof(arr)/sizeof(*arr);
printf("%d\n", LongestSeries(arr, size, 0, 0));
}
reduce code:
int LongestSeries(int* arr, int size, int count, int maxcount){
if(size == 0)
return maxcount < count ? count : maxcount;
if(count == 0 || arr[-1] != *arr){
if(count > maxcount)
maxcount = count;
return LongestSeries(arr + 1, size - 1, 1, maxcount);
}
return LongestSeries(arr + 1, size - 1, count + 1, maxcount);
}
I'm trying to implement a code that recursively calls itself and prints the given digits in ascending order, i.e. if the number is 5, then the function will print 1 2 3 4 5. I cannot use loops in any way!
void print_ascending(int n)
{
int i = 1;
if(i < n)
{
printf("%d", i);
i++;
print_ascending(n);
}
}
Of course, the problem with this code is it will re-initialize the variable i to 1 every single time and infinitely loop to print 1.
There are also no outside global variables or outside functions allowed!
Try incrementing value of argument, when you call recursive function each time.
void print_ascending(int limit, int current_value)
{
if(current_value < limt)
{
printf("%d ", current_value);
print_ascending(limit, current_value + 1);
}
}
Initially call the function as
print_ascending(5, 1)
Alternatively,
void print_ascending(int n)
{
if(n > 0)
{
print_ascending( n - 1);
printf("%d ", n);
}
}
The function can be defined simply the following way
void print_ascending( unsigned int n )
{
if ( n > 1 ) print_ascending( n - 1 );
printf( "%u ", n );
}
I used type unsigned int instead of int because otherwise you have to consider the case when n can be a negative number.