[原创] 编写帐号的输入的函数

作者在 2007-12-16 09:46:55 发布以下内容

[原创+分享]  编写帐号的输入的函数

    我想大家对帐号和密码的输入都知道是怎么回事吧```不知道话```那么就请点击桌面上的那个企鹅```然后回有QQ号码和密码``
以后面的两个空白行``你点进去按一按键盘``就更感觉到什么是输入帐号和密码了```

    在开始讲这个函数的编写的时候```我要先说清楚一点````因为我要在这个函数里使用getch()函数``而这个函数是被包括
在conio.h这个头件里的``所以我不得不使用conio.h这个头文件``要知道这个头文件并 !!不是标准库!! 里的头文件```
也就是说``getch()``不是 !!标准库函数!! 所以有些编译器可能没有这个头文件``那就没有办法运行我编写的函数``但是应该大
所数都支持吧```我的编译器是g++``Dev-CPP\bin\g++.exe```
             命令行编译是 当前路径\Dev-CPP\bin\g++ -c 函数文件路径\函数文件名.c
    比如我的: D:\Dev-cpp\bin\g++ -c d:\c\chickid.c 然后回车
如果编译没问题``就什么都不显示``直接换行``然后你到bin下``回发现子一个chick.o也就是目标文件``编译后等待连接的文件

    现在开始进入正题```

    要实现这个功能```那么我们先要做什么呢```其实也就是实现2个功能: 帐号和密码的输入.

    我是这样编写筐架的:

    #include <stdio.h>   /*  输入输出  */
    #include <conio.h>   /*  要用到getch()函数  */
    #include <string.h>  /*  字符串的比较  */

    #define IWLEN 31     /*  帐号和密码允许的最大长度  */

    static char PASSID[IWLEN];       //  静态的外部字符组``一个存放ID``一个存放密码声明为静态``是因为这2个数组``只
    static char PASSWORD[IWLEN] ;    //  有我下面的函数声明为静态``是因为这2个数组``只有我下面的函数回用到``对其他文
                                          //  件里是不可见的``用stack可以将其相对其他文件隐藏起来
    void getid(void)   ;    //  相关
    void getword(void) ;    //  声
    void chick(void)   ;    //  明

     void chickid(void)
    {
         getid() ;     /*  负责读取I D  */
         getword() ;     /*  负责读取密码  */
         chick() ;     /*  负责核对帐号  */

         return  ;     /*  返回撒,大家都晓得勒  */
    }
    void getid(void){return;}
    void getword(void){return;}
    void chick(void){return;}

    编译一下````没问题````main里调用```也没问题``

    好了```主体函数编写好了``现在开始写其他的几个函数吧```

    第一个函数 :  读去我们的输入的ID``普通思路和我想的应该没什么区别 :

    void getid(void)
    {
         printf ("                           I N T O    P A S S I D\n");
         printf ("                           ");

         short id = 0 ;  /*  统计帐号的字符和表示其位置  */
         char c ;        /*  一个个字符的读取 */
         /*  为什么不用gets(*p)或scanf("%s",&变量或指向字符数组的指针)读取字符串``
          *  我是为了方便在读去完字符流后加上'\0'
          */
         while ( id<IWLEN && ( c=getchar() ) != '\n' && c != EOF )  /*  先查字符读够没再看输入的情况 */
         {
               *(passid+id++) = c ;
         }
         *(passid+id) = '\0' ;     /*   这是字符数组``不是字符串``别忘了最后加上一个'\0'  */
     
         return ;
    }   

   编译一下```没问题```main里调用```也没问题``

   第一个函数 :  读去我们的输入的PASSWORD````你是这样想的吗?``我是的``我的调试经历很漫长的``:

   void getword(void)
   {
        printf ("                           I N T O    P A S S W O R D\n");
        printf ("                           ");
           
        short word = 0 ;
        char c ;
     
        while ( ( c=getch() ) != '\n' && c != EOF && word<IWLEN )
        {
              *(password+word++) = c ;
              putchar('*');
       }
        *(password+word) = '\0' ;
     
       return ;
   }
   要恭喜我的是:  编译一下````没问题```
   为我感到悲伤的是``mian里运行```当回按回车时吃惊!!!``再试着ctrl+z```继续吃惊!!!``快按退格键``哇!!!!有没有搞错```
   我再试着按方向键(有时候感觉前面某个字符按错``回按'←')````按吧```这个惊更大```!!!

   编译没错是好的```说明相关语法知识过关了```犯的是逻辑错误```
   总结一下``程序运行不正常的想象:

   1: 回车没有用``按一下冒出一个*
   2: EOF输入```还是冒出一个*
   3: 退格键``还是冒出一个*
   4: 方向键```一下冒出2个*

   出现问题就要解决```一个一个来吧```
   第一个问题:  为什么按回车``回冒个*呢``
   分析:  查看程序可以知道``只有循环成立才回冒*``也就是说``我输入的回车时``
         c=getch() != '\n'成立
         c != EOF 成立
           word<IWLEN 成立
         冒出的*不超出30个``那么后面2个成立很容里理解的``word<=30继续``回车键又不是EOF继续``
        那么现在问题很明显了```getch()我们输入的回车``是不等于'\n'的```很奇怪啊``为什么不是呢``如果不是
         那又应该是多少呢```于是``一个测试main诞生了``
        int main(void)
        {
            char c = getch();
            printf("%c %d\n", c, c);
            getchar();
            return 0 ;
        }
        输出为: 空格13换行
        思考: 我希望看到的应该是: 一个字符 空格 一个整型值
                            结果是: 字符没了 空格 一个整型值
               没了是什么意思呢```就像是第一个位置什么也不输出``然后输出后面的空格和该字符的值``值是13``空字符应该是
               0吧```那么它回不有和空字符一样的效果呢?``于是变了一下输出语句:

             printf("1111%c2222 %d\n", c, c);
             理想输出为: 11112222空格13换行            
             实际输出是: 2222空格13换行

             说明getch()的回车``没有空字符的效果``那又怎么理解呢```想了下``产生了这样的想法: 这个回车回不回是把该字符
               前面所以的字符连同它自己清空``也就是忽略不挤了呢``然后只输出这个回车的后面呢?再改输出:

             printf("1111%c%d\n", c, c);
             理想输出为: 13换行            
             实际输出是: 1311换行
      
             说明字符13没有清空效果```但是前面2个11``被后面的c的值覆盖了```难道``字符13的功能是把它后面的字符串依次
               覆盖到最前面(转义字符除外)`覆盖完了``还有字符就继续输出???`结合前面的两个程序``的确有这样的现象啊```继改:
         
             printf("1111%c\n", c, c);

             理想输出为: 1111换行            
             实际输出是: 1111换行

               恩```比较满意``但是我还有一种情况没有试```那就是字符13后面什么字符也没有(包括转义字符)````:

             printf("1111%c\n", c, c);
             理想输出为: 1111不换行            
               实际输出是: 1111不换行......但是``````光标跑到第一个字符那里去了```
            
             我汗啊``第一次见到这样的事情```我怕啊````怕是怕``结合最后一个测试和上面几个测试``想了几分钟``我有了新想
               法: getch()读取的回车``的确不是我们常说的'\n'```而是一个值为13的字符``其输出表现为``将光标移动到当前行
               的最前面``很像编辑时的HOME键的作用```我们输出的内容是要先找到位置再输出的```这个窗口输出的位置就是光标所
               在的位置``既然光标帮到最前面了``那么那么原来输出格式里的字符13后面的字符序列``都回在现在光标所在的位置输出
               如果当前光标处有字符(不管是可打印可显示的内容还是不可的)```这些字符都回被后面要输出的内容被覆盖掉``直到把所
               有内容输出为止!!!

             测试:
             printf("1aaa%cABCDEFGH%c%d", c, c, c );
             理想输出为: 13GH光标在G的位置闪动
               实际输出是: 13CDEFGH光标在C的位置晃啊晃的``晃得我头晕``

             有不明白的就是要思考``调试就是那么难``不明白哇```几分钟后```新想法是:  输出前``格式字符串里
               回先把输出格式处理好怎么处理的呢??``它的处理方向是: 从屁股开始往脑袋```处理方式是: 从屁股开始找``找第一个
               字符13然后把它后面的所以字符串``依次覆盖``在它和它前面最进的字符13之间的字符串``接下来继续往前覆盖......
             如果前面没有字符13了``也就找到头了``直接覆盖它前面的字符串吧```
              
             printf("1aaa%cABCDEFGH%c%d9999%c%d%c7", c, c, c, c, c, c );  
               理想输出为: 739999GH光标在G的位置闪动
               实际输出是: 739999GH光标在3的位置闪动
  
               看来我要补充一点了``那就是光标停留位置的问题``它应该是停留在最屁股后面的字符串的后面``测试:

             printf("%c%d9999%c%d%c7", c, c, c, c, c, c );   
             printf("%c%d9999%c%d%c77", c, c, c, c, c, c );
             printf("%c%d9999%c%d%c777", c, c, c, c, c, c );
             printf("%c%d9999555%c%d%c7777", c, c, c, c, c, c );
             理想输出为: 739999GH光标在3的位置闪动
                           779999GH光标在最左边的9的位置闪动
                           777999GH光标在最左边的9的位置闪动  
                       777799555GH光标在最左边的9的位置闪动
             实际输出是:
                       739999GH光标在3的位置闪动
                           779999GH光标在最左边的9的位置闪动
                           777999GH光标在最左边的9的位置闪动  
                           777799555GH光标在最左边的9的位置闪动  

             结果验证成功````
             现在做一下总结:
             在用getch()获取回车键时``得到的是一个```字符值为13(没有益出的可能``我用long试过)的字符````这是一个不可
               见的字符``它的工作方式是: 单独输出``就将光标移到当前行的最前面,如果这个时候有内容输出,那么输出的内容将回
               把光标所在的位置的内容覆盖掉,然后光标移动到该内容的后面并紧靠该内容;  在格式字符串中使用时````printf语句
               回先检查``格式字符串``从末尾向最前依次检查``遇到第一个字符13就用该字符13以后的所以内容`去覆盖`它前面的离它
               最近的字符13到该字符13之间的所有内容``(如果前面没有字符13``就直接覆盖该字符13前面的所以内容)``覆盖了以后
               继续往前找字符13``找到最进的之后``重复以上操作``直到前面没有字符13``处理完后``光标的位置``位于格式字符串
               的最后一个字符13后面的字符串后面并紧靠这个字符串``上面的很多测试程序已经说明了.

    我开始不知道这个字符13是什么``然后去找ASCII表``结果是个看不懂的字符``问论坛``论坛里有朋友说``这个13其实就是一个转义
