C Language File-Writable Account Password Login System

The account login system is essential in many system designs. Today, this login system has comprehensive features, including registration, login, password recovery, password modification, and a password masking feature that displays * when entering the password. Now, let’s get to the code!

Table of Contents

  • 1. Header Files & Structure & Basic Function Implementation

  • 2. Main Function & Login Interface

  • 3. Registration System

  • 4. Login System

  • 5. Password Recovery (Change Password)

  • 6. Password Input & Masking

7. Complete Code!!!!

First, you need to create a file named users.dat in the same directory as the .c file to store data, as shown in the image below!

C Language File-Writable Account Password Login System
Image

You can also name it something else; the .dat suffix is just a random choice of mine, as long as you like it! But remember to change the filename in the code!

1. Header Files & Structure & Basic Function Implementation

// Include header files
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h> // Used to reflect unexpected situations, will be discussed below
#include <windows.h>

// Define macro constants
#define MAX_ID 11 // Maximum length of ID
#define MAX_PWD 20 // Maximum length of password
#define MAX_NAME 15 // Maximum length of name
#define MAX_SEX 5 // Maximum length of gender
#define MAX_PHONE 12 // Maximum length of phone

// Create user structure
typedef struct Users
{
 char id[MAX_ID]; // id is the login account
 char pwd[MAX_PWD]; // password
 char name[MAX_NAME]; // name
 char sex[MAX_SEX]; // gender
 char phone[MAX_PHONE]; // phone
} Users;

// Declare functions

// Print menu
void menu();

// User registration
void Register();

// Login
void Login();

// Password recovery
void Reback();

// Set cursor position
void gotoxy();

// Get x position
int posx();

// Get y position
int posy();

// Password input (with masking feature)
void Getpwd(char* pwd);

This section defines many macro constants that can be adjusted as needed, making it convenient to modify without changing them one by one in the code.

2. Main Function & Login Interface

void menu()
{
 printf("************************************\n");
 printf("************************************\n");
 printf("*****1.Register         2.Login*****\n");
 printf("*****3.Reback           0.exit *****\n");
 printf("************************************\n");
 printf("************************************\n");
}

int main()
{
 char input;
 do
 {
  menu();
  setbuf(stdin, NULL); // Clear the input buffer to avoid getchar reading leftover input
  input = getchar();
  switch (input)
  {
  case '1':
   Register();
   break;
  case '2':
   Login();
   break;
  case '3':
   Reback();
   break;
  case '0':
   printf("Exit successful!\n");
   break;
  default:
   printf("Invalid selection, please try again!\n");
   break;
  }
 } while (input != '0'); // If the input is 0, exit
}

This uses a character as the switch case condition because if an integer is used and something other than an integer is entered, the switch will get stuck in a loop. You can test this yourself; I won’t elaborate much here. Using a single character for judgment has not produced any bugs so far.

3. Registration System

void Register()
{
 Users a, b; // Create temporary user structure variables, a is used to receive user input, b is used to read from the file for comparison

 char tmp[20] = ""; // Used for the following judgment

 printf("Welcome to the registration interface!\n");
 FILE* pf = fopen("users.dat", "rb"); // "rb" means open the file in binary read-only mode
 fread(&b, sizeof(Users), 1, pf); // Read data into b
 if (!pf) // If opening fails
 {
  printf("%s", strerror(errno)); // errno can be understood as the error number corresponding to the error, strerror can translate this number and output it to the screen
  return;
 }
 Sleep(800);

 printf("Please enter your account >>");
 scanf("%s", a.id);
 while (1)
 {
  if (strcmp(a.id, b.id)) // Two usernames are not equal
  {
   if (!feof(pf)) // Not reached the end of the file
   {
    fread(&b, sizeof(Users), 1, pf); // Continue reading users from the file into b
   }
   else // Reached the end of the file, confirm no duplicate id
   {
    break;
   }
  }
  else // Two usernames are equal
  {
   printf("This username already exists, please re-enter!\n");
   Sleep(1000);
   fclose(pf); // Close the file
   pf = NULL; // Set pf to NULL to avoid dangling pointers
   return;
  }
 }
 printf("Please enter your name >>");
 scanf("%s", a.name);
 printf("Please enter your gender >>");
 scanf("%s", a.sex);
 printf("Please enter your phone number >>");
 scanf("%s", a.phone);
 printf("Please enter your password >>");
 Getpwd(a.pwd); // Function to input password, with masking feature, will be introduced below
 printf("\nPlease confirm your password again >>");
 Getpwd(tmp);
 do
 {
  if (!strcmp(a.pwd, tmp)) // Two passwords are equal
  {
   pf = fopen("users.dat", "ab");
   fwrite(&a, sizeof(Users), 1, pf);
   printf("\nAccount registration successful, please log in!\n");
   Sleep(500);
   fclose(pf);
   pf = NULL;
   return;
  }
  else
  {
   printf("\nThe two passwords do not match! Please re-enter >>");
   Getpwd(a.pwd);
   printf("\nPlease confirm again >>");
   Getpwd(tmp);
  }
 } while (1);
}

