[原创+分享] 编写帐号的输入的函数
我想大家对帐号和密码的输入都知道是怎么回事吧```不知道话```那么就请点击桌面上的那个企鹅```然后回有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 修改