20210729operator

#define _CRT_SECURE_NO_WARNINGS 1

//移位操作符:适用于整形数据
//只能移动正整数位,移动负整数是错误的写法。

// << 左移操作符  

//#include<stdio.h>
//int main()
//{
//
//
//    //对于整数的二进制有三种表达形式:原码,反码,补码
//
//    //正整数 原码 反码 反码都一样
//    int a = 5; //存放的的是补码,printf打印的是原码
//    //    00000000000000000000000000000101 //原码
//    //    00000000000000000000000000000101 //反码
//    //
//    int c = -1;
    10000000000000000000000000000001 //原码
    11111111111111111111111111111110 //反码
    11111111111111111111111111111111 //补码
//    //负整数 - 原码 - 直接按照数字的正负写出二进制序列
//    //反码 - 原码的符号位不变,其他位 按位取反
//    //补码 - 反码 加 1
//
//    //整数
//    int b = a << 1;//左移操作符:左边丢弃,右边补零
//    printf("a = %d\n",a);// 5
//    //移位后,a 不变
//    //00000000000000000000000000000101 //补码
//    //移位操作符:移动的是二进制位
//    //00000000000000000000000000001010//移位后 
//    printf("b = %d\n",b);// 10
//
//    //负数
//    int d = c << 1;
    11111111111111111111111111111111 //补码
 11111111111111111111111111111110 //移位后
//    printf("d = %d\n", d);//打印的是原码  -2
 11111111111111111111111111111110//补码
 11111111111111111111111111111101//反码 = 补码 - 1
 10000000000000000000000000000010//原码 = 反码符号位不变,其余按位取反
//    return 0;
//}

//  >>右移操作符 :右移有2种方式

//1.逻辑移位 右边丢弃,左边补零。

2.算术移位 右边丢弃,左边用原该值的符号位填充。(最常用)

//#include<stdio.h>
//int main()
//{
//    int a = 5;//因为 a = 5 是整数,即 原反补 三码相同
//    int b = a >> 1;
//    //    00000000000000000000000000000101 //原码
//    //    00000000000000000000000000000010 //移位后的原码()
//    printf("b = %d\n",b);// 2
//
//    int c = -1;//根据 -1 的值写出原码 - 反码 - 补码
//    //10000000000000000000000000000001 //原码
//    //11111111111111111111111111111110 //反码
//    //11111111111111111111111111111111 //补码
//    int d = c >> 1;
//    //11111111111111111111111111111111 //算术移位:右边丢弃,左边用原该值的符号位填充。
//    //值不变   -1
//
//     //01111111111111111111111111111111 //逻辑移位: 右边丢弃,左边补零。
原码 00000000000000000000000000000001  值为 1
//    //值的符号都变了
//
//    printf("d = %d\n", d); //当前电脑 vs2013 运用的是算术右移
//    //打印的是原码 值为 -1
//    //10000000000000000000000000000001 
//    return 0;
//}

//位操作符:
// 都是按二进制位(补码)进行逻辑计算
// & 按位与   
// | 按位或
// ^ 按位异或


// & 按位与   双1出1,有0出0

//#include<stdio.h>
//int main()
//{
//    int a = 3;// 3 为正整数
//    //00000000000000000000000000000011 //原码 = 反码 = 补码
//    int b = -2;
//    //10000000000000000000000000000010 //原码
//    //11111111111111111111111111111101 //反码
//    //11111111111111111111111111111110 //补码
//    int c = a & b;
//    //00000000000000000000000000000011 // a 补码
//    //11111111111111111111111111111110 // b 补码
//    //00000000000000000000000000000010 // c 的补码
//    //符号位为0;正整数 所以 三码相同
//    printf("c = %d\n",c);
//    //%d 说明我们打印的是 有 符号数
//    //%u 说明我们打印的是 无 符号数
//    return 0;
//}


// | 按位或  有1出1,双0出0
//#include<stdio.h>
//int main()
//{
//    int a = 3;
//    //00000000000000000000000000000011 //补码
//    int b = -2;
//    //11111111111111111111111111111110 //补码
//    int c = a | b;
//    //00000000000000000000000000000011 // a 补码
//    //11111111111111111111111111111110 // b 补码
//    //11111111111111111111111111111111 // c 的补码
//    printf("c = %d\n", c);// -1
//    return 0;
//}

// ^ 按位异或  相异出1,相同出0
//#include<stdio.h>
//int main()
//{
//    int a = 3;
//    int b = -2;
//    int c = a ^ b;
//    //00000000000000000000000000000011 // a 补码
//    //11111111111111111111111111111110 // b 补码
//    //11111111111111111111111111111101 // c 的补码
//
//    //10000000000000000000000000000011 // c 的原码
//    printf("c = %d\n", c);//  -3
//    return 0;
//}

