[原创+分享] 编写帐号的输入的函数
[原创+分享] 编写帐号的输入的函数我想大家对帐号和密码的输入都知道是怎么回事吧```不知道话```那么就请点击桌面上的那个企鹅```然后回有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个8
出现问题就要解决```一个一个来吧```
第一个问题: 为什么按回车``回冒个*呢``
分析: 查看程序可以知道``只有循环成立才回冒*``也就是说``我输入的回车时``
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) ) ;
}
这个都能看懂吧````
``现在好好组合一下个部分就可以了``这里组合好的`:
[[italic] 本帖最后由 死了都要C 于 2007-12-16 21:08 编辑 [/italic]]