1.数据类型取值范围
unsigned int 0~42 9496 7295
int -2147483648~21 4748 3647
unsigned long 0~4294967295
long -2147483648~2147483647
long long的最大值:922 3372 0368 5477 5807
long long的最小值:-9223372036854775808
unsigned long long的最大值:184 4674 4073 7095 5161
__int64的最大值:922 3372 0368 5477 5807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:1844 6744 0737 0955 1615
2. 无穷大常量取值是0x3f3f3f3f 或是1<<30(1<<30 表示1左移30位,每左移一位乘以2,所以就是1*2^30=1073741824)
3.一维数组初始化为0可以这样写Int a[8]={0};
二维数组初始化为0可以这样写Int a[8][8]={{0}}; 两个大括号即可
4.在判断两个浮点数大小
一定要在一边先减去0.000001,如a<b,一定写成a-0.000001<b才行!
5.如何输出float型而后面不加0?
printf("%g", num); \\ printf("%.f",num);
%g 用来输出实数,它根据数值的大小,自动选f格式或e格式(选择输出时占宽度较小的一种),且不输出无意义的0。即%g是根据结果自动选择科学记数法还是一般的小数记数法
7.scanf("\n%*c%d",&m);
Scanf 格式中,如果在%后面、格式字符前面加上一个“*”附加说明符,表示跳过该输入,输入的数据不放入变量中。
而输入的 '\n' 是中和掉输出的 \n
也可以换成
getchar();
scanf("%*c%d",&m);
而 *c 表示忽略一位 也可以改成
scanf("%*1d%d",&m);
8.分离整数和小数部分整数划分
要求:编写一个程序,其功能为:从键盘上输入一个浮点数(小数点后有三位数),然后分别输出该数的整数部分和小数部分。
样例输入:123.456
样例输出:123 456
#include <stdio.h>
int main()
{
float x;
int a, b;
scanf("%f",&x);
a=x; //自动类型转换,取整数部分
b=(int)(x*1000)%1000; //乘1000后对1000取余,得到3位小数点后数字
printf("%d %d\n", a, b);
return 0;
}
9.素数判定函数
int Prime_judge(int x)
{
int i;
if(x==0||x==1) return 0;
for(i=2;i<=sqrt(x);i++)
if(x%i==0) return 0;//不是素数
return 1;//是素数
}
10.itoa
将任意类型的数字转换为字符串。在<stdlib.h>中与之有相反功能的函数是atoi。
非标准C语言扩展函数
char*itoa(int value,char*string,int radix);
int value 被转换的整数,char *string 转换后储存的字符数组,int radix 转换进制数,如2,8,10,16 进制等
11.求最小公倍数和最大公约数
最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们的公倍数,其中一个最小的公倍数是他们的最小公倍数,同样地,若干个整数公有的倍数中最小的正整数称为它们的最小公倍数
求最小公倍数算法:最小公倍数=两整数的乘积÷最大公约数
求最大公约数算法:
(1辗转相除法
#include<stdio.h>
void main() /* 辗转相除法求最大公约数 */
{
int m, n, a, b, t, c;
printf("Input two integer numbers:\n");
scanf("%d%d", &a, &b);
m=a; n=b;
while(b!=0) /* 余数不为0,继续相除,直到余数为0 */
{ c=a%b; a=b; b=c;}
printf("The greates common divisor:%d\n", a);//最大公约数 GCD
printf("The least common multiple:%d\n", m*n/a);}//最小公倍数 LCM
2)递归法:最大公约数最小公倍数
- int gcd(int a,int b)
- {
- if(b==0)return a;
- gcd(b,a%b);
- }
12.自然常数e的x次方,表示方法为:exp(x)。
13.试求定积分的近似值(积分限a,b从键盘输入)。
算法分析如下:
求定积分的近似值常有矩形法与梯形法,其实质都是面积求和。
矩形法是把所要求的面积垂直x轴分成n个小矩形,然后把这n个小矩形的面积相加,即为所求的定积分的值。
梯形法是把所要求的面积垂直分成n个小梯形,然后作面积求和。
这两种近似求值的精度随分割个数n的增加而增加,对于相同的n个数,相对来说,梯形法的精度比矩形法的要高一些。
程序代码如下:
例一:
void main()
{
int i,n=1000;
float a,b,h,t1,t2,s1,s2,x;
printf("请输入积分限a,b:");
scanf("%f,%f",&a,&b);
h=(b-a)/n;
for(s1=0,s2=0,i=1;i<=n;i++)
{
x=a+(i-1)*h;
t1=(float)exp(-x*x/2);t2(float)=exp(-(x+h)*(x+h)/2);
s1=s1+t1*h; /*矩形面积累加*/
s2=s2+(t1+t2)*h/2; /*梯形面积累加*/
}
printf("矩形法算得积分值:%f.\n",s1);
printf("梯形法算得积分值:%f.\n",s2);
}
程序运行结果如下:
矩形法算得积分值:0.855821
梯形法算得积分值:0.855624
由上面的比较可知,梯形法的精度要高于矩形法。
例二 求函数f(x)=x*x+2*x+1在【0,2】上的定积分。
#include
main()
{ double s=0,h,a,b,f0,f1,n;
int i;
printf("Enter n,a,b:");
scanf("%lf,%lf,%lf",&n,&a,&b);
h=(b-a)/n;
f0=a*a+2*a+1;
for(i=1;i<=n;i++)
{ a=a+h;
f1=a*a+2*a+1;
s+=(f0+f1)*h/2;
f0=f1;
}
printf("sum is %f",s);
}
14.二分查找又称折半查找
void g(int k,int m)//在长度为m的数组num找到元素k.
{
int high=m-1,flag=0;//flag做标记
int low=0,mid;
while(low<=high){
mid=(low+high)/2;
if(num[mid]<k)
low=mid+1;
else if(num[mid]>k)
high=mid-1;
else{
flag=1;
printf("YES\n");
break;
}
}
if(flag==0)
printf("NO\n");
}
15.输出a和b的比值。如果需要,输出一个既约分数。
分子、分母只有公因数1的分数,或者说分子和分母互质的分数,叫做最简分数,又称既约分数。如:二分之一,三分之二,九分之八,八分之三等等。
int gcd(int a,int b)//求最大公约数
{
while(b!=0)
{
int r=a%b;
a=b;
b=r;
}
return a;
}
if(aa%bb==0)
printf("%d\n",aa/bb);
else
printf("%d/%d\n",aa/gcd(aa,bb),bb/gcd(aa,bb));
16.double型强转int型
应该使用向下取整;+0.5实现四舍五入。
例如:double a=;int b=(int)(a+0.5);
17.任意进制转换
语法:conversion(char s1[],char s2[],long d1,long d2);
参数:
s[]: 原进制数字,用字符串表示
s2[]: 转换结果,用字符串表示
d1: 原进制数
d2: 需要转换到的进制数
返回值: null
注意:
高于9的位数用大写'A'~'Z'表示,2~16位进制通过验证
源程序:
void conversion(char s[],char s2[],long d1,long d2)
{
long i,j,t,num;
char c;
num=0;
for (i=0;s[i]!='\0';i++)
{
if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;
num=num*d1+t;
}
i=0;
while(1)
{
t=num%d2;
if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;
num/=d2;
if (num==0) break;
i++;
}
for (j=0;j<i/2;j++)
{c=s2[j];s2[j]=s[i-j];s2[i-j]=c;}
s2[i+1]='\0';
}
18.求排列组合数
语法:result=P(long n,long m); / result=long C(long n,long m);
参数:
m: 排列组合的上系数
n: 排列组合的下系数
返回值: 排列组合数
注意:
符合数学规则:m<=n
源程序:
long P(long n,long m)
{
long p=1;
while(m!=0)
{p*=n;n--;m--;}
return p;
}
long C(long n,long m)
{
long i,c=1;
i=n;
while(i!=0)
{c*=n;n--;i--;}
while(m!=0)
{c/=m;m--;}
return c;
}
19.x的二进制长度
语法:result=BitLength(int x);
参数:
x: 测长的x
返回值: x的二进制长度
源程序:
int BitLength(int x)
{
int d = 0;
while (x > 0) {
x >>= 1;
d++;
}
return d;
}
20.返回x的二进制表示中从低到高的第i位
语法:result=BitAt(int x, int i);
参数:
x: 十进制 x
i: 要求二进制的第i位
返回值: 返回x的二进制表示中从低到高的第i位
注意:
最低位为第一位
源程序:
int BitAt(int x, int i)
{
return ( x & (1 << (i-1)) );
}
21 /*********************格式化输入输出*********************************/
%d 十进制有符号整数
%ld/%lld long/long long
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x, %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法
━━━━━━━━━━━━━━━━━━━━━━━━━━
说明:
(1). 可以在"%"和字母之间插进数字表示最大场宽。
例如: %3d 表示输出3位整型数, 不够3位右对齐。
%9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6,
小数点占一位, 不够9位右对齐。
%8s 表示输出8个字符的字符串, 不够8个字符右对齐。
如果字符串的长度、或整型数位数超过说明的场宽, 将按其实际长度输出。
但对浮点数, 若整数部分位数超过了说明的整数位宽度, 将按实际整数位输出;
若小数部分位数超过了说明的小数位宽度, 则按说明的宽度以四舍五入输出。
另外, 若想在输出值前加一些0, 就应在场宽项前加个0。
例如: %04d 表示在输出一个小于4位的数值时, 将在前面补0使其总宽度
为4位。
如果用浮点数表示字符或整型量的输出格式, 小数点后的数字代表最大宽度,
小数点前的数字代表最小宽度。
例如: %6.9s 表示显示一个长度不小于6且不大于9的字符串。若大于9, 则
第9个字符以后的内容将被删除。
(2). 可以在"%"和字母之间加小写字母l, 表示输出的是长型数。
例如: %ld 表示输出long整数
%lf 表示输出double浮点数
(3). 可以控制输出左对齐或右对齐, 即在"%"和字母之间加入一个"-" 号可
说明输出为左对齐, 否则为右对齐。
例如: %-7d 表示输出7位整数左对齐
%-10s 表示输出10个字符左对齐
22. /*************************立方之和*****************************/
1^3+2^3+.....+n^3=n^2(n+1)^2/4=[n(n+1)/2]^2
23./****************************平方之和***************************************/
1^2+2^2+...n^2=1/6*n*(n+1)*(2*n+1);
24.快速幂求模取余
积的取余等于取余的积取余
代码如下:
int pow(int a,int n,int b)//返回值是a的n次方对b取余后的值
{
int result=1;
a=a%b;//积的取余等于取余的积取余
while(n>0)
{
if(n%2==1)
result=result*a%b;//n是奇数的话就要多乘一次,原理和前面的二分求幂一样
n=n/2;//二分
a=a*a%b;//积的取余等于取余的积取余
}
return result;
}
******************************************************************************
25.筛选法求素数
筛选法求素数小题
用筛法求素数的基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束。
代码如下:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define N 10000//N的大小可以根据需要变化
int a[N];//利用数组的下标记录要判断的数字
void is_sushu()
{
memset(a,0,sizeof(a));//对数组a进行初始化为0,不是素数的标记为1,剩下为0的就是素数了
a[1]=1;//1既不是素数也不是合数,先标记为0
for(int i=2; i<=sqrt(N); i++)
{
if(a[i]==0)//如果i是素数
{
for(int j=2; j*i<=N; j++) //循环标记的范围是i*j<N
{
a[i*j]=1;//如果i是素数,那么i*j肯定不是素数
}
}
}//最终所有非素数都标记为1,素数都标记为0
}
- void init()
- {
- a[1]=1;
- for(int i=2;i*i<maxn;i++)
- {
- if(!a[i])
- for(int j=i+i;j<maxn;j+=i)
- a[j]=1;
- }
- }
*******************************************************************************
26.巴什博弈:
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,
后者取胜。因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,
如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者
肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。
代码如下:
#include<stdio.h>
int main()
{
int t,sum,n;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&sum,&n);
if (sum % (n + 1))
printf("Win\n");
else
printf("Lose\n");
}
return 0;
}
******************************************************************************
27.矩形的个数
在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形。
while(scanf("%f%f",&a,&b)!=EOF)
{
printf("%.0f\n",(a+1)*a*(b+1)*b/4);
28.蔡勒公式(根据日期计算出周几)
W=[C/4]-2C+y+[y/4]+[26(m+1)/10]+d-1 (其中[ ]为取整符号)
W是所求日期的星期数.
如果求得的数大于7,可以直接对7取余,不过周日就输出为0了。
如果求得的数小于0,可以加上7的倍数,直到结果大于零小于7为止
c是公元年份的前两位数字,
y是已知公元年份的后两位数字;
m是月数,
d是日数.
方括[ ]表示只截取该数的整数部分。
所求的月份如果是1月或2月,则应视为前一年的13月或14月.
所以公式中m 的取值范围不是1-12,而是3-14.
模板代码:
int Change(int year,int month,int day)//根据日期判断出星期几
{
if(month==1||month==2)
{
month+=12;
year--;
}
int c=year/100;
int y=year%100;
int m=month;
int d=day;
int W=c/4-2*c+y+y/4+26*(m+1)/10+d-1;
if(W<0)
return (W+(-W/7+1)*7)%7;
return W%7;
}
29.数字与数字数组与字符型数字数组的转换问题
数字temp(长度为n) 数字数组num[n-1] 字符型数字数组str[n-1]
1.将数字转换成数字数组
memset(num,0,sizeof(num));
for(i=n-1;i>=0;i--){
num[i]=temp%10;
temp=temp/10;
}
2.将数字数组转换成数字
temp=0;
for(i=0;i<strlen(num);i++)
temp=temp*10+num[i];
3.将数字转换成字符型数字数组
memset(str,0,sizeof(str));
for(i=n-1;i>=0;i--){
str[i]=temp%10+'0';
temp=temp/10;
}
4.将字符型数字数组转换成数字
temp=0;
for(i=0;i<strlen(str);i++)
temp=temp*10+(str[i]-'0');
5.将数字数组转换成字符型数字数组
memset(str,0,sizeof(str));
for(i=0;i<n;i++)
str[i]=num[i]+'0';
6.将字符型数字数组转换成数字数组
memset(num,0,sizeof(num));
for(i=0;i<strlen(str);i++)
num[i]=str[i]-'0';
7.STL
sscanf(str+start,"%d%n",&v,&n);start+=n;return v;
//此处的意思是从str+start开始讲字符转化为数字赋值给v,一共转化了n个字符(有几个数字字符就转化成///多少数字,)
30.位 运 算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。运位算包括位逻辑运算和移位运算,位逻辑运算能够方便地设置或屏蔽内存中某个字节的一位或几位,也可以对两个数按位相加等;移位运算可以对内存中某个二进制数左移或右移几位等。
计算机内部是以补码形式存放数值的。C语言提供了六种位运算
假设a,b为整型的数据,并且设a=15(等于二进制数00000000 00001111),b=80(等于二进制数 00000000 01010000)
a的补码:00000000 00001111
b的补码:00000000 01010000
————————
a&b: 00000000 00000000 a&b=0x0
a|b : 00000000 01011111 a|b=0x5f
a^b : 00000000 01011111 a^b=0x5f
~a : 11111111 11110000 ~a=0xfff0
位运算应用口诀
清零取反要用与,某位置一可用或
若要取反和交换,轻轻松松用异或
1.“按位与”运算符&
运算规则:参加运算的两个运算量,如果两个数相应位的值都是1,则该位的结果值为1,否则为0。即:0 & 0 =0;0 & 1 =0;1 & 0 =0;1 & 1 =1。
(1)将某些二进制位屏蔽掉(保留一个数据中的某些位)。
如果要使整数k的低四位置零,保留其它位。用位与运算即可,将的高字节与0相与,低字节与1相与;
代码如下:unsigned int_set(unsigned int k)
{k=k&0x1110;
Return(k);}
例】00101010 01010010&11111111 11110000=00101010 01010010。
结论:任何二进制位与0能实现置0;与1保持原值不变
(2)判断一个数据的某一位是否为1。
如判断一个整数a(2个字节)的最高位是否为1,可以设一个与a同类型的测试变量test,test的最高位为1,其余位均为0,即int test=0x8000。
【例】 0100010011111110&1000000000000000=0 说明最高位为0;
1100010011111110&1000000000000000=1000000000000000 说明最高位为1;
例如一个数 and 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数.
2.“按位或”运算符|
常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
运算规则:参加运算的两个运算量,如果两个数相应位的值都是0,。即:0 | 0 =0;0 | 1 =1;1 | 0 =1;1 | 1 =1
把一个数据的某些位置为1。
如果把a的第10位置为1,而且不要破坏其它位,可以对a和b进行“按位或”运算,其中b的第10位置为1,其它位置为0,即int b=0x400。
【例】00100000 01010010|00000010 00000000=00100010 01010010。
3.“按位异或”运算符^
运算规则:参加运算的两个运算量,如果两个数的相应位的值不同,则该位的结果值为1,否则为0。即:0 ^ 0 =0;0 ^ 1 =1;1 ^ 0 =1;1 ^ 1 =0
应用举例:
(1)把一个数据的某些位翻转,即1变为0,0变为1。
如要把a的奇数位翻转,可以对a和b进行“按位异或”运算,其中b的奇数位置为1,偶数位置为0,即int b=0xaaaa。
【例】a的补码:00000000 01010010
b的补码: 01010101 01010101
^ -------------------
结果的补码: 01010101 00000111
(2)交换两个值,不用临时变量。
【例】a=3,b=4。想将a和b的值互换,可以用以下三条赋值语句实现:
a=a^b;即:a=3^4=7(0011^0100=0111)
b=b^a;即:b=4^7=3(0100^0111=0011)
a=a^b;即:a=7^3=4(0111^0011=0100)
不用temp交换两个整数
void swap(int x , int y)
{
x ^= y;
y ^= x;
x ^= y;
}
编写对字符串进行密钥匙异或加解密程序
有了加密程序(a^b),相应的就应该有解密程序。解密程序是加密程序的逆过程,这里的加密和解密程序是完全相同的,原因是(a^b)^b=a。
4.“按位取反”运算符~
移位运算符:
左移、右移运算实现将一个数的各个二进制位向左向右移若干位。
1.左移运算符<<
运算规则:对运算符<<左边的运算量的每一位全部左移右边运算量表示的位数,右边空出的位补0。
【例】a<<2表示将a的各位依次向左移2位,a的最高2位移出去舍弃,空出的低2位以0填补。
例:char a=0x21;
则a<<2的过程 0010 0001〈〈2 = 1000 0100;即 a<<2的值为0x84。
左移1位相当于该数乘以2,左移n位相当于该数乘以2n。
乘法运算转化成位运算 (在不产生溢出的情况下)
a * (2^n) 等价于 a<< n
2. 右移运算符>>
运算规则:对运算符>>左边的运算量的每一位全部右移右边运算量表示的位数,右边低位被移出去舍弃掉,空出的高位补0还是补1,分两种情况:
(1)对无符号数进行右移时,空出的高位补0。这种右移称为逻辑右移。
(2)对带符号数进行右移时,空出的高位全部以符号位填补。即正数补0,负数补1。这种右移称为算术右移。
右移1位相当于除以2,同样,右移n位相当于除以2n。
除法运算转化成位运算 (在不产生溢出的情况下)
a / (2^n) 等价于 a>> n
取模运算转化成位运算 (在不产生溢出的情况下)
a % (2^n) 等价于 a & (2^n - 1)
循环移位的实现。
如将一个无符号整数x的各位进行循环左移4位的运算,即把移出的高位填补在空出的低位处。
可以用以下步骤实现:
(1)将x左移4位,空出的低4位补0,可通过表达式x<<4实现。
(2)将x的左端高4位右移到右端低4位,可通过表达式x>>(16-4)实现。由于x为无符号整数,故空出的左端补0。
(3)将上述两个表达式的值进行按位或运算,即:
y=(x<<4) | (x>>(16-4));
x 0010 1111 0010 0001
x<<4 1111 0010 0001 0000
x>>(16-4) 0000 0000 0000 0010
y 1111 0010 0001 0010
unsigned rol ( unsigned a,int n)
{ unsigned b ;
b=(a<<n) | (a>>(16-n)) ;
return(b);}
计算绝对值
int abs( int x )
{ int y ;
y = x >> 31 ;//二进制最高位
return (x^y)-y ; //or: (x+y)^y
}