//
//不创建变量,交换两个变量 (a^a=0,0^b=b)
//#include<stdio.h>
//int main()
//{
//    int a = 0;
//    int b = 15;
//    a = a^b;
//    b = a^b;
//    a = b^a;
//    printf("%d\n", a);
//    printf("%d\n", b);
//    return 0;
//}

//连续赋值

//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = 10;
//    int x = 0;
//    a = x = b + 1;//(建议)x=b+1;  a=x; 
先计算b+1;再赋给a,再赋给b                  
//    printf("%d", a);
//    return 0;
//}


//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    //1.
//    a = a >> 1;
//    //2.
//    a >>= 1;
//
//    //1.
//    a = a + 10;
//    //2.
//    a += 10;
//    return 0;
//}


//单目操作符(unary operator)
//#include<stdio.h>
//int main()
//{
//    // ! 逻辑反操作
//    int a = 5;
//    int b = !a;
//    printf("%d\n", b);//a=非零为真,!a==0 把真变为假,反之  a = 0    !a== 1
//    if (a != 0)//a为真,打印hehe
//    {
//        printf("hehe\n");
//    }
//    if (!a)//a为假,打印haha
//    {
//        printf("haha\n");
//    }
//    return 0;
//}


// &取地址  *解引用符  sizeof:
//#include<stdio.h>
//#include<string.h>
//int main()
//{
//
//    char array[10] = "abc";// 10个字节的内存
//    printf("%d\n",sizeof(array));// 10
//    printf("%d\n", sizeof array);//两者等价,因为sizeof操作符不是函数,所以可去括号
//                                 //如果括号里是类型:sizeof(int),此处括号不可省略
//                   //计算变量或者类型创建变量的内存大小,单位字节,和内存中存放什么没有关系
//    printf("%d\n", strlen(array)); // 3
//                 // strlen(arr) 遇到'\0',就定制计算
//                 // 且不能省略().
//
//    int arr[10] = { 0 };
//    // arr //数组首元素地址
//    // &arr //取数组地址 == sizeof(arr) 中的 arr 都是代表整个数组
//    // &arr[0]//数组首元素地址
//    // &arr[9]//数组第10个元素地址
//    int a = 10;     
//    int* p = &a;
//    *p = 20;//*p仿作左边代表的是用来存放数值的空间
//    printf("%d\n", a);// 20
//    int b = *p;// *p放在右边代表的是存储的空间里存储的数值
//    printf("%d\n",b);//  20
//    return 0;
//}


//#include<stdio.h>
//int main()
//{
//    int a = 5;
//    short s = 10;
//    printf("%d\n", sizeof(s = a + 1));// 2  s是短整型,a+1=6,把这个整形放进短整型,放不下,发生截断
//                                      //最终的结果,归s负责,为short类型,算变量或者类型创建变量的内存大小,和内存中存放什么没有关系
//                                      //即为 2
//
//    printf("%d\n",s);// 10  sizeof不参与计算,直接计算出sizeof(short)拿走了,所以后面 a+1;根本就没机会运行,所以s还是10.
//    return 0;
//}

//  ~ 按位取反(包括符号)
//#include<stdio.h>
//int main()
//{
//    int a = 0;
//    //00000000000000000000000000000000
//    int b = ~a;
//    //11111111111111111111111111111111 //补码
//    printf("%d",b);// 原码= (补码 - 1)取反 (不包括符号位)
//    //10000000000000000000000000000001
//    // 值为 -1
//    return 0;
//}


//#include<stdio.h>
//int main()
//{
//    int a = 13;
//    //00000000000000000000000000001101 // a为正整数 三码一样,这是补码
//
//    // 1的补码
//    //00000000000000000000000000000001 
//
//    //1 << 1(1的补码向左移动一位)
//    //即:00000000000000000000000000000010 
//    a |= (1 << 1);//00000000000000000000000000001111//经由上两式子逻辑或之后,把 1101中的0改成了 1 ,即1111
//    printf("%d\n", a);// 值为 15
//    // 00000000000000000000000000001111
//
//    //00000000000000000000000000000010  1 << 1
//    //按位取反
//    //    11111111111111111111111111111101  &  00000000000000000000000000001111
//    a &= (~(1 << 1));//00000000000000000000000000001101
//    printf("%d\n", a); //13
//
//    
//    return 0;
//}

//前置加加/减减   后置加加/减减

//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = a++;//后置加加,先赋值,后加加
//    printf("%d\n",b);//10
//    printf("%d\n", a);//11
//    return 0;
//}
//

