I am an absolute beginner to programming and am learning it using C. I have just learned function pointers and tried to implement a quicksort function using function pointers to determine the nature of sorting.//Program implementing a quick-sort function using Hoare method //to partition using a random pivot.//Function pointer is used to determine the nature of sort (Ascending / Descending).#include <time.h>#include <math.h>#include <stdlib.h>#include <stdio.h>//Typedef: Function Pointer to be used for determining he nature of sort:typedef int (*p_compare_function)(long long,long long);enum BOOLEAN{FALSE,TRUE};//FUNCTION PROTOTYPES://Functions to be used for determining the nature of sort:int Ascending   (long long x,long long y);int Descending  (long long x,long long y);//Generates a random number between a lower and a upper limit.long long my_random(long long min, long long max);  //Functions to be used for the actual functioning of the algorithm:void my_swap(long long* a, long long* b);long long quicksort_partition(  long long* array, long long begin,                                long long end, p_compare_function cmp);void quicksort( long long* array, long long begin, long long end,                 p_compare_function cmp);void printarray(long long *pArray, long long nSize);int main() {    srand(time(NULL));    long long array[] = {5,2,9,7,3,1,6,8,4,0,4,3,5,67,22,3,644,335,345,24,                         33,25,22,5,2,43223,4};    long long arraysize = sizeof(array)/sizeof(*array);    //Testing    quicksort(array,0,arraysize-1,Ascending);    printarray(array,arraysize);    quicksort(array,0,arraysize-1,Descending);    printarray(array,arraysize);    return 0;}void printarray(long long *pArray, long long nSize) {    for (long long i=0; i < nSize; i++) {        printf(%lld ,pArray[i]);    }    printf(\n);}int Ascending   (long long x,long long y) {    if (x < y) {        return TRUE;    }    else {        return FALSE;    }}int Descending  (long long x,long long y) {    return ( !(Ascending(x,y)) );}long long my_random(long long min, long long max) {    long double result;    result = ((double)rand() / ((double)RAND_MAX + 1.0));    result = (result * (max - min));    result += min;    result = (long long) result;    return result;}void my_swap(long long* a, long long* b) {    long long temp = *a;    *a = *b;    *b = temp;}long long quicksort_partition(  long long* array, long long begin,                                 long long end, p_compare_function cmp) {    //Randomly selecting the pivot.    long long random_index  = my_random(begin,end);    long long pivot;    my_swap(&array[begin],&array[random_index]);    pivot = array[begin];    //Partion matheod used : Hoare partition.    long long i  = begin - 1;    long long j  = end   + 1;    while(TRUE) {        do {            j--;        } while (!(cmp(array[j],pivot)) && array[j] != pivot);        do {            i++;        }while ((cmp(array[i],pivot)) && array[i] != pivot);        if (i < j) {            my_swap(&array[i],&array[j]);        }        else {            return j;        }    }}void quicksort(long long* array, long long begin, long long end, p_compare_function cmp) {    if (begin < end) {        long long q = quicksort_partition(array, begin, end, cmp);        quicksort(array, begin  , q, cmp);        quicksort(array, (q + 1),  end   , cmp);    }}Please point out the bad practises used here and help me to rectify them.
Implementation of a quicksort function
beginner;algorithm;c;reinventing the wheel;quick sort
Here are some things I noticed that might help you improve your code.Use stdboolInstead of defining your own values for TRUE and FALSE, you might consider instead using #include <stdbool.h> which defines true and false.Use a consistent naming strategySome of your functions are uppercase as with Ascending, others have an underscore as with quicksort_partition and still others omit the underscore as with printarray.  The names, of course, are all legal C and the compiler doesn't care, but other people reading your code will find it easier if you use a consistent naming strategy for both functions and variables.return is not a function callBecause return is not a function call, parentheses are generally not used when returning a value.  Thus instead of this:int Descending  (long long x,long long y) {    return ( !(Ascending(x,y)) );}you could write this:int Descending  (long long x,long long y) {    return !Ascending(x,y);}Although technically, it would be a bit better to write it instead like this to avoid the negation operation:int Descending  (long long x,long long y) {    return Ascending(y,x);}Simplify your codeThe Ascending function could instead be written as a single line:int Ascending   (long long x,long long y) {    return x < y;}This makes it much simpler to understand the code at a glance.Similarly, the last two lines of my_random are currently these:result = (long long) result;return result;But the penultimate line is completely useless.  There is an implicit cast in the return and the explicit cast doesn't change the type of result which is long double so is useless.Use const where possibleYour printarray function just prints the passed array and does not (and should not) modify the array.  For that reason, the function prototype should instead look like this:void printarray(const long long *pArray, long long nSize);Avoid using long long for an array indexAn index into an array is an int or a size_t and not a long long, so having the an index that is a long long doesn't actually give you a larger range -- it simply forces the compiler to cast (on platforms for which an int and long long are different sizes).Reconsider the interfaceThe prototype for quicksort is currently this:void quicksort( long long* array, long long begin, long long end,                 p_compare_function cmp);However, it would probably make more sense from a user's point of view to have that instead be this:void quicksort( long long* array, size_t arraysize, p_compare_function cmp);You'll still need your original version internally, but that's not the way a user would likely want to think about using this sort function, which brings me to the last point.Define the interface clearlyFor a function like this which has the potential to be reused, one would normally define an interface which would be in a header file, say, quicksort.h and an implementation file which would be in quicksort.c.  The header file would contain only and exactly the public interface functions such as quicksort but not internal functions such as quicksort_partition.  This gives the user just what is needed but hides the implementation details.