中国居民身份证号码检验程序

功能:检查15位或18位的身份证号码的有效性
运行环境:Red Hat Enterprise Linux  AS release 3AIX Version 5 操作系统上测试通过
编译命令:cc -o personid_chk personid_chk.c
执行命令:./personid_chk
源代码:

/************************************************************
FileName:     personid_chke.c
Author:       yuanfen127
Date:         2005年01月01日
Description:  中国居民身份证检验程序
Version:      1.0
Function 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("%18s",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,"%1d",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, "%4d %2d %2d", &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," %04d%02d%02d %02d:%02d:%02d.%03d",
    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,"%04d%02d%02d",
                     tm1->tm_year + 1900,
                     tm1->tm_mon + 1,
                     tm1->tm_mday);
    return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值