Files are opened and written in binary for no other reason than it looks cool!

Follow the public account: C Language Chinese Community, get 300G of programming materials for free.

4. Login System

void Login()
{
 Users a, b; // Similarly, a is used for user input, b is used to read from the file for comparison

 FILE* pf = fopen("users.dat", "rb"); // Open the file in read-only mode
 if (!pf) // If reading fails
 {
  printf("%s\n", strerror(errno)); // Explained above
  return;
 }
 printf("Welcome to the login interface!\n");
 Sleep(1000);

 fread(&b, sizeof(Users), 1, pf); // First read a user from the file to test

 printf("Please enter your account >>");
 scanf("%s", a.id);

 while (1)
 {
  if (!strcmp(a.id, b.id)) // Found a matching id in the file
  {
   break;
  }
  else
  {
   if (!feof(pf)) // Not reached the end of the file, continue reading ids into b
   {
    fread(&b, sizeof(Users), 1, pf); // Continue reading user information into b until a matching one is found
   }
   else // Reached the end of the file, no matching account found
   {
    printf("This account does not exist! Please re-enter!\n");
    Sleep(500);
    fclose(pf);
    pf = NULL;
    return;
   }
  }
 }
 do
 {
  printf("Please enter your password >>");
  Getpwd(a.pwd); // Get password, will be discussed below
  if (!strcmp(a.pwd, b.pwd)) // Input password matches the one in the file
  {
   printf("\nLogin successful! Welcome to use!\n");
   Sleep(500);
   fclose(pf); // Of course, close the file after use
   pf = NULL; // Set to NULL to avoid dangling pointers
   return;
  }
  else
  {
   printf("\nPassword input error, please re-enter\n");
  }
 } while (strcmp(a.pwd, b.pwd));
}

The general idea is that the user first enters the account (id), then b reads the user from the file until it finds one that matches the user input id, and then checks whether the input password is correct. The library function strcmp is used to determine if the strings are the same; if they are, it returns 0, otherwise it returns a non-zero value.

5. Password Recovery (Change Password)

void Reback()
{
 char tmp[20] = ""; // Used for password matching
 Users a, b;

 FILE* pf = fopen("users.dat", "rb+"); // "rb+" is to open the file for reading and writing in binary

 if (!pf) // As usual, first check if it can be opened successfully
 {
  printf("%s", strerror(errno));
  return;
 }

 fread(&b, sizeof(Users), 1, pf); // Similarly, read one to test

 printf("Please enter your account >>");
 Sleep(800);

 scanf("%s", a.id);

 while (1) // Find a matching id in the file
 {
  if (!strcmp(a.id, b.id)) // If found a matching id
  {
   break;
  }
  else
  {
   if (!feof(pf)) // Not reached the end, continue reading
   {
    fread(&b, sizeof(Users), 1, pf);
   }
   else
   {
    printf("The account you entered does not exist! Please re-enter!\n");
    Sleep(500);
    fclose(pf);
    pf = NULL;
    break;
   }
  }
 }

 // Information matching verification
 do // Matching name
 {
  printf("Please enter your name >>");
  scanf("%s", a.name);
  if (!strcmp(a.name, b.name))
  {
   break;
  }
  else
  {
   printf("Input error, please re-enter!\n");
  }
 } while (strcmp(a.name, b.name));

 do // Matching gender
 {
  printf("Please enter your gender >>");
  scanf("%s", a.sex);
  if (!strcmp(a.sex, b.sex))
  {
   break;
  }
  else
  {
   printf("Input error, please re-enter!\n");
  }
 } while (strcmp(a.sex, b.sex));
 do // Matching phone number
 {
  printf("Please enter your phone number >>");
  scanf("%s", a.phone);
  if (!strcmp(a.phone, b.phone))
  {
   break;
  }
  else
  {
   printf("Input error, please re-enter!\n");
  }
 } while (strcmp(a.phone, b.phone));

 // Change password
 printf("Verification successful! Please modify your password!\n");
 printf("Please enter your password >>");
 Getpwd(a.id);
 printf("Please confirm your password again >>");
 Getpwd(tmp);
 if (!pf)
 {
  printf("%s", strerror(errno));
  return;
 }
 // Overwrite the original password
 do
 {
  if (!strcmp(a.pwd, tmp)) // Two passwords are equal
  {
   fseek(pf, -((int)(sizeof(Users) - MAX_ID)), SEEK_CUR); // Move the file stream back to the position to modify the password
   fprintf(pf, "%s", a.pwd); // Overwrite the original password
   printf("Password modified successfully, please log in!\n");
   Sleep(500);
   fclose(pf);
   pf = NULL;
   return;
  }
  else
  {
   printf("The two passwords do not match! Please re-enter >>");
   scanf("%s", a.pwd);
   printf("Please confirm again >>");
   scanf("%s", tmp);
  }
 } while (1);
}

