Una prima miglioria consiste nel terminare a 0 la stringa, come da convenzione in C.

Per il C la convenzione (e quello che si aspettano centinaia di funzioni C) è che la stringa di caratteri sia un array di char che termina con un carattere di valore ascii = 0.


codice:
int main()
{
    int i=1;//inizialmente serve almeno un carattere per il terminatore '\0'
    char *c,ci;
    c=(char*)malloc(sizeof(char));

    while(ci!=10)
    {
      ci=getchar();
      c[i]=ci;
      i++;
      c=(char*)realloc(c,sizeof(char)*i);
    }
    c[i]='\0'; //inserisco terminatore '\0' 
    puts(c);
    return 0;
}
Se vuoi anche raffinare un po il tutto, una seconda miglioria potrebbe consistere nel chiamare realloc non per ogni singolo carattere ma ogni multiplo di N (che so io 512) caratteri, risparmiando un be po di realloc.

Una terza miglioria sarebbe verificare che malloc e realloc non ritornino NULL, a meno che non sia un esercizio scolastico sarebbe anzi obbligatorio.