La lettura dal terminale senza l'attesa del carattere '\n' si chiama `canonical input processing'
leggendo le pagine info della libreria GNU C alla sezione `Low-level terminal interface' trovi tutto quel che riguarda le impostazioni di lettura e scrittura dalla console.
DOCUMENTAZIONE:
libc (pagina info attraverso il comando `info libc' e poi entri nella sezione low-level Terminal Interface)
man: `man tcsetattr', `man tcgetattr' (Si possono usare anche le funzioni linux ioctl `man ioctl' e `man tty_ioctl' ma il programma non è piu compatibile con gli standard POSIX)

Un esempio di funzione che legge un solo carattere:

#include <termios.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>

/* Legge un sigolo carattere dal terminale senza
* aspettare la pressione del tasto invio.
* Restituisce 1 in caso di successo, 0 in caso di errore.
* Il carattere letto viene memorizzato nel parametro `c' */
unsigned char read_nocannon(int *c)
{
/* orig per ripristinare le impostazioni
* new per cambiare le impostazioni */
struct termios orig, new;

/* Legge le impostazioni del terminale e
* le memorizza in orig (vedere `man tcgetattr')*/
if(tcgetattr(0, &orig) != 0)
{
perror("tcgetattr");
return 0;
}
/* copia le impostazioni in new. Metodo consigliato nella
* documentazione della libreria GNU C (vedere `info libc') */
memcpy(&new, &orig, sizeof(struct termios));

/* Imposta `canonical imput' e toglie l'echo dei caratteri */
new.c_lflag &= ~(ICANON|ECHO);

/* Imposta il minimo numero di caratteri da leggere */
new.c_cc[VMIN] = 1;

/* Imposta il tempo di attesa 0 dice a read di attendere finchè non ci
* sono X.c_cc[VMIN] caratteri letti */
new.c_cc[VTIME] = 0;

/* Setta le nuove impostazioni (vedere `man tcsetattr') */
if(tcsetattr(0, TCSANOW, &new) != 0)
{
perror("tcsetattr");
return 0;
}

/* legge 1 carattere */
if(read(0, c, 1) == -1)
{
perror("read");
tcsetattr(0, TCSANOW, &orig);
return 0;
}

/* Ripristina le impostazioni precedenti ###IMPORTANTE### */
tcsetattr(0, TCSANOW, &orig);

return 1;
}

int main()
{
int c;
if(read_nocannon(&c))
{
printf("Read one character: '%c'\n", c);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
Spero di esserti stato utile. Se hai domende sono qui.