分类目录归档:C/C++

将15位一代身份证号转换成18位二代身份证号

原来的一代身份证号是15位的,现在用的二代身份证号是18位的,它们之间有一个转换规则。
一代:340524800101001
二代:34052419800101001X
可以看到它们之间的区别是二代在年份前多了19,最后面多了一位校验位

第十八位数字的计算方法为:
1.将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
2.将这17位数字和系数相乘的结果相加。
3.用加出来和除以11,看余数是多少?
4余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2。
5.通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。

以下代码VC6编译测试通过:

#include<stdio.h>
#include<string.h>

void id_card_convert(char * id)
{
  char tmp[20];
  int i, j ,sum = 0;
  char verify[11] = {'1','0','X','9','8','7','6','5','4','3','2'};//校验位
  int num[17] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};//系数

  //转换号码15位到18位
  memset(tmp, 0x00, sizeof(tmp));
  memcpy(tmp, id, 6);//复制前6位
  memcpy(&tmp[6], "19", 2);//前6位后补19
  memcpy(&tmp[8], id+6, 9);//复制后9位
  
  for (i = 0; i < 17; i++)//现在tmp有17位算第18位校验位
  {
    sum = sum + (tmp[i]-0x30)*num[i];
  }

  j = sum % 11;//从verify数组中找到第j位就是校验值

  tmp[17] = verify[j];
  
  memcpy(id, tmp, 20);  
}

void main()
{
  char id_card[20];
  memset(id_card, 0x00, sizeof(id_card));
  memcpy(id_card, "340524800101001", 15);
  printf("原身份证号:%s\n", id_card);
  id_card_convert(id_card);
  printf("转换后:%s\n", id_card); //显示34052419800101001X是正确值
}

参考资料:
http://blog.csdn.net/ylqmf/article/details/4904483

VC6.0代码编辑风格设置

一、设置显示颜色
(1)单击菜单“Tools/Options”,弹出 Options 窗口,在 Format 页中选取 Category 中的All Windows 项。
(2)在 Colors 栏中对文本颜色、背景色、关键字的颜色等进行设置。
=========================================
         推荐的颜色修改表
=========================================
  Colors        Forground  Background
Text (文本)        绿色     深蓝色
Text Selection (选定文本) 蓝色     灰色
BookMark (书签)      黑色     绿色
Breakpoint (断点)     白色     红色
Keyword(关键字)      白色    Automatic
Comment(注释)       灰色    Automatic
Number (数字)       绿色    Automatic
=========================================

二、设置tab键
单击菜单“Tools/Options”,弹出 Options 窗口,找到 Tabs 页。
将size都设置为8,选中Insert spaces,将tab键转换为空格。

Source Insight设置

这篇文章是同事写的source insight代码编辑器设置方法,觉得写的很好,故发出来分享。

A.Source Insight的代码字体设置在:“Options”——“Document Options”中,打开后会弹出如下界面:

  1.“Screen Fonts”选项即为代码的显示字体选项,我推荐使用“Courier New”字体,此字体的优点为:所有中文或其他全角字符的显示宽度总是英文半角字符显示宽度的2倍,包括在字符串中显示也同此规则,这样便于代码对齐和判断需要显示在显示屏上的字符的宽度。至于字体的大小,请大家按照自己的习惯修改。

  2.“Editing Options”组合框内的选项的说明:
  (1)“Expand tabs”勾选后,按下一次TAB键时会根据Tab width的设定替换成对应宽度的空格,可避免代码中出现TAB的问题。
  (2)“Show line numbers”勾选后,每行的左边会显示行号,便于查看行号,大家可根据习惯酌情勾选。
  (3)“Show right margin”勾选后,会显示右边距边界线(灰色竖线),根据设定的“Margin width”宽度来显示,可以使我们直观的判断一行的代码是否太长而需要拆分为多行。此项可酌情勾选。
  (4)“Tab width”设置为2,当勾选“Expand tabs”后,按下1次TAB键就相当于按了2次空格。
  (5)“Margin width”设置为80,当勾选“Show right margin”后,右边80字符宽度处会显示右边距边界线,可酌情设置。
继续阅读Source Insight设置

C语言程序设计学习

1.定义和声明最重要的区别:定义创建了对象并为这个对象分配了内存,声明没有分配内存

2.static
变量
静态局部变量:作用域在函数内,保存在内存的静态存储区,只被初始化一次,在下一次调用前还可以保持原来的赋值
静态全局变量:作用域在定义的文件内

函数
对于函数而言,任何用static修饰的函数,其作用域仅为当前源文件,而对外部来说这个函数是不可见的,即只有和其在同一源文件中的函数才能调用这个静态函数;
反过来说,如果一个函数仅仅被同一源文件中的其他函数调用,那么这个函数应该声明为静态的,这样做的好处在于:可以一定程度上的解决不同源文件之间函数的命名冲突问题;

