C/C++笔记(一) 2015/8/15
2015-08-15 11:17
429 查看
1.C语言中左值和右值的区别
左值可以放在赋值符左边的值,右值是放在赋值符右边的值。 左值,没有内存实体的左值是存在的 右值,可以有内存实体,也可以没有内存实体(寄存器),a+1,&a,右值都在寄存器。
2.调试、下断点
断点:可以中断程序执行,观察内部过程 GPU,显卡的处理器
3.const和define的区别
const会进行类型转换,而define不会,只是的替换
#define K 100.0 const int Knum = 100.0; //赋值号会自动进行数据类型转换 void main() { printf("%d\n", K); printf("%d", Knum); }
4.printf的容错机制
printf的容错机制,第一个错误,第二个会连带这错误,而且printf也不会进行类型转换 `printf("%d, %d\n", 10.9, 10);`结果两个数都是错的,而换成两行,则10就会正常输出 //printf按照%d,%u,按照你指定的方式解析二进制
unsigned int data1 = -1; //二进制数 printf("%u\n", data1); //二进制数据,%d,有符号十进制 printf("%d\n", data1); //%u无符号十进制
5.变量的赋值就是拷贝二进,内存之间不能直接拷贝,必须通过CPU
常量必须初始化,const常量只有在初始化的时候是左值。
6.指针的本质
指针是一种数据类型,类型决定了大小(步长),决定了二进制数据的解析方式
void main8()
{ //指针是一种数据类型,类型决定了大小(步长),决定了二进制数据的解析方式int num = 100;
double *p1 = # //这里只是把num的地址赋给了p1,而num并没有进行类型转换
int *p2 = #
float *p3 = #
printf("%f\n", *p1); //乱码
printf("%d\n", *p2); //可以
printf("%f\n", *p3); //不可以,没有进行类型转换0.00000
getchar();
}
手机号使用long long int存数
7.float存储
浮点数按指数(阶码)方式存储 阶码分为三大部分,符号位s,幂数e,系数x 1.第31个bit为符号位,为0表示整数,为1表示负数(32-bit为单精度,64-bit浮点数为双精度); 2.第30~23bit,共8bit为幂数,其读数值用e表示,以2为底; 3.第22~0bit,共23bit作为系数,视为二进制纯小数,假定该小数的十进制值为x;
浮点数的值用十进制表示为
(-1)^s*(1+x)*2^(e-127)
符号位的代码推演
float fl1 = 10.0; float fl2 = -10.0; printf("%p, %p\n", &fl1, &fl2);
10.0的十六进制41200000 二进制0 100 0001 0 010 0000 0000 0000 0000 0000
-10.0的十六进制c1200000 二进制1 100 0001 0 010 0000 0000 0000 0000 0000
结论第32个bit是符号位
系数的代码推演
float fl1 = 10.0; float fl2 = 11.0; float fl3 = 5.0; printf("%p, %p, %p\n", &fl1, &fl2, &fl3);
10.0的十六进制41200000 二进制0 100 0001 0 010 0000 0000 0000 0000 0000 11.0的十六进制41300000 二进制0 100 0001 0 011 0000 0000 0000 0000 0000 10 100 0001 0 1010 +130(130-127) 1.010*2^3 11 100 0001 0 1011 +130(130-127) 1.011*2^3
幂数的代码推演
float fl1 = 1.0; float fl2 = 2.0; float fl3 = 0.5; printf("\n%p,%p,%p", &fl1, &fl2, &fl3);
1.0的十六进制3f800000 二进制0 011 1111 1 000 0000 0000 0000 0000 0000 2.0的十六进制40000000 二进制0 100 0000 0 000 0000 0000 0000 0000 0000 0.5的十六进制3f000000 二进制0 011 1111 0 000 0000 0000 0000 0000 0000 1.0 011 1111 1 0000 127 1.000*2^0 2.0 100 0001 0 0000 128 1.000*2^1 0.5 100 1111 0 0000 126(e-127) 1.000*2^(-1)
8.为什么使用补码
补码的优势是运算速度快 例一个字节大小的 1 ,-3 相加 1的原码: 0000 0001 -3的原码:1000 0011 第一步,转换成减法,求绝对值, 看那个数大 第二步 绝对值的大数减小数 得到0000 0010 第三步 判断符号位 得到1000 0010, -2 使用补码 1的补码: 0000 0001 -3的补码: 1111 1101 两个数相加 1111 1110 1111 1110 的原码是1000 0010 就是-2 再例如 3和-1相加 3的补码: 0000 0011 -1的补码: 1111 1111 两个数相加 10000 0010 多的1舍弃,得到0000 0010 0000 0010 的原码还是0000 0010 就是2 利用进位巧妙的把符号位放到运算里来,大大加快了计算的效率
9.位运算
与 & 0&0->0 0&1->0 1&0->0 1&1->1 或 | 0|0->0 0|1->1 1|0->1 1|1->1 异或 ^ 0^0->0 0^1->1 1^0->1 1^1->0 相同为0,不相同为1 使用异或交换数据,避免溢出的风险 unsigned char ch1 = 15; //0000 1111 unsigned char ch2 = 255;//1111 1111 ch1 = ch1^ch2; //ch1 = 1111 0000 ch2 = 1111 1111 ch2 = ch2^ch1; //ch2 = 0000 1111 ch1 = 1111 0000 ch1 = ch1^ch2; //ch1 = 1111 1111 ch2 = 1111 0000 位取反 ~ ~0 = 1 ~1 = 0 !0 = 1是逻辑运算符不是位运算符 unsigned char ch1 = ~0; ~0之后 1111 1111 unsigned int int1 = ~0; ~0之后 1111 1111 1111 1111 1111 1111 1111 1111 左移 << 0001<<1 -->0010 0001<<2 -->0100 //相当于每次乘以2 int num = 1; printf("%d\n", num << 1); //打印的值是2,但是num的指没有改变 printf("%d\n", num << 2); //打印的值是4,但是num的指没有改变 printf("%d\n", num); //打印的值是1 printf("%d\n", num <<= 2); //打印的值是4,num的值改变 <<= 相当于+= printf("%d\n", num); //打印的值是4 右移 >> 0100>>1 -->0010 0100>>2 -->0001 //相当于每次除以2
与:某一段清零
或:指定的字符置一
异或:指定的字符反转
10.求一个数的二进制中1的个数
利用与操作来求 例如 100 1100100 3个1 100-1=99 1100011 100&99=96 1100000 少了一个1 +1 96-1=95 1011111 96&95=64 1000000 少了一个1 +1 64-1=63 0111111 64&63=0 0000000 少了一个1 +1 代码实现 for (; num; num = num&(num-1)) wei++; 递归 int getwei3(int num) { if (num == 0) return 0; else return 1 + getwei3(num&(num - 1)); }
11.求一个数的补码和原码
求补码因为一个数在内存中就是按照补码的方式存的 所以1的二进制是0000 0000 0000 0000 0000 0000 0000 0001 -1的二进制是1111 1111 1111 1111 1111 1111 1111 1111 我们构造一个数 1000 0000 0000 0000 0000 0000 0000 0000 把这个数与1或者-1位求与就可以得到这个数的这一位是什么,然后再把1或者-1左移一位,就是到了第二位的值,以此类题 int num = 1; int data = 1 << 31; for (int i = 1; i <= 32; i++) { printf("%c", (data&num ? '1' : '0')); num <<= 1; if (i % 4 == 0) printf(" "); } 递归的写法是 void buma(int n, int cnt) { int data = 1 << 31; if(cnt == 0) return; if(cnt %4 == 0) printf(" "); printf("%c", (data&n ? '1' : '0')); n <<=1; --cnt; buma(n,cnt); }
求原码
根据原码和补码的转换规则,正数的原码和补码一样,负数的原码和补码的转换规则是: 原码->补码:符号位不变,其余位取反+1 补码->原码:符号位不变,其余位取反+1 例如num = -1; num = ~num +1;//这是全部按位取反,再加一,但是符号位也取了反 num = num | (1<<31);//这是把符号位再重新置为1 //然后在按位把这个数读出来 代码就是: if (num < 0) { num = ~num + 1;//根据补码求原码 num = num | data; } for (int i = 1; i <= 32; i++) { printf("%c", (data&num ? '1' : '0')); num <<= 1; if (i % 4 == 0) printf(" "); }
反码:
-1的原码 1000 0001 反码 1111 1110 补码 1111 1111 所以一个数的反码就是这个数的补码-1 代码: if (num < 0) { num -=1; } for (int i = 1; i <= 32; i++) { printf("%c", (data&num ? '1' : '0')); num <<= 1; if (i % 4 == 0) printf(" "); }
补码求原码 正数不变 负数的话取反+1在重置符号位
补码求反码 正数不变 负数的话-1
相关文章推荐
- C++ 遍历所有文件和文件夹,建立文件夹
- 【四】C++函数的升级(一)--内联函数
- C++ 内存分布
- Majority Element && Majority Element II
- 八皇后问题的相关C++代码解答示例
- C++11的特性
- C++ Primer : 第九章 : 顺序容器的操作以及迭代器失效问题
- C++ Primer 学习笔记与思考_5 bitset你用的正确吗?
- 关于C++中返回值是数组类型失败的问题
- VC++模态对话框和非模态对话框
- C++在设计和使用智能指针
- C语言宏定义和宏定义函数
- #ifdef #endif 简要说明
- C++规定有四个运算符 =, ->, [], ()不可以是全局域中的重载(即不能重载为友员函数)理解。
- [笔记] C语言 轻量级字符串操作 函数 CpyString,CpyBytes,CatString,StrLen
- 堆排序(非递归版)-- c语言实现
- C语言-scanf与printf的格式控制
- 【C语言经典实例】-选择排序
- OC语言-06-OC语言-block与protocol
- 关于C++中常量的理解