第二题:身份证号查验程序
Author : StarsAC
Date : May 16th, 2024
1. 题目解析
本题要求编写一个程序来查验身份证号码的有效性并输出有问题的号码。查验的内容包括字符串长度,字符串所含字符以及最后一位的校验码是否正确。其中,位于身份证号最后一位的校验码的计算规则如下:
-
前17位数字按照特定的权重进行加权求和,权重分配为如下表所示。
身份证数字位数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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
2.关键数据结构
char
类型字符串数组id1[][]
用于存储输入的身份证号码组。char
类型数组id[]
:用于存储待验证的身份证号码。int
类型数组weights
:存储身份证号码前17位的加权因子,数组长度为17,元素值为{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
。char
类型数组check_num
:储存身份证号码最后一位的校验码M的映射,字符串长度为11,值为"10X98765432"
。
3.功能模块设计
- **身份证号码的格式检查:**检查身份证号码组成的字符串长度是否为18,且前17位只能是数字09,最后一位只能是数字09或字符‘X’。
- **加权求和计算:**计算身份证号码前17位数字的加权和。
- **Z值的计算:**将身份证号码前17位数字的加权和对11取模得到Z值。
- **校验码M的计算:**根据Z值与校验码M的值的对应关系得到相对应的M值。
- **验证身份证号码的有效性:**检查用户输入的身份证号码的校验码值和计算结果是否匹配。
- **结果输出:**向控制台打印输出经过校验后发现问题的身份证号码。
4.编写并调试各功能模块
1.身份证号码的格式检查
int validate_format(char* id){ //身份证号码校验函数
int i;
if(strlen(id) != 18){ //判断身份证号码是否为18位
return -1;
}
for (i = 0; i < 17; i++) { //判断前17位是否合法
if(id[i] < '0' || id[i] > '9'){
return -1;
}
}
if(!((id[17] >= '0' && id[17] <= '9' ) || id[17] == 'x' || id[17] == 'X' )){ //判断第18位是否合法
return -1;
}
return 0; //如果合法, 返回正常值0
}
2.加权求和计算
int weights[17] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};//权重
int sum_weights,i,j,n; //初始化变量
for (i= 0; i < 17; i++) { //计算加权和
sum_weights += (id[i] - '0') * weights[i];
}
3.Z值的计算
int z = sum_weights % 11; //计算Z
4.校验码M的计算
char check_num[] = {"10X98765432"}; //Z和M之间的映射关系
char m = check_num[z]; //得到相应的M值
5.验证身份证号码的有效性,输出判断结果
char id1[n][18]; //创建字符串数组
for (j = 0;j < n; j++){ //遍历字符串数组
printf("请输入身份证号,以回车键结束:\n");
scanf("%s", &id1[j]);
char* id = id1[j];
if(validate_format(id) != 0){ //若身份证号格式错误
printf("身份证号格式错误:%s\n",id);
}else{
for (i= 0; i < 17; i++) { //计算加权和
sum_weights += (id[i] - '0') * weights[i];
}
int z = sum_weights % 11; //计算Z
char m = check_num[z]; //得到相应的M值
if(id[17] != m) { //若身份证号校验码错误
printf("身份证号校验码错误:%s\n", id);
}
}
}
5.测试样例及对应输出
请输入要验证的身份证号码的数量,以回车键结束:
4
请输入身份证号,以回车键结束:
101
身份证号格式错误:101
请输入身份证号,以回车键结束:
11111111111111111A
身份证号格式错误:11111111111111111A
请输入身份证号,以回车键结束:
111111111111111111
身份证号校验码错误:111111111111111111
请输入身份证号,以回车键结束:
111111111111111110
进程已结束,退出代码为 0
6.完整程序
#include <stdio.h>
#include <string.h>
int validate_format(char* id);
int main(void) {
int weights[17] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; //权重
char check_num[] = {"10X98765432"}; //Z和M之间的映射关系
int sum_weights,i,j,n; //初始化变量
printf("请输入要验证的身份证号码的数量,以回车键结束:\n");
scanf("%d",&n);
char id1[n][18]; //创建字符串数组
for (j = 0;j < n; j++){ //遍历字符串数组
sum_weights = 0;
printf("请输入身份证号,以回车键结束:\n");
scanf("%s", &id1[j]);
char* id = id1[j];
if(validate_format(id) != 0){ //若身份证号格式错误
printf("身份证号格式错误:%s\n",id);
}else{
for (i= 0; i < 17; i++) { //计算加权和
sum_weights += (id[i] - '0') * weights[i];
}
int z = sum_weights % 11; //计算Z
char m = check_num[z]; //得到相应的M值
if(id[17] != m) { //若身份证号校验码错误
printf("身份证号校验码错误:%s\n", id);
}
}
}
return 0;
}
int validate_format(char* id){ //身份证号码校验函数
int i;
if(strlen(id) != 18){ //判断身份证号码是否为18位
return -1;
}
for (i = 0; i < 17; i++) { //判断前17位是否合法
if(id[i] < '0' || id[i] > '9'){
return -1;
}
}
if(!((id[17] >= '0' && id[17] <= '9' ) || id[17] == 'x' || id[17] == 'X' )){ //判断第18位是否合法
return -1;
}
return 0; //如果合法, 返回正常值0
}