//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = ++a;//前置加加,先加加,后赋值
//    printf("%d\n",b);//11
//    printf("%d\n", a);//11
//    return 0;
//}

//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = a--;//后置减减,先赋值,后减减
//    printf("%d\n", b);//10
//    printf("%d\n", a);//9
//    return 0;
//}

//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = --a;//前置减减,先减减,后赋值
//    printf("%d\n", b);//9
//    printf("%d\n", a);//9
//    return 0;
//}

//  ()强制转换符
//#include<stdio.h>
//int main()
//{
//    int a = (int)3.14;
//    printf("%d\n",a);// 3
//    return 0;
//}


// &&  逻辑与 只关注真假
//#include<stdio.h>
//int main()
//{
//    int a = 1;
//    int b = 2;
//    int c=a&&b;
//    printf("%d\n",c);// a 和 b 都是非零,所以c为真 c == 1
//    return 0;
//}

// &&  逻辑或,有1出1,双零出零
//#include<stdio.h>
//int main()
//{
//    int a = 1;
//    int b = 0;
//    int c = a||b;
//    printf("%d\n", c);// a 是非零,所以c为真 c == 1
//    return 0;
//}

//  >=   <= 
//#include<stdio.h>
//int main()
//{
//    int age = 0;
//    scanf("%d",&age);
//    if ((age >= 10) && (age <= 30))
//    {
//        ;
//    }
//    if ((age >= 10) || (age <= 30))
//    {
//        ;
//    }
//    return 0;
//}


// 360 笔试题
//#include<stdio.h>
//int main()
//{
//    int i = 0, a = 0, b = 2, c = 3, d = 4;
//    i = a++ && ++b && d++; // a++ 先赋值再加加,a=0;所以为假,与任何数相与都为假。 所以 && ++b && d++ 没有执行
//                             //用完之后 a加加等于 1
//    printf("a = %d b = %d c = %d d = %d\n",a,b,c,d);//即输出位 1,2,3,4
//    return 0;
//}

//#include<stdio.h>
//int main()
//{
//    int i = 0, a = 1, b = 2, c = 3, d = 4;
//    i = a++ && ++b && d++; // a=1;所以为真, ++b先加后赋值,即b==3, d++先加后赋值,此时d=4
//    //用完之后 a=2,b= 3,c=3,d=5
//    printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);//即输出位 2335
//    return 0;
//}

//#include<stdio.h>
//int main()
//{
//    int i = 0, a = 1, b = 2, c = 3, d = 4;
//    i = a++ || ++b || d++; // a=1;所以为真, 或逻辑 只要一个为真,就是真,所以后面的|| ++b || d++ 都不执行
//    //用完之后 a=2,b= 3,c=3,d=4
//    printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);//即输出位 2234
//    return 0;
//}

//#include<stdio.h>
//int main()
//{
//    int i = 0, a = 0, b = 2, c = 3, d = 4;
//    i = a++ || ++b || d++; // a=0;所以为假,++b,先加后赋,b==3, 因为或逻辑只要一个为真,就是真,所以后面的 || d++ 都不执行
//    //用完之后 a=1,b= 3,c=3,d=4
//    printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);//即输出位 1334
//    return 0;
//}

//条件操作符  ()?():() 又称 三目操作符
//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = 20;
//    int c = (a > b) ? (a) : (b);// 如果a>b为真, 就返回a,否则返回 b
//    printf("%d\n",c);//a > b 为假,所以返回 b
//    return 0;
//}

//逗号表达式
//#include<stdio.h>
//int main()
//{
//    int a = 1;
//    int b = 2;
//    int c = (a > b/*只是执行一下*/, a = b + 10/* a == 12 */, a/* 12 */, b = a + 1/* 13 */);//从左往右计算,以为 最右边的式子 的 结果 为 整个式子的结果
//    printf("%d\n",c);// 13
//    return 0;
//}

//#include<stdio.h>
//int main()
//{
//    int a = get_val();
//    count_val(a);
//    while (a > 0)//while (a = get_val(),count_val(a);a > 0) //逗号表达式可以运用到循环中,从左往右计算
//    {
//        ;
//    }
//
//    return 0;
//}

//下标引用操作符[],函数调用操作符(),结构访问操作符


