C语言PAT刷题 - 1031 查验身份证

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答;
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

一、题目描述
一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:
首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:
Z:0 1 2 3 4 5 6 7 8 9 10
M:1 0 X 9 8 7 6 5 4 3 2
现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。
输入格式:
输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码。
输出格式:
按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed。
输入样例1:
4
320124198808240056
12010X198901011234
110108196711301866
37070419881216001X
输出样例1:
12010X198901011234
110108196711301866
37070419881216001X
输入样例2:
2
320124198808240056
110108196711301862
输出样例2:
All passed

二、解题思路
读题:

//身份证由17位(地区、日期编号和顺序编号)加1位(校验码)组成;
//首先按照权重分配对前17位数字加权求和,然后将计算的和对11取模得到值Z,按照题目所给规则根据Z值得到校验码M的值,把M和身份证最后一位进行比对;
//要求设计程序检测身份证号码是否合理,输入第一行给正整数N,代表后面给的身份证号码的个数,一行一个;
//要求按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed。
思路:
1.定义结构体ID,存储身份证号card和当前身份证是否合理的检测标志位Result;
2.定义需要的变量;
3.完成输入要求——第一行接收N(表示之后需要接收的身份证号码的数量),后面的n行接收身份证号,一行一个;
4.检测正式开始前默认所有号码的检测标志位为1,即号码合理,后面发现问题再置0;
同时由于后面的检测可能要用到sum去存储加权求和的值,所以每一轮检测开始前把sum也置0,排除之前sum中存储的值的干扰;
5.设置循环,检测身份证号的前面17位数字,一位一位地进行加权求和,若存在非数字则直接判定该身份证号不合理,提前结束处理各位数字的循环;
6.思路5的循环结束后,若当前身份证号的检测标志位依然为1,表明前17位没有非数字,需要继续进行检测。
(1)加权求和的最终结果sum对11取模得z;
(2)参照规则,根据模z获取校验码m;
(3)如果校验码和当前身份证号的最后一位不相等,则将其检测标志位置0,表示身份证号不合理;
7.如果所有的号码都没有问题,打印“All passed”,否则打印有问题的号码。

三、具体实现
0.标准C源程序框架

#include <stdio.h>
int main()
{
    return 0;
}

1.定义结构体ID,存储身份证号card和当前身份证是否合理的检测标志位Result;

typedef struct ID
{
    char card[19];//多一位用于存储'\0'
    int result;//存储检测结果,1表示号码合理,0表示号码有问题
}ID;

2.定义需要的变量;

    ID id[100];//存储身份证号的数组
    int n;//存储身份证号码的数量
    int ratio[18] = { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 };//权重分配
    int i, j;//循环变量
    int sum;//存储身份证号码前17位数字加权求和的结果
    int z;//存储sum对11取模后的对应值
    char m;//存储校验码
    int num=0;//表示有问题的号码的数量

3.完成输入要求——第一行接收N(表示之后需要接收的身份证号码的数量),后面的n行接收身份证号,一行一个;

    scanf("%d", &n);
    for (i=0;i<n;i++)//进行n轮,每轮循环检测一个身份证号码
    {
        scanf("%s",id[i].card);//scanf遇到空白符(空格、回车、换行、tab)会自动截断并添加'\0'
    	//每轮循环接收一个数据,接收时顺便对当前身份证号进行检测,检测实现代码在后面
    }

4.检测正式开始前默认所有号码的检测标志位为1,即号码合理,后面发现问题再置0;
同时由于后面的检测可能要用到sum去存储加权求和的值,所以每一轮检测开始前把sum也置0,排除之前sum中存储的值的干扰;

        id[i].result = 1;//检测正式开始前默认所有号码的检测结果为1,即号码合理
        sum = 0;

5.设置循环,检测身份证号的前面17位数字,一位一位地进行加权求和,若存在非数字则直接判定该身份证号不合理,提前结束处理各位数字的循环;

        for (j = 0; j < 17; j++)//每轮循环处理身份证号码的一位数字
        {
            //如果身份证号码前17位并非全数字,直接判定号码有问题
            if (id[i].card[j] < '0' || id[i].card[j] > '9')
            {
                id[i].result = 0;
                num++;
                break;//已经判定号码有问题,没既要继续监测,跳出内层循环
            }
            //对身份证号码前17位数字加权求和
            sum += (id[i].card[j]-'0') * ratio[j];
        }

