功能:检查15位或18位的身份证号码的有效性运行环境:Red Hat Enterprise Linux AS release 3 、AIX Version 5 操作系统上测试通过编译命令:cc -o personid_chk personid_chk.c执行命令:./personid_chk源代码:
/************************************************************FileName: personid_chke.cAuthor: yuanfen127Date: 2005年01月01日Description: 中国居民身份证检验程序Version: 1.0Function List: 1. int chk_pid(unsigned char *v_idno) 检查身份证校验位 2. int ATOI(char *ptr, int len) 文本类型按位转化为数值类型 3. int chkdate(char *date) 检查日期有效性 4. int get_curr_time(char *out_time) 获取当前工作日期History: <author> <time> <version > <desc>***********************************************************/#include <stdio.h>#include <string.h>#include <time.h>#include <timeb.h>
main(){ char l_tidno[19]; /*定义19位的字符串*/
printf("请输入15位或者18位身份证件号码:"); /*提示输入身份证号*/ scanf("s",l_tidno); /*输入身份证号码*/ if ( 0 == chk_pid(&l_tidno) ) /*调用chk_pid函数检查身份证号*/ { printf("此身份证号码正确!/n"); /*如果校验后正确,显示在屏幕上*/ }
return; /*返回空值*/}
int chk_pid(unsigned char *v_idno){ char l_tbuf[1024]; /*存放一些文本提示信息*/ char l_tmpdate[9]; /*存放身份证中的出生日期*/ char l_check[2]; /*存放18位身份证号的校验码*/ char l_today[9]; /*存放系统当前日期*/ int l_itmp=0; int l_inumber=0; int i; unsigned char l_chk_code[] = {'1','0','X','9','8','7','6','5','4','3','2'}; short l_wi[] = { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1};
/*定义省份地区数组*/ char l_tarea[92][10]={"null","null","null","null","null","null","null", "null","null","null","null","北京","天津","河北", "山西","内蒙古","null","null","null","null","null", "辽宁","吉林","黑龙江","null","null","null","null", "null","null","null","上海","江苏","浙江","安微", "福建","江西","山东","null","null","null","河南", "湖北","湖南","广东","广西","海南","null","null", "null","重庆","四川","贵州","云南","西藏","null", "null","null","null","null","null","陕西","甘肃", "青海","宁夏","新疆","null","null","null","null", "null","台湾","null","null","null","null","null", "null","null","null","null","香港","澳门","null", "null","null","null","null","null","null","null", "国外"};
/*初始化变量*/ memset(l_tbuf,' ',sizeof(l_tbuf)); memset(l_tmpdate,' ',sizeof(l_tmpdate)); memset(l_check,' ',sizeof(l_check));
/*判断身份证号码位数*/ if ( 15 != strlen(v_idno) && 18 != strlen(v_idno) ) { printf("身份证号码必须为15位或18位!/n"); return -1; }
/*判断是否全部为数字*/ if ( strlen(v_idno) == 15 ) { for ( i=0;i<15;i++ ) { if ( 0 == isdigit( v_idno[i] ) ) { printf("身份证输入有误!/n"); return -1; } } } else { /*如果是18位的身份证,前面17位均为数字*/ for ( i=0;i<17;i++ ) { if ( 0 == isdigit(v_idno[i]) ) { printf("身份证输入有误!/n"); return -1; } }
/*第18位如果不是数字,那么只可能是"x"或者"X"*/ if ( 0 == isdigit(v_idno[i]) && 0 != memcmp(&v_idno[i],"x",1) && 0 != memcmp(&v_idno[i],"X",1) ) { printf("身份证输入有误!/n"); return -1; } }
/*身份证号码前2位代表省份地区码*/ l_itmp = ATOI(v_idno,2); /*调用ATOI函数前面2位转换成int型*/
/*组装显示信息字符串*/ sprintf(l_tbuf,"身份证号码:%s/n",v_idno);
if ( memcmp(l_tarea[l_itmp],"null",4) == 0 || l_itmp > 91 ) { sprintf(l_tbuf,"%s地区: 不详/n",l_tbuf); } else { sprintf(l_tbuf,"%s地区: %s/n",l_tbuf,l_tarea[l_itmp]); }
if ( strlen ( v_idno ) == 18 ) { l_itmp = 16; } else { l_itmp = 14; }
if ( (v_idno[l_itmp] - '0') % 2 == 0 ) { sprintf(l_tbuf,"%s性别: 女/n",l_tbuf); } else { sprintf(l_tbuf,"%s性别: 男/n",l_tbuf); }
printf("%s",l_tbuf);
/*判断出生日期*/ if ( strlen(v_idno) == 15 ) /*如果15身份证,默认为19XX年*/ { sprintf(l_tmpdate,"19%.6s",&v_idno[6]); } else { sprintf(l_tmpdate,"%.8s",&v_idno[6]); }
get_curr_time(l_today); /*调用函数获取系统当前日期*/
/*判断出生日期是否有效,并且不能晚于当前系统日期*/ if ( 0 != chkdate(&l_tmpdate) || memcmp( l_tmpdate, l_today, 8) > 0) { printf("身份证出生日期错误,请重新输入!/n"); return -1; }
/*如果是18位身份证号码,则需要判断校验位*/ if ( strlen(v_idno) == 18 ) { l_inumber=0; /* i 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 Wi 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1 S=a2*W2+a3*W3+...+ai*Wi (1<i<19) Y=mod(S,11) */
/* l_inumber=l_inumber + ATOI(&v_idno[0],1)*7; l_inumber=l_inumber + ATOI(&v_idno[1],1)*9; l_inumber=l_inumber + ATOI(&v_idno[2],1)*10; l_inumber=l_inumber + ATOI(&v_idno[3],1)*5; l_inumber=l_inumber + ATOI(&v_idno[4],1)*8; l_inumber=l_inumber + ATOI(&v_idno[5],1)*4; l_inumber=l_inumber + ATOI(&v_idno[6],1)*2; l_inumber=l_inumber + ATOI(&v_idno[7],1)*1; l_inumber=l_inumber + ATOI(&v_idno[8],1)*6; l_inumber=l_inumber + ATOI(&v_idno[9],1)*3; l_inumber=l_inumber + ATOI(&v_idno[10],1)*7; l_inumber=l_inumber + ATOI(&v_idno[11],1)*9; l_inumber=l_inumber + ATOI(&v_idno[12],1)*10; l_inumber=l_inumber + ATOI(&v_idno[13],1)*5; l_inumber=l_inumber + ATOI(&v_idno[14],1)*8; l_inumber=l_inumber + ATOI(&v_idno[15],1)*4; l_inumber=l_inumber + ATOI(&v_idno[16],1)*2; */
l_inumber = 0; for ( i = 0 ; i < 17 ; i++ ) { l_inumber += ATOI(&v_idno[i],1) * l_wi[i]; }
l_itmp = l_inumber % 11;
/* l_itmp 0 1 2 3 4 5 6 7 8 9 10 校验码 1 0 X 9 8 7 6 5 4 3 2 */ /*switch ( l_itmp ) { case 0: sprintf(l_check,"%.1s","1"); break; case 1: sprintf(l_check,"%.1s","0"); break; case 2: sprintf(l_check,"%.1s","X"); break; default: i = 12 - l_itmp; sprintf(l_check,"",i); break; } */
/*printf("%d/n",l_inumber);*/ /*printf("输入号码的校验位:%d/n",l_itmp);*/ /*printf("计算出正确的检验位:%d",l_check);*/
if ( v_idno[17] == 'x') { v_idno[17] = 'X'; }
if ( l_chk_code[l_itmp] != v_idno[17] ) { printf("身份证校验位错误,请重新输入/n"); return -1; } }
return 0;}
int ATOI(char *ptr, int len){ char tmpbuf[80]; int int_val;
sprintf(tmpbuf,"%.*s",len,ptr); tmpbuf[len]='/0'; int_val=atoi(tmpbuf);
return(int_val);}
int chkdate(char *date){ int day_tbl[2][13] ={ 0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0,31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int yr,mon,day; int leap,i;
for ( i=0; i<8; i++) { if( (date[i]<'0') || (date[i]>'9') ) { return(-1); } }
if (sscanf(date, "M - -", &yr, &mon, &day) != 3) { return(-1); }
if (mon < 1 || mon > 12 || day < 1 || day > 31) { return(-1); }
leap = (yr % 4 == 0 && yr % 100 != 0 || yr % 400 == 0);
if (day > day_tbl[leap][mon]) { return(-1); } else { return(0); }}
int get_curr_time(char *out_time){ struct tm *tm1; time_t curr; struct timeb tm2;
time(&curr); ftime(&tm2);
tm1 = localtime (&curr);
/*返回毫秒级的当前时间* sprintf(out_time," ddd d:d:d.d", tm1->tm_year + 1900,tm1->tm_mon + 1, tm1->tm_mday,tm1->tm_hour, tm1->tm_min ,tm1->tm_sec,tm2.millitm); */
sprintf(out_time,"ddd", tm1->tm_year + 1900, tm1->tm_mon + 1, tm1->tm_mday); return 0;}