字符 ' \r ' ``这个转义字符``我只能说我见过它``然后我又回去翻书```结果还是那样``只知道它一个换行的意思``其他不知道更不明
白它和' \n '之间的区别```现在总算是明白了`虽然很累但是很舒服```

   现在已经知道为什么"为什么按回车``回冒个*了``"那么改程序也方便了``
   while ( ( c=getch() ) != '\n' && c != EOF && word<IWLEN ) 改为
   while ( ( c=getch() ) != '\r' /* '\r'或13 */ && c != EOF && word<IWLEN )
   调试通过``运行也通过```说明``只要用户在输入密码时能一次就输入成功``不回按退格键和左右移动键``
   这个函数就是没问题的```      

   现在开始处理第2个问题``有了第一个问题的分析模式``下面的就简单了``

             printf("%c %d", c, c ) ;
             理想输出为: 不知道
               实际输出是: →空格26

             什么什么问题呢```windows下ctrl+z是EOF``但这不是对getch()而言的``对它而言 ctrl+z 的值是26``也就是
               ASCII字符→的值``这个好改了``而且还尝试输入了ESC键``你知道得到的结果是什么吗``是: ←空格27``也就是说
               ESC键对getch()来说就是ASCII←的字符值``现在可以得到2个方式退出了

              while ( ( c=getch() ) != '\r' && c != EOF && word<IWLEN )
            改:
            while ( ( c=getch() ) != '\r' &&  c != 26 && c != 27  && word<IWLEN )

            调试运行成功```

   现在开始处理第3个问题``

            加上一句
            printf("%c %d", '\b', 'b' ) ;
            理想输出为: 空格按了退格键后的值 (不知道是多少)
                       空格'\b'的值(不知道是多少)
              实际输出是: 空格8
                       空格8            
            
            呵呵```看来getch()和'\b'很熟悉啊```都是一样的``
  现在循环体里面就好办了:
  while(...)
  {
     if ( c == '\b' )
     {
        if ( !word )
           continue ;
        else
        {
           printf("%c", '\b') ;
           --word ;
        }
     }
     else
     {
       *(password+word++) = c ;
       putchar('*') ;
     }

    *(password+word) = '\0' ;

    return ;
  }
            结果是失败的``按一次退格光标后移一位``我们输出的只有一个'\b'看来``getch()和退格``还是不很熟悉``只是
              光标后移一位``现在有前面经验现在好办了``这个时候输出一个不可见字就可以符覆盖退格后的*``多加一个'\0'
            有些人可以用空格去覆盖``
         
            测试中......
        
            结果是``光标不动``但是前面的*是消失了``而且再怎么按退格都没反映``其实这是比较明显的``输出'\0'覆盖*后
              是输出一个内容``既然输出了内容``光标当然要前进一下了``覆盖的地方没了*``而光标又在输出覆盖后前移了一位
              也就成这样的结果```再输入空格的时候``也是一样的``怎么办呢把光标再后移一下吧``也就是再输出'\b'

            测试中......
           
            我真开心```测试成功```!!! ^_^  ~~~

  现在对付最后一个问题: 按方向键的问题

              这里要注意一点``我们原来按方向键的时候``是出现2个*``也就是说``我们在按方向键是``被连续读入了2个字符``
            否则怎么回冒2个*呢```
            
                 char c1 = getch() ;
                 char c2 = getch() ;
      
                 printf("%c %d", c1, c1 ) ;
                 printf(" %c %d", c1, c2 ) ;
                 getchar();

                 理想输出为: 一个字符 空格一个值空格一个字符 空格一个值_(下划线是光标)
                 实际输出是: ?-32空格H空格72_ 按的是↑
                                ?-32空格K空格75_ 按的是←
                                ?-32空格P空格80_ 按的是↑
                                ?-32空格M空格77_ 按的是→
                   ( 这里小说一下:  大家都知道END键光标到行为尾``HOME键到头``而他们和方向键类似`都是-23加一个值``
                  END是79```HOME是``71``)
                   ?比较麻烦``所以我把字符``unsiged了``结果是-32都变成了224`````看来getch()对方向键简直是陌生到极点
                   输出为````不认识``也就是?``
                看来读取的第一个字符都一样``为224无符号型和-32有符号型``区别在第2个``
                所以```只有靠第2个来帮忙了```修改代码:  只考虑方向键

                  else if ( c == 224 )
               {              
                    unsigned char fx = getch() ; //  读取第2个字符``判别到底是按的哪个方向键
               
                       if ( fx == 72 || fx == 80  ) // 上或下``不考虑
                              continue ;
                    else if ( fx == 77 )     //  右移```
                    {
                       if ( insert == word ) //  光标不管怎么移``最到右移到*最右边
                              continue ;
                       else
                       {
                            putchar('*') ;   //  覆盖之前左移后光标位置的*``然后光标回下移一位``就自然的光标右移了
                            ++insert ;
                       }     
                    }
                    else if ( fx == 75  )
                    {                 
                       if(insert)
                       {
                         putchar('\b') ;  // 向后移动光标``一个'\b'就搞定```
                         --insert ;  
                       }
                    }
                    else if ( fx == 79  )
                    {      
                           short i = word - insert ; // 计算覆盖*的数量
                     
                           while ( i-- )
                                 putchar('*') ;     
                                 
                           insert = word ;         //  刷新
                    }
                    else if ( fx == 71  )
                    {
                         short i = insert ;       // 计算\b的数量
                    
                         while ( i-- )
                                putchar('\b') ;
                           
                         insert = 0 ;           // 置0
                    }
                    else {;}     
               }

        还有就是``就是在*中间插入和删除密码时的问题:
        删除:  
              if ( insert && insert != word )   //  在*中间修改密码``
                 {
                     short i = word - insert ;  // 显示方式  
                     short j = i ;         
                     while ( i-- > 1 )
                     {
                         putchar('*') ;     
                     }
                     
                     printf ("%c", '\0');  
                     
                     while ( j-- > -1 )
                     {
                         putchar('\b') ;         //  显示方式
                     }
                     
                     for( short move = insert ; move < word; ++move )  //  移动相关密码
                     {
                        password[move-1] = password[move];   
                     }
                     password[--word] = '\0' ;
                     
                     --insert ;
                 }
        插入:
               if ( insert != word )              //  在*中间修改密码``
               {
                   short i = word - insert + 1  ;  //  显示方式
                   short j = word - insert ;
                  
                   while ( i-- )
                         putchar('*') ;
                   while ( j-- )
                         putchar('\b') ;         //  显示方式
                        
                   for( short move = word - 1 ;  move >= insert ; --move )   //  移动相关密码
                   {
                     password[move+1] = password[move] ;
                   }
                  
                   password[insert++] = c ;
                   password[++word] = '\0' ;                                                
               }

        添加到``getword函数里````编译运行都```OK``现在度取密码的问题已经搞定```剩下的就是核对帐号密码了``

        short chick( char * pass )
        {
              if ( pass == passid)
                  return ( ( strcmp( pass, ID ) ) ?  (0) : (1) ) ;
              else
                  return ( ( strcmp( pass, WORD ) )  ?  (0) : (1) ) ;
        }

        这个都能看懂吧````

``现在好好组合一下个部分就可以了``我的文件库有组合好的`函数` :

//   07 - 12 - 16   9:18P         修改

MCP | 阅读 1581 次
文章评论,共0条
游客请输入验证码