The general idea is to input the account -> match information -> modify the password. When modifying the password, the file stream must be moved back to the position to modify the password; fseek is used here, and -((int)(sizeof(Users) – MAX_ID)) is the range to move back.

6. Password Input & Masking

void gotoxy(int x, int y)
{
 // Update cursor position
 COORD pos;
 HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); // GetStdHandle is a Windows API function.
 pos.X = x;
 pos.Y = y;
 SetConsoleCursorPosition(hOutput, pos);
}

int posx()
{
 CONSOLE_SCREEN_BUFFER_INFO ptr;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr);
 return (ptr.dwCursorPosition.X);
}

int posy()
{
 CONSOLE_SCREEN_BUFFER_INFO ptr;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr);
 return (ptr.dwCursorPosition.Y);
}

void Getpwd(char* pwd)
{
 int i = 0;
 int x, y;
 while (1)
 {
  pwd[i] = getch(); // Get a single password character
  if (pwd[i] == VK_BACK && i >= 0) // If the input is the backspace key, VK_BACK is the key value of the keyboard, ASCII code is 8
  {
   if (i > 0) // i>0 means something has been input, then backtrack one space
   {
    i--;
    x = posx() - 1; // Locate x and backtrack one space
    y = posy(); // Locate y
    gotoxy(x, y); // Set cursor position
    printf(" "); // Cover * with a space
    x = posx() - 1; // Backtrack again, so the cursor will display in the correct position next time
    y = posy(); // Locate y
    gotoxy(x, y);
    continue; // Then skip this loop
   }
   else if (i == 0) // i==0 means nothing has been input, directly skip this loop
   {
    continue;
   }
  }
  if (i >= 0 && pwd[i] != VK_RETURN && pwd[i] != VK_BACK) // Something has been input
  {
   x = posx();
   y = posy();
   gotoxy(x, y);
   printf("*");
  }
  if (i == 0 && pwd[i] == VK_RETURN) // If nothing has been input and enter is pressed, directly skip this loop to avoid treating enter as a password
  {
   continue;
  }
  if (pwd[i] == VK_RETURN || i == MAX_PWD - 2) // If enter is pressed or the limit is reached
  {
   i++;
   pwd[i] = '\0'; // Place '\0' at the end
   break;
  }
  i++;
 }
}

Those long functions are Windows console API functions, and I won’t elaborate on them here.

7. Complete Code!!!!

// Include header files
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <windows.h>

// Define macro constants
#define MAX_ID 11
#define MAX_PWD 20
#define MAX_NAME 15
#define MAX_SEX 5
#define MAX_PHONE 12

// Create user structure
typedef struct Users
{
 char id[MAX_ID];
 char pwd[MAX_PWD];
 char name[MAX_NAME];
 char sex[MAX_SEX];
 char phone[MAX_PHONE];
} Users;

// Declare functions

// Print menu
void menu();

// User registration
void Register();

// Login
void Login();

// Password recovery
void Reback();

// Set cursor position
void gotoxy();

// Get x position
int posx();

// Get y position
int posy();

// Password input (with masking feature)
void Getpwd(char* pwd);

int main() // Main function
{
 char input;
 do
 {
  menu();
  setbuf(stdin, NULL);
  input = getchar();
  switch (input)
  {
  case '1':
   Register();
   break;
  case '2':
   Login();
   break;
  case '3':
   Reback();
   break;
  case '0':
   printf("Exit successful!\n");
   break;
  default:
   printf("Invalid selection, please try again!\n");
   break;
  }
 } while (input != '0');
}

// Print menu
void menu()
{
 printf("************************************\n");
 printf("************************************\n");
 printf("*****1.Register         2.Login*****\n");
 printf("*****3.Reback           0.exit *****\n");
 printf("************************************\n");
 printf("************************************\n");
}