3.sizeof是披着函数皮的关键字
sizeof()包含最后的结束符’\0′
strlen()只计算字符串中元素个数,不包含’\0′
sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’\0’结尾的
继续阅读C语言程序设计学习

指针类型的定义

在C/C++中定义指针类型的变量,使用:
数据类型 * 指针变量名

例如:

int * p_update;

*操作符两边的空格是可选的。

C程序员习惯使用这种格式:

int *ptr;

这强调*ptr是一个int类型的值。

C++程序员习惯使用:

int* ptr;

这强调int*是一种复合类型,是指向int的指针。

在哪里添加空格对于C++编译器来说是没有任何区别的。不过在书上看到事例中的指针定义都是在*左右各加一个空格。

C语言计算两个日期之间的天数

计算两个年月日之间的天数,思路是分别算出日期的总天数然后相减。

要考虑闰年的情况,判断闰年的口诀:4年一闰,100年不闰,400年再闰。
((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)

网上找了一个(偷懒= =!),修改下如下:
#include <stdio.h>
int sum(int y,int m,int d)
{
  unsigned char x[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
  int i,s=0;
  for(i=1;i<y;i++)
    if(i%4==0 && i%100!=0 || i%400==0)
      s+=366;//闰年
    else
      s+=365;//平年

  if(y%4==0 && y%100!=0 || y%400==0)
    x[2]=29;

  for(i=1;i<m;i++)
    s+=x[i];//整月的天数
  s+=d;//日的天数

  return s;//返回总天数,相对公元1年
}

void main()
{
  unsigned char y1,m1,d1,y2,m2,d2;
  int s1,s2;

  printf(“输入第一个年 月 日:”);
  scanf(“%d %d %d”,&y1,&m1,&d1);
  printf(“输入第二个年 月 日:”);
  scanf(“%d %d %d”,&y2,&m2,&d2);

  s1=sum(y1,m1,d1);
  s2=sum(y2,m2,d2);

  if (s1 > s2)
    printf(“相差天数:%ld\n”,s1-s2);
  else
    printf(“相差天数:%ld\n”,s2-s1);

}

以上代码VC6编译测试通过。

虽然这个思路显得有些笨,但是其它算法,代码太长太复杂,要考虑多种情况,不如直接算两个日期距离公元元年1月1日的天数,然后相减。

C语言库函数学习(2)

1、strncpy
原型:extern char *strncpy(char *dest, char *src, int n);
功能:把src所指由NULL结束的字符串的前n个字节复制到dest所指的数组中。
说明:如果src的前n个字节不含NULL字符,则结果不会以NULL字符结束。
如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。

2、strncat
原型:extern char *strncat(char *dest, char *src, int n);
功能:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的’\0′)并添加’\0’。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。

3、strncmp
原型:extern int strcmp(char *s1, char *s2, int n);
功能:比较字符串s1和s2的前n个字符。
比较结果:
当s1<s2时,返回值<0
当s1=s2时,返回值=0
当s1>s2时,返回值>0
继续阅读C语言库函数学习(2)

C语言和大小端模式

在操作系统中数据长度的单位有:字节、字、双字、四字(不包括浮点型)。
比如在VC6.0的windef.h中定义了BYTE、WORD、DWORD这些类型:

typedef unsigned char       BYTE;
typedef unsigned short      WORD;
typedef unsigned long       DWORD;
当然四字类型可以定义为:
typedef unsigned long long  DDWORD;


大小端模式就和CPU对字、双字、四字的存储方式有关了。
大端模式(Big-Endian):字数据的高字节存储在低地址中,字数据的低字节存储在高地址中。
小端模式(Little-Endian):字数据的高字节存储在高地址中,字数据的低字节存储在低地址中。
继续阅读C语言和大小端模式

C语言内存观

  在内存中存储的数据都是以二进制形式存储,比如有一个字节数据为11110001。把它看成十六进制就是0xF1,看成十进制就是数值241,看成有符号的数值就是-113,看成ASCII码是一个不可显示的字符(ASCII码范围是数值0-255),看成BCD码就是由0x0F和0x01组成的。在内存中这个字节一直是11110001,各种进制是我们看待它的一种表象。

C语言库函数学习(1)

1、memcpy
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。

2、memcmp
原型:extern int memcmp(void *buf1, void *buf2, unsigned int count);
功能:比较内存区域buf1和buf2的前count个字节。
比较结果:
当buf1<buf2时,返回值<0
当buf1=buf2时,返回值=0
当buf1>buf2时,返回值>0

3、memset
原型:extern void *memset(void *buffer, int c, int count);
功能:把buffer所指内存区域的前count个字节设置成字符c。
说明:返回指向buffer的指针。
备注:常用于初始化连续的一块内存。
继续阅读C语言库函数学习(1)