This C program shows how to mask password input with asterisks (*) — exactly what you see on a login screen, where each character you type is hidden behind a *. The trick is to read the keyboard without echoing the typed character to the screen, print a * in its place, and store the real character in a buffer. Because turning off echo is operating-system specific, this tutorial gives you a single portable program that works on Windows, Linux and macOS.
Why You Can’t Just Use scanf
A normal scanf("%s", password) or getchar() echoes every character straight to the terminal, so anyone looking over your shoulder sees the password. To hide it we must read each key in “raw” mode with echo disabled:
- On Windows,
_getch()from<conio.h>reads a key without echoing it. - On Linux / macOS, we temporarily turn off the
ECHOandICANONterminal flags using<termios.h>, read the key, then restore the old settings.
The Program (Portable)
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <conio.h>
static int get_ch(void) { return _getch(); }
#else
#include <termios.h>
#include <unistd.h>
static int get_ch(void)
{
struct termios old, raw;
int ch;
tcgetattr(STDIN_FILENO, &old); /* save current settings */
raw = old;
raw.c_lflag &= ~(ICANON | ECHO); /* turn off line buffering + echo */
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &old); /* restore settings */
return ch;
}
#endif
int main(void)
{
char password[32];
int i = 0, ch;
printf("Enter your password: ");
fflush(stdout);
while (i < (int)sizeof(password) - 1) {
ch = get_ch();
if (ch == '\n' || ch == '\r') /* Enter ends input */
break;
if (ch == 127 || ch == 8) { /* Backspace / Delete */
if (i > 0) {
i--;
printf("\b \b"); /* erase the last * on screen */
fflush(stdout);
}
continue;
}
password[i++] = (char)ch;
printf("*");
fflush(stdout);
}
password[i] = '\0'; /* null-terminate the string */
printf("\nYour password is: %s\n", password);
return 0;
}
How the Program Works
get_ch()hides the OS difference: one definition for Windows (_getch), one for Linux/macOS (termios). The rest of the program is identical on every platform.- Each keypress is read without echo. We store the real character in
password[]and print a*so the screen never shows the actual text. - Backspace (codes 8 or 127) deletes the last character and erases its
*using"\b \b"— backspace, space, backspace. - Enter (
\nor\r) ends input. We then write'\0'to terminate the string properly — the original textbook code used'', which is an invalid empty character constant. - The loop is bounded by
sizeof(password) - 1, so it can never overflow the buffer — unlike the oldgets()version.
This is a complete modernisation of the classic example: gone are void main(), clrscr(), gets() and the Windows-only conio.h dependency.
Sample Output
Enter your password: ******** Your password is: secret12
(As you type secret12 you only ever see eight asterisks on screen.)
A Note on Real Security
Masking only hides the password from shoulder-surfers. In real software you should never store or print a plaintext password — you would hash it (e.g. with bcrypt) and compare hashes. This program is for learning terminal input, not production authentication. For the C fundamentals behind it, The C Programming Language by Kernighan and Ritchie is the classic reference — find it on Amazon.
This post contains affiliate links. If you buy through them, we may earn a small commission at no extra cost to you.
Related C Programs
- C Program to Demonstrate the getchar() Function
- C Program to Compare Two Strings
- Complete List of C Programs
This program reads the terminal directly, so it needs a real local terminal — browser-based online compilers can’t emulate raw key input. Set up a proper toolchain with our guide to a complete C development environment.