程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言實現輸入密碼顯示星號 實現教程

C語言實現輸入密碼顯示星號 實現教程

編輯:關於C語言
 

眾所周知,一個良好的密碼輸入程序是在用戶輸入密碼時不顯示密碼本身,只回顯星號。或者,在安全性要求更高的某些程序中,什麼都不顯示。那麼,在C語言中如何實現它呢?

       getc()和getchar()函數想必大家都經常用到,但它們都在輸入的同時顯示輸入內容,並由回車終止輸入。為了不顯示輸入內容,我們調用另外一個函數getch(),它包含在<conio.h>頭文件中。該函數可以在輸入的同時不顯示輸入內容,並在輸入完成後不需回車而自動終止輸入。與此同時,該頭文件中還包含另外一個函數getche(),它和getch()功能相同,唯一的區別是輸入的同時顯示輸入的內容。

 

//先來看一個網上出現最多的版本,這個函數有哪些不合理的地方?怎麼改進?

#include <stdio.h>
#include <conio.h>

char passwd[64]="";
void getPasswd(const char *prompt)
{
    char c;

    int i = 0;
    puts(prompt);
    while ((c=getch()) != '\r')
    {
        passwd[i++] = c;
        putchar('*');
    }
    passwd[i] = '\0';

     printf("\n");
}

 

//下面是我改進的版本,還有哪些不足的地方,請大家指出,謝謝了!

//原型:char *getPasswd(const char *prompt);

//功能:提示用戶輸入密碼,並將密碼保存在static char[]裡

 

 

//參數:const char* prompt 提示字符串

 

//返回:返回以null結尾的密碼字符串指針(函數內的static char [])

//注意:如果密碼要留著用的話,要用strcpy保存起來,否則再次調用getPasswd()時,static char[]會被新的密碼覆蓋

//該函數調用了getch(),而UNIX下似乎不支持此函數,文章後面給出了替代方案。。。

 

#include<stdio.h>
#include<string.h>
#include<conio.h>
#define MAX_LEN   8
#define BACKSPACE 8
#define ENTER     13
#define ALARM     7

char *getPasswd(const char *prompt)
{
    int i=0, ch;
    static char p[MAX_LEN+1]="";
    printf("%s", prompt);
    while((ch = getch())!= -1 && ch != ENTER)
    {
         if(i == MAX_LEN && ch != BACKSPACE)
         {
              putchar(ALARM);
              continue;
         }
         if(ch == BACKSPACE)
         {
             if(i==0)
              {
                  putchar(ALARM);
                  continue;
              }
              i--;
              putchar(BACKSPACE);
              putchar(' ');
              putchar(BACKSPACE);
         }
         else
         {
             p[i] = ch;
             putchar('*');
             i++;
         }
    }

    if(ch == -1)
    {
        while(i != -1)
        {
            p[i--] = '\0';
        }
        return NULL;
    }
    p[i]='\0';
    printf("\n");
    return p;
}

//可惜上面的版本在我的Linux虛擬機上跑不起來,說不認識conio.h,沒招,繼續探索...

//於是找到了下面的版本...

getch()是conio.h中提供的,標准C裡面沒有。

如果需要在Linux和VC裡面同時編譯,用到getch()的地方就這麼處理:

#ifndef _WIN32                 //Linux platform
#include <termio.h>
#define getch() get_char(0) //without stdout
#define getche() get_char(1) //with stdout
#else                         //WIN32 platform
#include <conio.h>
#endif

#ifndef _WIN32               //Linux platform

/************************************************************************

* author:hzcpig
* method name: get_char
* input: 0--getch() 1--getche()
* return: char
* remark: Linux simulative gech(),getche()
            Instead of "conio.h" using in VC6.0 environment
************************************************************************/
char get_char(int flag)
{
char ch;
struct termios new_settings;
struct termios stored_settings;
tcgetattr(0, &stored_settings);
new_settings = stored_settings;
new_settings.c_lflag &= (~ICANON);
new_settings.c_cc[VTIME] = 0;

tcgetattr(0, &stored_settings);
new_settings.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &new_settings);