//下标引用操作符
//#include<stdio.h>
//int main()
//{
//    int  arr[] = { 1, 2, 3, 4, 5 };
//    int i = 0;
//    //arr[4]// 代表的是数组中第五个元素 5,等价于 *(arr+4)== *(4+arr)   和  4[arr].,说明这些式子支持交换律
//     // []是一个操作符,而 4 和 arr 是操作数
//
//    // *(arr+4) == *(4+arr) 意思是用 arr 的 起始地址 加上 4 ,找到下标为4 的元素
//    //该式子支持交换律
//    for (i = 0; i < 5; i++)
//    {
//        printf("%p\n",&arr[i],arr+i);//输出的数列arr中第 i+1 个元素的地址
//        //printf("%p\n",arr+i);//与上式子完全等价 
//    }
//    return 0;
//}

//函数调用操作符
// 能接受一个或者多个操作数;第一个操作数是函数名,其余操作数就是专递函数的参数
//
//#include<stdio.h>
//#include<string.h>
//
//void test()
//{
//    printf("hehe\n");
//}
//
//int main()
//{
//    char  arr[] = "hello world1";
//    strlen(arr);// 这里的小圆括号,是函数调用操作符,不可省略(strlen arr // error)
//    //strlen  函数的返回值是 size_t == unsigned int 无符号整形
//
//    printf("%u\n",strlen(arr));//   %u,表示打印无符号整形,%d 表示打印有符号整形
//    printf("%u\n", strlen("hello"));//函数调用操作符() ,不可省略
//
//
//    test();//函数调用操作符() ,不可省略.即使不传参,也是一样。
//
//    return 0;
//}


//结构访问操作符 . 例:结构体.c成员名   -> 指针型 : 结构体指针 -> 成员名

//#include<stdio.h>

自定义类型
//struct book
//{
//    char name[20];
//    float price;
//    char id[20];
//};
//void print(struct book* pb)
//{
//    //常用后者表示
//    printf("%s\n", (*pb).name);//printf("%s\n", pb->name);
//    printf("%f\n", (*pb).price);//printf("%f\n", pb->price);
//    printf("%s\n", (*pb).id);//printf("%s\n", pb->id);
//}
//int main()
//{
//    struct book b = { "z语言",48.5f, "ab12345" };
//
//    printf("%s\n",b.name);//printf("%s\n",b.name);
//
//    strcpy(b.name,"c");//改变 或 赋值 数据结构,需要通过 strcpy 函数
//    //因为数组名是地址,数据结构需要放在储存空间里
//    b.price = 50; // 但变量可以直接赋值
//
//    print(&b);
//
//    printf("%s\n", b.name);
//    printf("%f\n", b.price);
//    printf("%s\n", b.id);
//    return 0;
//}


//表达式求值的顺序

// 一部分有操作符的优先级和结合性决定。
//同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

//隐式类型转换 :偷偷的进行类型转换

//c的整形算术运算总是至少以缺省整形类型的精度来进行的
//为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为 整形提升。
//#include<stdio.h>
//int main()
//{
//    char a = 3;//char 1 byte 只能存放 8 bit
//    //000000000000000000000000 00000011 //补码 。 a 是正整数 三码相同 
//    //00000011 //数据截断(最低位)后的数据,也就是存入a的数据
//    char b = 127;
//    //000000000000000000000000 01111111 // 127的二进制位
//    //01111111 这是真正存入b的二进制位
//
//
//    // b 和 a 的值都被提升为普通整形,再进行加法运算,
//    //加法运算完以后,结果将被截断(整形存入字符类型),然后存储于c中
//    char c = a + b;
//    // a 和 b 如何相加   表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为 整形提升。
//    //00000011     整形提升是按照变量的数据类型的符号位来提升的。
//    //01111111     因为截断后的数据第一位是0,即为正,根据变量类型的符号位,来进行整形提升
                  // 无符号整形直接补0
//
//    //整形提升后
//    //000000000000000000000000 00000011 
//    //000000000000000000000000 01111111
//    //000000000000000000000000 10000010 // 加法运算完后,a+b
//    //再进行截断 10000010(补码) 这就是放进c的二进制位
//    //11111111111111111111111110000010(补码)  //整形提升:按照变量的数据类型的符号位(10000010)来提升的,所以补1,
//    printf("%d\n",c);// 打印原码 :100000000000000000000000 01111110  -126
//
//    //整形提升的意义
//    //表达式的整形运算要在CPU的相应运算器件内执行,CPU内整形运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU通用的寄存器的长度。
//
//    //    因此,即是两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整形操作数的标准长度。
//
//    //通过CPU(general-purpose CPU)是难以直接实现两个8字节直接相加运算(虽然机器指令中可能有这种字节相加的指令)。
//    //所以,表达式中各种长度可能小于 int 长度的整型值,都必须先转换为 int 或 unsigned int ,然后才能送入CPU执行运算
//    return 0;
//}

