Search code examples
crecursioncommand-line-argumentsfunction-definition

Creating a C program with recursive function to check if a given integer is a multiple of 4. Why is my implementation failing?


I was trying to create this program:

function power4 takes a command line argument "n", it converts it into an integer (because in the command line everything is formatted as a string), and it does something to say whether or not "n" is multiple of 4.

output format must be the same way: "4*i=n", and it's required to use recursion.

because I need to use recursion, I cannot use modulus "%" operand; i've used subtractions, and the base case of recursion must be when "n == 0", or when "n < 0" (or when n = 1, if it's not multiple of 4), inductive step is "power4(n - 4, i + 1)".

I've used strtol function to convert "n" to an integer, and I've used *p to check if strtol was successful or not.

I did it in the following way:

#include <stdio.h>
#include <stdlib.h>

void power4(int n, int i) {
    if (n < 0 || n == 1) {
        printf("!p4"); 
        return; 
    } 
    if (n == 0) {
        printf("4*");
        printf("%d", i);
        printf("=%d", n); 
    }
    power4(n - 4, i + 1); 

}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        return 1; 
    }
    int ptr = 0; 
    int* p = &ptr; 
    int c = strtol(argv[1], p, 10); 
    if (p == NULL) {
        return 1; 
    }
    power4(c, 1); 
    return 0; 
} 

I've tried this program with "n = 12" (i.e a multiple of 4) but it says it's not multiple, why is it not working properly?

EDIT: this is the updated version of my solution:

#include <stdio.h>
#include <stdlib.h>

void power4(int n, int i) {
    if (n < 0 || n == 1) {
        printf("!p4"); 
        return; 
    } 
    if (n == 0) {
        printf("4*");
        printf("%d", i);
        printf("=%d", n); 
        return; 
    }
    power4(n - 4, i + 1); 
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        return 1; 
    }
    int c = strtol(argv[1], NULL, 10); 
    power4(c, 1); 
    return 0; 
}

EDIT: I've changed the recursive algorithm, but now the error is that argc!=2 is always true, and therefore it returns always 1.

#include <stdio.h>
#include <stdlib.h>
void power4(int n1, int i, int n2) {
    // base case
    if (n1 % 4 != 0 && n1 != 1) {
        printf("!p4"); 
        return; 
}
    if (n1 == 1) {
        printf("4^%d=%d", i, n2); 
        return; 
    }
    // inductive step
    power4(n1 / 4, i + 1, n2); 
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        return 1; 
    }
    int c = strtol(argv[1], NULL, 10); 
    power4(c, 0, c); 
    return 0; 
}

Solution

  • For starters the function should not output any message. It is the caller of the function that will issue a message.

    So the function return type should not be void.

    With your approach the function will not work correctly with signed integers. So there is no sense to declare the function parameter as having the signed integer type int. And the function should have only one parameter.

    The function can be defined the following way as shown in the demonstration program below.

    #include <stdio.h>
    
    unsigned int power4( unsigned int n )
    {
        if (n == 0)
        {
            return 0;
        }
        else if (n < 4)
        {
            return -1;
        }
        else
        {
            unsigned int i = power4( n - 4 );
            return i == -1 ? -1 : 1 + i;
        }
    }
    
    int main( void )
    {
        for ( unsigned int n = 0; n < 13; n++ )
        {
            unsigned int i = power4( n );
    
            if (i != -1)
            {
                printf( "4*%d = %d\n", i, n );
            }
            else
            {
                puts( "!p4" );
            }
        }
    }
    

    The program output is

    4*0 = 0
    !p4
    !p4
    !p4
    4*1 = 4
    !p4
    !p4
    !p4
    4*2 = 8
    !p4
    !p4
    !p4
    4*3 = 12
    

    To convert command line argument you can use standard function strtoul as for example

    unsigned int n = ( unsigned int )strtoul( argv[1], NULL, 10 );
    

    If you want to check whether the conversion was successful then you need to supply the second parameter of the call of strtoul unequal to NULL and check its value after the call and the value of errno.