Converting Integer to dynamically allocated Char array, digit by digit using pointers Problem: Write a function to convert Integer to String, using only
  pointers, without array indexes, string must be dynamically
  allocated.




#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdbool.h&gt;

// move each character in array one place to the right
// we need to make place for new character on the left
void moveArrayElementsRight(char *ptr, int len) {
    for (int j = len; j &gt; 1; j--) {
        *(ptr + j - 1) = *(ptr + j - 2);
    }
}

void intToStr(int myNumber, char* myString){
    int i = 1;    //track size of allocated memory
    bool isMinus = false;

    if (myNumber &lt; 0) {

        myNumber *= -1;    //without this (myNumber % 10) + '0' wont work
        isMinus = true;
    }

    if (myNumber == 0){    //special case for 0

        myString = (char*)realloc(myString, ((i + 1) * sizeof(char)));
        *myString = '0';
        *(myString + 1) = '\0';
    }

    while (myNumber != 0) {

        myString = (char*)realloc(myString, ((i + 1) * sizeof(char)));  //increse memory =+1 for next digit
        i++;
        moveArrayElementsRight(myString, i);
        *myString = (myNumber % 10) + '0'; //put digit to array
        myNumber /= 10;
    }

    if (isMinus) {

        myString = (char*)realloc(myString, ((i + 1) * sizeof(char)));  //increse memory =+1 for '-' sign
        i++;
        moveArrayElementsRight(myString, i);
        *myString = '-'; //put sign at the beginning
    }
}

int main() {

    int numberToConvert = -10;
    char *numberAsString = (char*)malloc(sizeof(char));  //create empty array, with place only for '\0'
    *numberAsString = '\0';    //mark the end of array

    intToStr(numberToConvert, numberAsString);

    printf("%s", numberAsString);

    return 0;
}
Issues Concerning Allocation
It is not necessary to cast the result of a call to malloc() in C, and many consider this to be a more error-prone style. It is easier to write correctly, read, and maintain the allocation line if you write it like this:
char *numberAsString = malloc(sizeof(*numberAsString));

This way, if the type is changed at some point in the future, there is only one place you need to update, versus three places to update in your version.
I would also suggest moving the allocation from main() into the intToStr() function (which is already reallocating the memory), and returning a pointer to the allocated memory to the calling function. This would necessitate changing the function signature of intToStr() to:
char * intToStr(int myNumber, char* myString);

Then in main(), you should declare:
char *numberAsString = NULL;

The same advice given above for malloc() applies to the calls to realloc() in the function intToStr(). Additionally, realloc() returns a NULL pointer in the event of an error. By assigning the return value directly to myString you risk leaking memory by losing the pointer to the previous allocation. You should store the return value of realloc() in a temporary variable, and then assign it to myString if it is non-null.
Continuing with allocation issues, I would consider mallocing enough memory to hold any int number-string (really, I would suggest using an int32_t number-- see below) at the beginning of intToStr(). Then, before returning the pointer to this memory, you can realloc() to the size of the actual number-string, i.e.:
number_string_sz = 12;  // for int32_t plus space for `-` and `\0`

myString = malloc(number_string_sz);

...

temp = realloc(myString, strlen(myString) + 1);
if (temp) {
    myString = temp;
}

You may wish to return a NULL pointer from intToStr() if there is an allocation error, and let the caller handle the error. Of course, the caller is responsible for freeing allocated memory.
Integer Overflow
Note that it is possible that myNumber is equal to INT_MIN, and then the line myNumber *= -1; would lead to integer overflow (invoking undefined behavior for signed integer types). Consider using a fixed-width type, such as int32_t, that is passed into the function, and copy this to a larger fixed-width type (int64_t) for a working copy within the function. The reasoning here is that the widths of the integer types are implementation-dependent, and even long int is only guaranteed to be at least as wide as int. By choosing specific widths for your integer types, you can protect against integer overflow in your calculations. The int64_t type is larger than int32_t, so the smallest value which can be held by an int32_t, when stored in an int64_t, can safely be multiplied by -1.