if (flag == 1) //getche()
{
ch = getchar();
}
else            //getch()
{
system("stty -echo ");
ch = getchar();
system("stty echo ");

tcsetattr (0, TCSANOW, &stored_settings);
}

return ch;
}
#endif

//可惜我編排了半天的格式,最後一運行,發現上面的版本在我的機子上跑起來停不下來,沒招,繼續探索

//下面這個版本跑不起來,不過似乎是高手寫的,所以留著,以後看得懂了再看看為什麼跑不起來,繼續。。。

#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>


int getch()
{
     char ch;
     struct termios save, ne;
     ioctl(0, TCGETS, &save);
     ioctl(0, TCGETS, &ne);
     ne.c_lflag &= ~(ECHO | ICANON);
     ioctl(0, TCSETS, &ne);
     read(0, &ch, 1);
     ioctl(0, TCSETS, &save);
    return ch;
}

//終於讓我找到一個可以替代的,不過還是看不懂,而且只是經過簡單的測試。。。

#include <stdio.h>
#include <termio.h>

int getch(void)
{
        struct termios tm, tm_old;
        int fd = STDIN_FILENO, c;
        if(tcgetattr(fd, &tm) < 0)
                return -1;
        tm_old = tm;
        cfmakeraw(&tm);
        if(tcsetattr(fd, TCSANOW, &tm) < 0)
                return -1;
        c = fgetc(stdin);
        if(tcsetattr(fd, TCSANOW, &tm_old) < 0)
                return -1;
        return c;
}

//於是完整的在linux和windows下通用的版本出來了......

#include <stdio.h>

#ifndef _WIN32                   //Linux platform
#include <termio.h>
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif

int getch(void)
{
        struct termios tm, tm_old;
        int fd = STDIN_FILENO, c;
        if(tcgetattr(fd, &tm) < 0)
                return -1;
        tm_old = tm;
        cfmakeraw(&tm);
        if(tcsetattr(fd, TCSANOW, &tm) < 0)
                return -1;
        c = fgetc(stdin);
        if(tcsetattr(fd, TCSANOW, &tm_old) < 0)
                return -1;
        return c;
}

 

#else                            //WIN32 platform
#include <conio.h>
#endif


#define MAX_LEN   8
#define BACKSPACE 8
#define ENTER     13
#define ALARM     7

char *getPasswd(const char *prompt)
{
    int i=0, ch;
    static char p[MAX_LEN+1]="";
    printf("%s", prompt);
    while((ch = getch())!= -1 && ch != ENTER)
    {
         if(i == MAX_LEN && ch != BACKSPACE)
         {
              putchar(ALARM);
              continue;
         }
         if(ch == BACKSPACE)
         {
             if(i==0)
              {
                  putchar(ALARM);
                  continue;
              }
              i--;
              putchar(BACKSPACE);
              putchar(' ');
              putchar(BACKSPACE);
         }
         else
         {
             p[i] = ch;
             putchar('*');
             i++;
         }
    }

    if(ch == -1)
    {
        while(i != -1)
        {
            p[i--] = '\0';
        }
        return NULL;
    }
    p[i]='\0';
    printf("\n");
    return p;
}


int main()
{
    char *pw = getPasswd("passwd:");
    puts(pw);
    puts("clearing the static buffer with 0 ...");
    while(*pw)
    {
        *pw++=0;
    }
    pw=NULL;

    return 0;
}

 

//其實在UNIX下有一個函數,直接就是用來輸入密碼用的,我們每次登陸的時候都在調用。。。

//但手冊上說該函數已經被遺棄,不過UNIX環境高級編程給出了他的一個實現,未完待續。。。

//如果需要對密碼加密,可以查一下crypt函數的用法

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved