When you allocate the Memory,
copy
points at the first character in the space. You then use that to copy the input to an output area - you don't really need to do that at all, just use the two pointers you already have:
copy
and
input
char* uppercase_no_array(char* input)
{
char* mem = malloc(sizeof(char) * (strlen(input) + 1));
char* copy = mem;
char c;
do
{
c = *input++;
... uppercase it here ...
*copy++ = c;
} while(c != '\0')
return mem;
}