//案例 1
//#include<stdio.h>
//int main()
//{
//    char a = 0xb6;// 0xb6 二进制码 1011 0110 存入 a ;然后 0xb6 == a要进行比较,所以 a 要整形提升,按照变量的数据类型的符号位,即 1。所以补 1
//                  //111111111111111111111111 1011 0110 //整形提升后,很明显 a 与 0xb6 不相等,所以不打印 a
//    short b = 0xb6000;  // 与上式子同理,所以 b 也不打印
//    int c = 0xb6000000;//因为 c 本来就是整形,所以不用整形提升,即if (0xb6000000 == c)条件成立,所以可以打印 c
//    if (0xb6 == a)
//    {
//        printf("a");
//    }
//    if (0xb6000 == b)
//    {
//        printf("b");
//    }
//    if (0xb6000000 == c)
//    {
//        printf("c");
//    }
//    return 0;
//}


//案例 2
//#include<stdio.h>
//int main()
//{
//    char c = 1;//char 1 byte
//    printf("%u\n",sizeof(c)); // 1
//    printf("%u\n", sizeof(+c));// 4 要进行整形计算了,所整形提升,故32 bit,即4字节。也就说sizeof计算的是一个整形的大小 
//    printf("%u\n", sizeof(!c));// 1
//    return 0;
//}


//算术转换
//如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换 为另一个操作数的类型,否则操作就无法进行。

//寻常算术转换
// long double
// double
// float
// unsigned long int
// long int
// unsigned int
// int
//如果程序中出现上面其中2个类型,下面的要向上面的进行 算术转换
// 比如 出现 int 和 unsigned int, int 要转换成 unsigned int 进行运算——算术转换

//操作符的属性

//复杂表达式的求值有三个影响的因素
// 1. 操作符的优先级
// 2. 操作符的结合性
// 3. 是否控制求值顺序
// 两个相邻的操作符执行哪一个?取决于它们的优先级,如果两者的优先级相同,取决于它们的结合性。

//#include<stdio.h>
//int main()
//{
//    int a = 10;
//    int b = 20;
//    // 1. 优先级
//    int c = a + b*3;// *(乘) 的优先级比 + 的优先级要高,所以要先计算 a*3,在计算 + a
//    printf("%d\n",c);// 20*3+10= 70
//    // 2, 结合性
//    int d = a + b + 3; // + 的结合性 LR 从左往右计算
//    printf("%d\n", d);
//    // 3. 是否控制求值顺序
//    int e = a && b + 3;// 逻辑与 && 结合性 LR,如果 a为假的话,后面的式子,他就不会计算了,这就是控制求值顺序
//                       // 逻辑或 ||  条件操作符(三目操作符)()?():()  逗号表达式 , 也是一样的。
//                                                                       //结果为最后一个表达式的结果
//    printf("%d\n", e);
//    return 0;
//}


//一些问题表达式  (重点: 最好能确定唯一的计算路径,如果不能,说明这个表达式就是存在问题的)


// 代码1. a * b + c * d + e * f  绝对不能写出这种的表达式,如果非要写,写好()因为它的优先级最高,
                                                                           // 比如 ,我想先计算a * b ,后c * d,再e * f 
                                                                          //即((a * b )+ c * d )+ e * f 
//代码在计算的时候由于*的优先级高,只能保证比+早,但是优先级并不能决定 三个*中哪一个早执行。

// 代码2. c + --c; // --优先级高,先--c,再加 c
// 但是 + 操作符的 左操作数的 获取,在 右操作数 之前 还是 之后 求值,我们不能确定,所以结果不可预测,是有歧义的
//左操作数的 获取,在 右操作数 之前 比如说 c = 1 表达式为 c(1)+--c(0)=1
//左操作数的 获取,在有 操作数 之后, c = 1  表达式为 c(0)+ --c(0)=0


// 代码3. 非法表达式
//#include<stdio.h>
//int main()
//{
//    int i = 10;
//    i = i-- - --i * (i = -3) * i++ + ++i;//error 错误写法,最好能确定唯一的计算路径。
//    printf("i = %d\n", i);//在不同的编译器里,输出也不同
//    //在vs2013 中输出为 4
//    return 0;
//}

// 代码 4.
#include<stdio.h>
int fun()
{
    static int count = 1;
    return ++count;
}
int main()
{
    int answer;
    answer = fun() - fun() * fun();// 错误在于,不确定这三个 fun()函数,谁先调用
    //        1       2       3  按照这个顺序调用 2 - 3 *4 = -10

    //        2       3       1   3 - 4 * 2 = -5

    //        3       2       1   4 - 3 * 2 = -2
    printf("%d\n",answer);
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dark And Grey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值