作者的话:若有朋友复制代码去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;
}