// Registration system
void Register()
{
 Users a, b; // Create temporary user structure variables, a is used to receive user input, b is used to read from the file for comparison

 char tmp[20] = ""; // Used for the following judgment

 printf("Welcome to the registration interface!\n");
 FILE* pf = fopen("users.dat", "rb"); // "rb" means open the file in binary read-only mode
 fread(&b, sizeof(Users), 1, pf); // Read data into b
 if (!pf) // If opening fails
 {
  printf("%s", strerror(errno)); // errno can be understood as the error number corresponding to the error, strerror can translate this number and output it to the screen
  return;
 }
 Sleep(800);

 printf("Please enter your account >>");
 scanf("%s", a.id);
 while (1)
 {
  if (strcmp(a.id, b.id)) // Two usernames are not equal
  {
   if (!feof(pf)) // Not reached the end of the file
   {
    fread(&b, sizeof(Users), 1, pf); // Continue reading users from the file into b
   }
   else // Reached the end of the file, confirm no duplicate id
   {
    break;
   }
  }
  else // Two usernames are equal
  {
   printf("This username already exists, please re-enter!\n");
   Sleep(1000);
   fclose(pf); // Close the file
   pf = NULL; // Set pf to NULL to avoid dangling pointers
   return;
  }
 }
 printf("Please enter your name >>");
 scanf("%s", a.name);
 printf("Please enter your gender >>");
 scanf("%s", a.sex);
 printf("Please enter your phone number >>");
 scanf("%s", a.phone);
 printf("Please enter your password >>");
 Getpwd(a.pwd); // Function to input password, with masking feature, will be introduced below
 printf("\nPlease confirm your password again >>");
 Getpwd(tmp);
 do
 {
  if (!strcmp(a.pwd, tmp)) // Two passwords are equal
  {
   pf = fopen("users.dat", "ab");
   fwrite(&a, sizeof(Users), 1, pf);
   printf("\nAccount registration successful, please log in!\n");
   Sleep(500);
   fclose(pf);
   pf = NULL;
   return;
  }
  else
  {
   printf("\nThe two passwords do not match! Please re-enter >>");
   Getpwd(a.pwd);
   printf("\nPlease confirm again >>");
   Getpwd(tmp);
  }
 } while (1);
}

// Login system
void Login()
{
 Users a, b; // Similarly, a is used for user input, b is used to read from the file for comparison

 FILE* pf = fopen("users.dat", "rb"); // Open the file in read-only mode
 if (!pf) // If reading fails
 {
  printf("%s\n", strerror(errno)); // Explained above
  return;
 }
 printf("Welcome to the login interface!\n");
 Sleep(1000);

 fread(&b, sizeof(Users), 1, pf); // First read a user from the file to test

 printf("Please enter your account >>");
 scanf("%s", a.id);

 while (1)
 {
  if (!strcmp(a.id, b.id)) // Found a matching id in the file
  {
   break;
  }
  else
  {
   if (!feof(pf)) // Not reached the end of the file, continue reading ids into b
   {
    fread(&b, sizeof(Users), 1, pf); // Continue reading user information into b until a matching one is found
   }
   else // Reached the end of the file, no matching account found
   {
    printf("This account does not exist! Please re-enter!\n");
    Sleep(500);
    fclose(pf);
    pf = NULL;
    return;
   }
  }
 }
 do
 {
  printf("Please enter your password >>");
  Getpwd(a.pwd); // Get password, will be discussed below
  if (!strcmp(a.pwd, b.pwd)) // Input password matches the one in the file
  {
   printf("\nLogin successful! Welcome to use!\n");
   Sleep(500);
   fclose(pf); // Of course, close the file after use
   pf = NULL; // Set to NULL to avoid dangling pointers
   return;
  }
  else
  {
   printf("\nPassword input error, please re-enter\n");
  }
 } while (strcmp(a.pwd, b.pwd));
}