6.思路4的循环结束后,若当前身份证号的检测标志位依然为1,表明前17位没有非数字,需要继续进行检测。
(1)加权求和的最终结果sum对11取模得z;
(2)参照规则,根据模z获取校验码m;
(3)如果校验码和当前身份证号的最后一位不相等,则将其检测标志位置0,表示身份证号不合理;

        if(id[i].result==1)
        {
            //sum对11取模
            z = sum % 11;
            //获取校验码m
            switch (z)
            {
            case 0: {m = '1'; break; }
            case 1: {m = '0'; break; }
            case 2: {m = 'X'; break; }
            case 3: {m = '9'; break; }
            case 4: {m = '8'; break; }
            case 5: {m = '7'; break; }
            case 6: {m = '6'; break; }
            case 7: {m = '5'; break; }
            case 8: {m = '4'; break; }
            case 9: {m = '3'; break; }
            case 10: {m = '2'; break; }
            }
            if (m != id[i].card[17])
            {
                id[i].result = 0;
                num++;//找到一个有问题的号码,num自增1
            }
        }

7.如果所有的号码都没有问题,打印“All passed”,否则打印有问题的号码。

    //如果所有的号码都没有问题,打印“All passed”
    if (num==0)
        printf("All passed");
    else//打印有问题的号码
    for (i = 0; i < n; i++)
    {
        if (id[i].result == 0)
            printf("%s\n",id[i].card);//因为card是一个数组名,本身就代表一个地址,所以不需要加&
    }

四、测试数据
输入样例1:(测试点4)

(考察你的程序遇到单个问题代码且此问题代码为前17位有字母时,能否返回正确的结果)
1
x30128123456781613
输出样例1:
x30128123456781613

五、全部代码

#include <stdio.h>
typedef struct ID
{
    char card[19];//多一位用于存储'\0'
    int result;//存储检测结果,1表示号码合理,0表示号码有问题
}ID;
int main()
{
    ID id[100];//存储身份证号的数组
    int n;//存储身份证号码的数量
    int ratio[18] = { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 };//权重分配
    int i, j;//循环变量
    int sum;//存储身份证号码前17位数字加权求和的结果
    int z;//存储sum对11取模后的对应值
    char m;//存储校验码
    int num=0;//表示有问题的号码的数量
    scanf("%d", &n);
    for (i=0;i<n;i++)//进行n轮,每轮循环检测一个身份证号码
    {
        scanf("%s",id[i].card);//scanf遇到空白符(空格、回车、换行、tab)会自动截断并添加'\0'
        id[i].result = 1;//检测正式开始前默认所有号码的检测结果为1,即号码合理
        sum = 0;
        for (j = 0; j < 17; j++)//每轮循环处理身份证号码的一位数字
        {
            //如果身份证号码前17位并非全数字,直接判定号码有问题
            if (id[i].card[j] < '0' || id[i].card[j] > '9')
            {
                id[i].result = 0;
                num++;
                break;//已经判定号码有问题,没既要继续监测,跳出内层循环
            }
            //对身份证号码前17位数字加权求和
            sum += (id[i].card[j]-'0') * ratio[j];
        }
        if(id[i].result==1)
        {
            //sum对11取模
            z = sum % 11;
            //获取校验码m
            switch (z)
            {
            case 0: {m = '1'; break; }
            case 1: {m = '0'; break; }
            case 2: {m = 'X'; break; }
            case 3: {m = '9'; break; }
            case 4: {m = '8'; break; }
            case 5: {m = '7'; break; }
            case 6: {m = '6'; break; }
            case 7: {m = '5'; break; }
            case 8: {m = '4'; break; }
            case 9: {m = '3'; break; }
            case 10: {m = '2'; break; }
            }
            if (m != id[i].card[17])
            {
                id[i].result = 0;
                num++;//找到一个有问题的号码,num自增1
            }
        }
    }
    //如果所有的号码都没有问题,打印“All passed”
    if (num==0)
        printf("All passed");
    else//打印有问题的号码
    for (i = 0; i < n; i++)
    {
        if (id[i].result == 0)
            printf("%s\n",id[i].card);//因为card是一个数组名,本身就代表一个地址,所以不需要加&
    }
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值