进制转换:
为什么要使用二进制、八进制 、十六进制?
因为现在的CPU只能识别高低两种电流,只能对二进制数据进行计算
二进制数据虽然可以直接被CPU识别计算,但是不方便书写、记录,所以
把二进制数据转换成八进制是为了方便记录到文档
随着CPU不断发展位数不停增加,由早期的8位ID发展到现在的64位,因此
八进制不再满足需求,所以发展出了十六进制,由于历史原因八进制还不能完全
地退出历史舞台
十进制转二进制:
求余法:用2(转几进制就对几求余)对数据求余,记录余数,然后继续对商求余,直到商为0结束,过程中产生的余数就是该数据的二进制(逆序)。
127%2 1
63%2 1
. .
. .
. .
0
01111111
求权法:从高位到低位,数据 - 2^(n-1),如果能减,第n位就是1,否则就是0
137
- 128 64 32 16 8 4 2 1
1 0 0 0 1 0 0 1
手算:
练习1:输入一个正整数以及m,显示该正整数的m(m>=2)进制,超过十进制用字母表示10A 11B 12C 13D... 求差值的方法 'A'+bits[i]-10
#include
int main(int arg,const char* argv[])
{
int n=0,m=0;
printf("输入一个n以及m:");
scanf("%d %d",&n,&m);
char bits[32]={},cnt=0;
while(n)
{
bits[cnt++]=n%m;
n/=m;
}
for(int i=cnt-1;i>=0;i--)
{
if(bits[i]<10)
{
printf("%hhd",bits[i]);
}else
{
printf("%c",'A'+bits[i]-10);
}
}
}
二进制转十进制:
每位的2^(n-1)求和
1001 1010 128+16+8+2 = 154
二进制转八进制:
低位开始,每三位二进制位对应一位八进制
二进制:1 001 101 110 010
八进制:1 1 5 6 2
二进制转十六进制:
低位起,每四位二进制对应一位十六进制
二进制:1 1011 0111 1010
十六进制: 1 B 7 A(10)
在C语言中:只要是以0开头的数据都是八进制,以0x开头的数据都是十六进制数据
%o 以八进制形式显示数据
%x 以十六进制形式显示数据
%#o %#x 以对应的格式显示不同进制
原码、反码、补码:
原码:数据的二进制就是所谓的原码
反码:
正数的反码就是原码 -10 --> 10001010
负数的反码是原码除符号外,其它位按位求反(聊的一直是二进制的)11110101
*** 补码: 数据在内存中都是以补码形式存储
正数的补码就是原码
负数的补码:
1、先把数转换成二进制的原码
2、原码的符号位不变,其它按位求反得到反码
3、反码+1得到补码
-127 --> 1111 1111--> 1000 0000 --> 1000 0001
原码 反码 补码
%hd 0000 0000 1000 0001==129
补码转数据:
无符号补码直接转成十进制
有符号最高位是0,说明是正数,也直接转换成十进制
有符号且最高位是1:
1、补码-1得到反码
2、反码符号不变,按位求反得到原码
3、原码转换成十进制
1111 1111 补码 (有符号)
1111 1110 反码
1000 0001 原码 (-1)
位运算符:
& | ~ ^ >> <<
A & B 按位相与
10101101 0xAD
01101110 0x6E
--------
00101100 0x2C
A | B 按位相或
10101101 0xAD
01101110 0x6E
--------
11101111 0xEF
~A 按位求反
10101101 0xAD
01010010 0x52
A ^ B 按位异或 相同为0,相异为1
10101101 0xAD
01101110 0x6E
--------
11000011 0xC3
A << n 把A的补码向左移n位,右边补0,左边丢弃
10101101 << 4
11010000 0xD0
A >> n 把A的补码右移n位,右边丢弃,左边补符号位
10101101 >> 4
11111010
练习2:输入一个整数,把它的4~7位设置为1010,其它不能变
xxxxxxxx xxxxxxxx xxxxxxxx 1010xxxx
num & ~(0xf<<4) | (oxA<<4)
思考:输入两个整数,把A的4~7位设置为B的3~6位,其它位不能变
函数:
一段具有某项功能的代码的集合,是c语言中'管理代码'的最小单位
把代码分成一个个函数,可以方便地管理和调用代码
函数分类:
标准库函数:
C语言标准委员会为C语言以函数形式提供的一套基础功能,被封装在libc.so库中
使用时要包含头文件,函数(参数)即可调用标准库函数
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
功能:把字符串转换成整数
int isalnum(int c);
功能:判断c是不是数字、字母字符
int isalpha(int c);
功能:判断c是不是字母字符
int isdigit(int c);
功能:判断c是不是数字字符
int islower(int c);
功能:当c是小写字母字符时返回真
int isupper(int c);
功能:当c是大写字母字符时返回真
int toupper(int c);
功能:把字符转换成大写字符
int tolower(int c);
功能:把字符转换成小写字符
#include
int abs(int j);
功能:返回j的绝对值
以下函数被封装在libm.so库中
double pow(double x, double y);
功能:求x的y次幂
double fabs(double x);
功能:求浮点型数据的绝对值
double sqrt(double x);
功能:返回x的平方根
double floor(double x);
功能:返回小于等于x的最大整数
double ceil(double x);
功能:返回大于等于x的最小整数
#include
time_t time(time_t *t);
功能:返回自1970-1-1 0:0:0到当前时间多了多少秒
time(NULL)
int system(const char *command);
功能:调用系统命令
int rand(void); srand(time(NULL));
功能:返回一个随机整数 printf("%d\n",rand());
void srand(unsigned int seed);
功能:种随机种子
练习3:获取10个范围[100,1001)的随机数
[a,b)
rand()%(b-a)+a
rand()%901+100
练习4:随机出一注双色球彩票号码
红球6个:1-33 %33+1
蓝球一个:1-16 %16+1
#include
#include
#include
int main(int arg,const char* argv[])
{
srand(time(NULL));
char red[6]={},cnt=0,i=0;
while(cnt<6)
{
int num=rand()%33+1;
for(i=0;i { if(num==red[i]) { break; } } if(i==cnt) { red[cnt++]=num; } } printf("red:"); for(i=0;i<6;i++) { printf("%d ",red[i]); } printf("blue: %d\n",rand()%16+1); } 系统函数:(底层不是函数) 是操作系统以函数接口形式提供的一套功能, 内存管理、信号管理、文件IO、文件管理、进程管理、进程通信、线程管理、线程同步、'网络通信'(最为重要) 第三方库函数: 由第三方提供的,一些开源的收费的代码 msdn MD5 验证 JSON 序列化和反序列化 glog 日志记录 自定义函数: 为了更好地管理代码,减少冗余把代码封装成函数 注意:一个函数尽量控制在50行以内,要求一个函数一个功能 1、函数声明;函数声明的目的是为了告诉其他代码该函数的调用格式 返回值类型 函数名(类型1 形参名1,类型2 形参名2,...); 1.C语言中函数名全部小写,用下划线分隔 2.如果不需要参数时,建议写void,不要空着 3.如果不需要返回值,也写void,但是return后不能跟数据 隐式声明: 当调用函数之前没有声明和定义,编译器会猜测函数的格式,参数列 表会根据调用时提供的实参(数据)来猜测,返回值会猜测成int类型; 注意:函数定义如果在函数调用之前,可以省略函数声明; 2、函数定义: 返回值类型 函数名(类型1 形参名1,类型2 形参名2,...) { 函数体 return val; } 3、函数调用: 函数名(实参1,实参2,...); 注意:返回值会放在调用位置,可以立即打印显示,或者也可以用变量记录下来 #include //函数声明 int func(int num); int main(int arg,const char* argv[]) { // 函数的调用 int num = func(100); func(num); } //函数定义 int func(int num) { printf("我被调用了%d\n",num); return 10; }