// Password recovery
void Reback()
{
 char tmp[20] = ""; // Used for password matching
 Users a, b;

 FILE* pf = fopen("users.dat", "rb+"); // "rb+" is to open the file for reading and writing in binary

 if (!pf) // As usual, first check if it can be opened successfully
 {
  printf("%s", strerror(errno));
  return;
 }

 fread(&b, sizeof(Users), 1, pf); // Similarly, read one to test

 printf("Please enter your account >>");
 Sleep(800);

 scanf("%s", a.id);

 while (1) // Find a matching id in the file
 {
  if (!strcmp(a.id, b.id)) // If found a matching id
  {
   break;
  }
  else
  {
   if (!feof(pf)) // Not reached the end, continue reading
   {
    fread(&b, sizeof(Users), 1, pf);
   }
   else
   {
    printf("The account you entered does not exist! Please re-enter!\n");
    Sleep(500);
    fclose(pf);
    pf = NULL;
    break;
   }
  }
 }

 // Information matching verification
 do // Matching name
 {
  printf("Please enter your name >>");
  scanf("%s", a.name);
  if (!strcmp(a.name, b.name))
  {
   break;
  }
  else
  {
   printf("Input error, please re-enter!\n");
  }
 } while (strcmp(a.name, b.name));

 do // Matching gender
 {
  printf("Please enter your gender >>");
  scanf("%s", a.sex);
  if (!strcmp(a.sex, b.sex))
  {
   break;
  }
  else
  {
   printf("Input error, please re-enter!\n");
  }
 } while (strcmp(a.sex, b.sex));
 do // Matching phone number
 {
  printf("Please enter your phone number >>");
  scanf("%s", a.phone);
  if (!strcmp(a.phone, b.phone))
  {
   break;
  }
  else
  {
   printf("Input error, please re-enter!\n");
  }
 } while (strcmp(a.phone, b.phone));

 // Change password
 printf("Verification successful! Please modify your password!\n");
 printf("Please enter your password >>");
 Getpwd(a.id);
 printf("Please confirm your password again >>");
 Getpwd(tmp);
 if (!pf)
 {
  printf("%s", strerror(errno));
  return;
 }
 // Overwrite the original password
 do
 {
  if (!strcmp(a.pwd, tmp)) // Two passwords are equal
  {
   fseek(pf, -((int)(sizeof(Users) - MAX_ID)), SEEK_CUR); // Move the file stream back to the position to modify the password
   fprintf(pf, "%s", a.pwd); // Overwrite the original password
   printf("Password modified successfully, please log in!\n");
   Sleep(500);
   fclose(pf);
   pf = NULL;
   return;
  }
  else
  {
   printf("The two passwords do not match! Please re-enter >>");
   scanf("%s", a.pwd);
   printf("Please confirm again >>");
   scanf("%s", tmp);
  }
 } while (1);
}

// Set cursor position
void gotoxy(int x, int y)
{
 // Update cursor position
 COORD pos;
 HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); // GetStdHandle is a Windows API function.
 pos.X = x;
 pos.Y = y;
 SetConsoleCursorPosition(hOutput, pos);
}
// Get cursor x coordinate
int posx()
{
 CONSOLE_SCREEN_BUFFER_INFO ptr;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr);
 return (ptr.dwCursorPosition.X);
}
// Get cursor y coordinate
int posy()
{
 CONSOLE_SCREEN_BUFFER_INFO ptr;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr);
 return (ptr.dwCursorPosition.Y);
}
// Input password
void Getpwd(char* pwd)
{
 int i = 0;
 int x, y;
 while (1)
 {
  pwd[i] = getch(); // Get a single password character
  if (pwd[i] == VK_BACK && i >= 0) // If the input is the backspace key, VK_BACK is the key value of the keyboard, ASCII code is 8
  {
   if (i > 0) // i>0 means something has been input, then backtrack one space
   {
    i--;
    x = posx() - 1; // Locate x and backtrack one space
    y = posy(); // Locate y
    gotoxy(x, y); // Set cursor position
    printf(" "); // Cover * with a space
    x = posx() - 1; // Backtrack again, so the cursor will display in the correct position next time
    y = posy(); // Locate y
    gotoxy(x, y);
    continue; // Then skip this loop
   }
   else if (i == 0) // i==0 means nothing has been input, directly skip this loop
   {
    continue;
   }
  }
  if (i >= 0 && pwd[i] != VK_RETURN && pwd[i] != VK_BACK) // Something has been input
  {
   x = posx();
   y = posy();
   gotoxy(x, y);
   printf("*");
  }
  if (i == 0 && pwd[i] == VK_RETURN) // If nothing has been input and enter is pressed, directly skip this loop to avoid treating enter as a password
  {
   continue;
  }
  if (pwd[i] == VK_RETURN || i == MAX_PWD - 2) // If enter is pressed or the limit is reached
  {
   i++;
   pwd[i] = '\0'; // Place '\0' at the end
   break;
  }
  i++;
 }
}
The simulated running result after compilation is shown in the image below:

C Language File-Writable Account Password Login System

From Information Technology People Information Technology People Public Account

Leave a Comment