C/C++笔记(一) 2015/8/15

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值