Disclaimer, this is help with a school assignment. That being said, my issue only occurs about 50% of the time. Meaning if I compile and run my code without edits sometimes it will make it through to the end and other times it will not. Through the use of multiple print statements I know exactly where the issue is occurring when it does. The issue occurs in my second call to hugeDestroyer(right after the print 354913546879519843519843548943513179 portion) and more exactly at the free(p->digits) portion.
I have tried the advice found here (free a pointer to dynamic array in c) and setting the pointers to NULL after freeing them with no luck.
Through some digging and soul searching I have learned a little more about how free works from (How do malloc() and free() work?) and I wonder if my issue stems from what user Juergen mentions in his answer and that I am "overwriting" admin data in the free list.
To be clear, my question is two-fold.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Secondly, how can I guard against this kind of behavior in my functions?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct HugeInteger
{
    // a dynamically allocated array to hold the digits of a huge integer
    int *digits;
    // the number of digits in the huge integer (approx. equal to array length)
    int length;
} HugeInteger;
// Functional Prototypes
int str2int(char str) //converts single digit numbers contained in strings to their int value
{
    return str - 48;
}
HugeInteger *parseInt(unsigned int n)
{
    int i = 0, j = 0;
    int *a = (int *)calloc(10, sizeof(int));
    HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
    if(n == 0)
    {
        p->digits = (int *)calloc(1, sizeof(int));
        p->length = 1;
        return p;
    }
    while(n != 0)
    {
        a[i] = n % 10;
        n = n / 10;
        i++;
    }
    p->length = i;
    p->digits = (int *)calloc(p->length, sizeof(int));
    for(i = 0; i <= p->length; i++, j++)
        p->digits[j] = a[i];
    return p;
}
HugeInteger *parseString(char *str)  //notice datatype is char (as in char array), so a simple for loop should convert to huge int array
{
    int i = 0, j = 0;
    HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
    if(str == NULL)
        {
        free(p);
        p = NULL;
        return p;
        }
    else
    {
        for(i=0; str[i] != '\0'; i++)
            ;
        p->length = i;
        p->digits = (int *)calloc(p->length, sizeof(int));
        for(; i >= 0; i--)
            p->digits[j++] = str2int(str[i - 1]);
    }
    return p;
} //end of HugeInteger *parseString(char *str)
HugeInteger *hugeDestroyer(HugeInteger *p)
{
//printf("No problem as we enter the function\n");
    if(p == NULL)
        return p;
//printf("No problem after checking for p = NULL\n");
    if(p->digits == NULL)
    {
        free(p);
        p = NULL;
        return p;
    }
//printf("No Problem after checking if p->digits = NULL\n");  
    //else
    //{
        free(p->digits);
printf("We made it through free(p->digits)\n");
        p->digits = NULL;
printf("We made it through p->digits = NULL\n");
        free(p);
printf("We made it through free(p)\n");
        p = NULL;
printf("We made it through p = NULL\n");
        return p;
    //}
    //return NULL;
}//end of HugeInteger *hugeDestroyer(HugeInteger *p)
// print a HugeInteger (followed by a newline character)
void hugePrint(HugeInteger *p)
{
    int i;
    if (p == NULL || p->digits == NULL)
    {
        printf("(null pointer)\n");
        return;
    }
    for (i = p->length - 1; i >= 0; i--)
        printf("%d", p->digits[i]);
    printf("\n");
}
int main(void)
{
    HugeInteger *p;
    hugePrint(p = parseString("12345"));
    hugeDestroyer(p);
    hugePrint(p = parseString("354913546879519843519843548943513179"));
    hugeDestroyer(p);
    hugePrint(p = parseString(NULL));
    hugeDestroyer(p);
    hugePrint(p = parseInt(246810));
    hugeDestroyer(p);
    hugePrint(p = parseInt(0));
    hugeDestroyer(p);
    hugePrint(p = parseInt(INT_MAX));
    hugeDestroyer(p);
    //hugePrint(p = parseInt(UINT_MAX));
    //hugeDestroyer(p);
    return 0;
}