Search code examples
cparameter-passingfunction-pointers

Pointer variables generated in functions cannot be passed in parameters of function pointers


Topic: Given a positive integer with no more than 5 digits, require:

  1. Find out how many digits it is;
  2. Output each digit separately;
  3. Output each digit in reverse order. For example, if the original digit is 321, 123 should be output.

When I called the following program using a function pointer, I found that the parameters "number" and "digit" could not be passed to each function.

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

void inputNumber(int *number){
    printf("Enter number: ");
    scanf_s("%d", number);
    while(*number <= 0 || *number > 9999){
        if(*number <= 0){
            printf("The number is not positive integer! Retry!\nEnter number: ");
        }
        if(*number > 9999){
            printf("The number is more than 5 digits! Retry!\nEnter number: ");
        }
        scanf_s("%d", number);
    }
}

void outputDigit(int *number, int *digit){
    int i;
    for(i = 0; *number != 0; i++){
        *number /= 10;
    }
    *digit = i;
    //printf("%d\n", *number);    Test Output
    printf("The number is %d digits!\n", i);
}

void outputNumber(int *number, int *digit){
    int base = 10;
    int temp = *number;
    for(int i = 1; i < *digit - 1; i++){
        base *= 10;
    }
    //printf("%d %d\n", *number, temp);    Test Output
    for(int i = 0; i < *digit; i++){
        printf("%d ", temp / base);
        temp -= temp / base * base;
        base /= 10;
    }
    printf("\n");
}

void outputReverseNumber(int *number, int *digit){
    int temp = *number;
    for(int i = 0; i < *digit; i++){
        printf("%d ", temp % 10);
        temp = (temp - temp % 10) / 10;
    }
    printf("\n");
}

void function(int *number, int *digit, void (*fun[])(int*, int*)){
    for(int i = 0; i < 3; i++){
        fun[i](number, digit);
    }
}

int main(){
    int *number = (int*)malloc(sizeof(int));
    int *digit = (int*)malloc(sizeof(int));
    void (*fun[3])(int*, int*) = {outputDigit, outputNumber, outputReverseNumber};
    inputNumber(number);
    function(number, digit, fun);
    free(number);
    free(digit);
    system("pause");
    return 0;
}

I want parameters in function pointers to be passed by pointer variables generated by other functions.


Solution

  • There is no problem with parameter passing. The problem is that you keep dividing numbers inside outputDigit and thereby ensuring that the original number is zero upon leaving the function. That can be fixed by using a temporary variable instead:

    void outputDigit(int *number, int *digit){
        int i;
        int tmp = *number;
        for(i = 0; tmp != 0; i++){
            tmp /= 10;
        }
        *digit = i;
        printf("The number is %d digits!\n", i);
    }
    

    Another bug is that *number > 9999 checks that a number isn't larger than four digits, not five. Should be 99999.

    General code review:

    • Avoid scanf_s since it is poorly standardized. Original scanf actually supports reading a fixed amount of characters if you check the result. However, in this specific case it would have been much more convenient to read the input as a string with fgets, since base-10 decimal digits is a cumbersome format forcing you to use division over and over.

    • It makes no sense at all to use function pointers here. The various functions in your array do unrelated tasks, so generic programming with an abstraction layer only makes the program hard to read for nothing gained. I take it you are just using them for learning purposes.

    • The big bug here could have been avoided if you use const correctness, meaning that pointer parameters that aren't supposed to be modified should be marked read-only. That is:

      void outputDigit(const int *number, int *digit);
      void outputNumber(const int *number, const int *digit);
      void outputReverseNumber(const int *number, const int *digit)
      

      Although now the functions have different types so the function pointer array can no longer be used either.

    • In general don't mix up algorithms (calculating number of digits) with user I/O (printing or taking input). Programmers don't expect a function named outputDigit to calculate a digit, they expect it to print one.

    • Using dynamic allocation for a single int is senseless. Similarly, casting the result of malloc is pointless.

    • Always use typedef when dealing with function pointers, for readability. In this case you could have done:

      typedef void func_t (int*, int*);
      ...
      func_t* fun[3] = {outputDigit, outputNumber, outputReverseNumber};
      ...
      void function(int *number, int *digit, func_t* fun[3])