简体   繁体   中英

Recursive function to count the amount of digits in a number

Is there a way to code a recursive function that prints the number of the digits in a number such that:

-It is a void function

-The "if" condition is if(num==0), return

-The "else" will call the recursion.

I saw 2 different types of codes, one of them is where the "if" condition has the recursive call and the else is for "return". But thats not what I want.

I am pretty bad with recursion and trying to understand it by coding myself, but unsuccessfully.

This is my code(I understand why it prints 122 instead of 3 but I dont really know how code it differently. Help anyone?)

    #include <iostream>
    #include <string.h>
    using namespace std;
    void numOfDigits(unsigned int num);

    int main(){
        int num = 994;
        numOfDigits(num);
    }
    void numOfDigits(unsigned int num)
    {
        int size = 1;
        if (num==0)
            return;
        else
        {
            if (num / 10 != 0)
                size++;
            numOfDigits(num / 10);
        }
        cout << size;
    }

A quick hack that makes this code work is to make size static, that is, change

int size = 1;

to

static int size = 1;

But that only works the first time you call the function.

For a more robust solution , in each call to the function you have to pass the count so far:

void numOfDigits(unsigned int num, int countSoFar = 0) {
    if (num == 0)
        std::cout << countSoFar << '\n';
    else
        numOfDigits(num / 10, countSoFar + 1);
}

You can pass a value by reference and make use of it, initialize ans=0 every time you call this function

void recursive(unsigned int num,int &ans){
    if(num == 0){
        return;
    }
    else{
        ans++;
        recursive(num/10,ans);
    }
}

See this and this

You have a number of mistakes in the numOfDigits() function.

  1. First, you are declaring a new local variable called size each time the function is called. This has no relation to the 'size' defined in the calling function. To see this, print size after initializing it. To fix this, make size static; it will then use the same static variable each time you call the function.
  2. As you are printing size at the end of the function, it simply gives the value of the size variable after that function is run. Even if you set size as static, you will also print the intermediate values of size. An easy way to fix this is to allow the function to return size, and you would have to simply print the value of the function in the main function.

     #include <iostream> #include <string.h> using namespace std; int numOfDigits(unsigned int num); int main(){ int num = 994; cout<<numOfDigits(num); } int numOfDigits(unsigned int num) { static int size = 1; if (num==0) return 0; else { if (num / 10 != 0) size++; numOfDigits(num / 10); } return size ; } 

Make sure to put the case with (num == 0) as you want; in this case it prints 0 as the answer.

PS: Always put a space after printing numbers. Otherwise you might think that 1 2 2 (which are the numbers actually printed) is the number 122.

#include <iostream>
#include <string.h>
using namespace std;
void numOfDigits(unsigned int num);

void main(){
    int num = 994;
    int size = 1;
    cout << numOfDigits(num, size);
}
void numOfDigits(unsigned int num, int &size)
{

    if (num==0)
        cout<<size;
    else
    {
        if (num / 10 != 0)
            size++;
        numOfDigits(num / 10, size);
    }

}

try declaring size globally because it was intialized every time when the funtion executes

   int size = 1;
void numOfDigits(unsigned int num)
    {

        if (num==0)
            return;
        else
        {
            if (num / 10 != 0)
                size++;
            numOfDigits(num / 10);
        }
    }

print value of size inside main

Without using any global variable, this code works. Just a little note: you declared unsigned int the argument, but the number you give to the function is a signed integer.

 #include <iostream>
    #include <string.h>
    using namespace std;
    void numOfDigits(unsigned int num, unsigned int& digits);

    int main(){
        unsigned int num = 93934;
        unsigned int digits = 1;
        numOfDigits(num, digits);
        cout <<digits <<endl;

        return 0;
    }

    void numOfDigits(unsigned int num, unsigned int& digits) {
        if (num==0){
            return;
        }else{
            if (num / 10 != 0){
                ++digits;
                numOfDigits(num / 10, digits);
            }
        }
    }

I think your misunderstanding is that you assume that size is one single variable. However, in every call of your function, you have a different one. Also, every call of your function will print it again.

The cout in your main does nothing, since it prints a void, which has no content.

Usually, you'd give it a return parameter that is the accumulated number, like

int numOfDigits(unsigned int num);
void main(){
    cout << numOfDigits(994) << endl;
}

If you don't want that for some reason, you could do it by reference:

int numOfDigits(unsigned int num, unsigned int& digits);
void main(){
    unsigned int digits;
    numOfDigits(994,digits);
    cout << digits << endl;
}

but that is not that good.

That said, in terms of style, what I would do is either making it a loop (idea is that you want to avoid recursion most times):

unsigned int numOfDigits(unsigned int num){
    if(num == 0) { return 1; }
    unsigned int size = 0;
    while(num != 0){
        size++;
        num /= 10;
    }
    return size;
}

which can be also done with a call by reference return value. But again, that is somewhat strange if not necessary.

You might even make it a one-liner by using mathematics, cout << floor(log_10(num)) << endl; (not accounting for the special case if num is zero)

One solution that would also work is to make size a global variable. However, I'd advice against that. Global variables should be avoided in general. Just wanted to mention it if somebody else recommends it.

Lastly, you could go with a class, like DigitsCounter that is usually short lived and does the recursive call on methods, with the size variable being a class member. That is overkill in your case, though.

  • numOfDigits is a void function

  • The "if" condition is if(num==0), return

  • The "else" will call the recursion.

Here:

void numOfDigits(unsigned int num)  {
    if (num == 0)
        return;

    // The "else" will call the recursion.
    else {

        static int size = 1;

        if (num / 10 != 0) {
            size++;

            numOfDigits(num / 10);
        }

        else {
            cout << size << '\n';
            size = 1;
        }
    }
}

try this code :

int numOfDigits(unsigned int num)
{
    int size = 1;
    if (num!=0)
    {
        if (num / 10 != 0)
           size+= numOfDigits(num / 10);
    }
    return size;
}

use the return value in your main function

The problem with using a void return type on recursive functions is that it's not possible for the nested calls to return any information back to the method which invoked them. If we want to print the value at the first (outer) call, that first call can't gain any information from it's recursive call.

As you've observed, it's not possible to simply print the value as we go, since there isn't a one-to-one mapping from recursive calls to characters of the output (if we use Base 10... see the appendix). If we relax the condition that the if condition must return immediately, we can avoid this problem by passing the information as parameters to the recursive call and then printing the value at the deepest level of recursion. For example:

// The accumulator starts at 0, then increases by 1 for each recursive call
void numOfDigits(unsigned int num, unsigned int accumulator = 0) {
  if (num == 0) {
    if (accumulator == 0) cout << 1; // Special case: numOfDigits(0) = 1
    else cout << accumulator;

  } else numOfDigits(num / 10, accumulator + 1);
} 

Side-note: This is now a tail-recursive method: it makes the recursive call as its last action. This is useful, since it allows the compiler to reduce the space complexity of the method (see explanation ). Essentially, the compiler transforms the method to simple iteration, eliminating the need for accumulating stack frames.

Appendix: The only way I can see to keep constraint (2) is to print the number of digits in Base 1, since each digit taken from the argument corresponds directly to a single character in Base 1). This probably isn't what you meant, but here's a solution:

// The accumulator starts at 0, then increases by 1 for each recursive call
void numOfDigits(unsigned int num) {
  if (num == 0) return;

  else {
    cout << 1
    numOfDigits(num / 10);
  }
}

NB This method will not print anything for numOfDigits(0) , which is necessary if we want to keep the line if (num == 0) return;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM