美文网首页C语言
C 语言 运算符 全网最全整理

C 语言 运算符 全网最全整理

作者: 不会编程的程序圆 | 来源:发表于2020-03-28 01:14 被阅读0次

    C 语言 运算符 全网最全整理

    码字不易,对你有帮助 点赞/转发/关注 支持一下作者

    微信搜公众号:不会编程的程序圆

    看更多干货,获取第一时间更新

    想看更好的排版,可以看原文
    点击查看原文

    思维导图


    image

    目录


    @[toc]

    正文


    一 算数操作符

    +

    -

    *

    /

    %: % 左右两边的数必须都为整数

    二 移位操作符

    >> : 右移

    <<: 左移

    例1:b = 20

    image

    例2:b = -4

    img

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-APrIn3AF-1585038906075)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

    注意1:

    左移直接在空的地方补0 如例1

    右移有两种情况:

    1.逻辑位移 补0

    2.算数位移 补1 如例2(一般都是这种情况)

    注意2:

    移位操作符,不要移动负数位,这是标准未定义。

    如:num >> -1//error

    三 位操作符

    & (按位与) | (按位或) ^(按位异或)

    例3:按位与

    img

    例4:按位或

    img

    例5:按位异或

    img

    例6:异或的应用——交换两个值的内容

    方法1:

    int a,b,c;
    c = a;
    a = b;
    b = c;
    

    方法2:(如果a,b很大可能会溢出)

    int a,b;
    a = a + b;
    b = a - b;
    a = a - b;
    

    方法3(异或法):

    int a, b;
    a = a^b;
    b = a^b;
    a = a^b;
    

    例7:怎么求一个二进制位中1的个数

    #include<stdio.h>
    int CountOneBit(unsigned int n){//解决负数无法计算问题,这种运算运算的是补码
      int count = 0;
      while(n){//类比十进制中每位数的求法
        if(n%2 == 1)
          count++;
        n/=2;
      }
      return count;
    }
    int main(){
      int n = 0;
      int num_1 = 0;
      printf("请输入一个数:");
      scanf("%d",&n);
      num_1 = CountOneBit(n);
      printf("%d的二进制序列中有%d个 1",n,num_1);
    }
    

    unsigned的作用:

    unsigned就是将这个二进制数最高位的符号位变成计数位。下面我们举个例子帮大家理解一下

    如果我们输入的是-1

    -1%2 == -1

    -1/2 = 0

    这样输出的count为0

    但是我们知道-1的补码是11111111111111111111111111111111

    这样我们的代码就局限在正整数

    如果加上unsigned 虽然我们输入的是-1 但是程序计算是是按照 unsigned int 的最大值,这样就避免了这个问题

    更多位运算相关示例: https://github.com/hairrrrr/linux.ccode/tree/master/Bit/ClassCode/2020-1-7%EF%BC%888%EF%BC%89

    四 赋值操作符

    =

    a = b = c

    它的意义是将c的值赋给b,再将b的值赋给a。其实这样理解不够准确,其实应该这么写:

    a = (b = c)

    先将c的值赋给b 然后将这个整体,即b的值赋给a

    五 复合赋值符

    += -= *= \= %= >>= <<= &= |= ^=

    六 单目操作符

    \-

    =

    &(取地址)

    sizeof(操作数的类型长度)

    ~ (对一个数的二进制位按位取反)

    -- ++(前置,后置)

    * (解引用)

    (类型)(强制类型转换)

    例8:!的应用

    应用!与flag来判断情况做出选择

    if(flag){

    flag为真进入循环;

    }

    if(!flag){

    flag为假进入循环;

    }

    printf函数打印格式

    %#p 0XCCCCCC

    %p 00CCCCCCC

    %x cccccc

    %X CCCCCC

    1
    
    int a = 0; 
    
    sizeof(a)=4
    
    sizeof(int) = 4
    
    sizeof a    √
    
    sizeof int   ×
    
    2
    
    sizeof求数组大小    sizeof(arr)
    
    sizeof求数组元素个数  sizeof(arr)/sizeof(arr[0])
    
    切记!!!sizeof不能再函数内部求指针数组的大小
    
    3
    
    int  a = 10;
    
    short s =3;
    
    printf('%d\n",sizeof(s = a+4));
    
    printf("%d\n",a);
    
    printf("%d\n",s);
    
    输出: 2     10      3
    
    赋值并不会将类型一同赋予左值
    
    sizeof在编译阶段就已经运行结束了(sizeof 被 换成 2)
    
    而s = a + 4要到生成可执行文件之后才会完成
    
    编译(.c) -- 链接(.exe)
    
    4  
    
    小心细节问题。进入函数后 ch实际上变成了指针变量。
    
    img

    例9:~ 的应用

    若想完成一下操作:
    
    15      00001111
    
    将从右数第4位变成0 ,应该如何操作?
    
    a = (1<<4-1)     00001000
    
    b = ~(a)            11110111
    
    b&15                00000111
    
    所以可以这么写:
    
    a &= (~(1<<4-1));
    
    如何变回来呢?
    
    00001000   1<<4-1
    
    00000111 |  (1<<4-1) 即可
    

    七 关系操作符

    >

    >=

    <=

    !=

    ==

    注意:不要将 ‘ == ’ 写成 ‘ = ’

    八 逻辑操作符

    &&

    ||

    例11 &与&&的差异:

    img
    例12 这个题值得思考 img

    在&&的判断中如果一边位假(0)那么程序就会停止向后面判断。所以++b与d++并没有执行

    在 || 的判断中如果一边为真,则停止继续向下判断。(如:++a || b++ || c)

    补充:

    img img img

    九 条件操作符

    a > b ? a : b

    十 逗号表达式

    a,b,c,d,.....n

    逗号表达式整体的值等于最后一个表达式的值

    例13 思考题

    int main() {
        int a = 0; 
        int b = 1, c = 2;
        a = (a = b, b += c, c--);
        printf("case1:%d\n", a);
    
        a = 0,b = 1, c = 2;
        a = (a < 0, a++, b = a);
        printf("case2:%d\n", a);
    
        a = 0, b = 1, c = 2;
        a = (a<0, b<a);
        printf("case3:%d\n", a);
    
        a = 0, b = 1, c = 2;
        if (a = b + 1, c = a / 2 - 1, c == 0)
            printf("case4:%d\n", c);
        }
    
    img

    另一种代码书写方式:

        //一般情况
        a = get_val();
        count_val(a);
        while (a > 0) {
            //业务处理
            a = get_val();
            count_val(a);
        }
        //应用逗号表达式
        while (a = get_val(), count_val(a), a > 0) {
            //业务处理
        }
    

    合理应用逗号表达式可以简化代码。

    11 其他

    1. [] 下标引用操作符

    对于数组 arr[5] = {1,2,3,4,5}

    我们一般的用法是:

    arr[0],arr[1],arr[2].....其中arr[0]就代表访问数组中第一个元素,arr[1]代表访问第二个以此类推

    学习了指针之后我们知道:

    arr代表数组首元素的地址。

    arr[0],arr[1],arr[2]...我们可以改写成:arr,(arr+1),(arr+2)..... (arr可以理解为*(arr+0))

    进一步思考:

    (arr+1)可以改写成(1+arr)

    那么arr[1]可否写成1[arr]呢?答案是肯定的。

    所以我们就有了一下结论:

    1[arr] == arr[1] == *(arr+1) == *(1+arr)

    事实上,无论哪一种写法,程序再最终编译的时候都会转化为:*( arr+1)

    2. ( ) 函数调用操作符

    例14.有参数调用

    int add(int x, int y){
        return x+y;
    }    
    int main(){
        int a = 1;
        int b = 2;
        printf("%d",add(a,b));
    }    
    

    例15.无参数调用

    void test(){
        printf("看到这里的都是人才!!!\n");
    }
    int main(){
        test();
    }
    

    3.访问一个结构的成员

    . (结构体.成员名)

    -> (结构体指针 -> 成员名)

    例16.

    struct Stu{
        char name[20];
        int age;
    }stu;
    int main(){
        stu = {"张三",20};
        struct Stu *ps = &stu;
        //下面三种写法都是正确的
        printf("%s  %d\n",stu.name,stu.age);
        printf("%s  %d\n",(*ps).name,(*ps).age);
        printf("%s  %d\n",ps->name,ps->age);
    }
    

    12 表达式求值

    1. 隐式类型转换

    • C的整型算术运算总是至少以缺省整型类型的精度来进行的。
    • 为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

    整型提升的意义:
    表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
    因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长 度。
    通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令 中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转 换为int或unsigned int,然后才能送入CPU去执行运算。

    整型提升方法:

    正数的整型高位补充0 负数补充1

    例17.整型提升示例

    注:char是有符号的

    img

    补充:字符类型的反码(1字节)及其表示的值

    img

    总结:

    char 的值范围是:-128 ~ 127

    unsigned char 值的范围是:0 ~ 255

    例18.整型提升在程序中的证明

    int main()
    {
        char a = 0x41;
        char b = 0xFF;//0xFF -> 255  11111111
        int c = 0xb6000000;
        if (a == 0x41) {//正数原码补码一致,整型提升补码不变
            printf("a\n");
            printf("%d %c\n", a, a);
        }
        if (b == 0xFF) {
            printf("b\n");
        }
        //在判断 b==0xFF 时 要对b进行整型提升
        //b  11111111  ->   11111111  11111111  11111111  11111111  而 0xEF的补码依然是11111111 所以这两个补码时不同的
        printf("%d %c\n", b, b);
        //输出时 依然要对b进行整型提升 
        // 11111111 -> 补码:11111111  11111111  11111111  11111111 
        //反码:11111111  11111111  11111111  11111110
        //原码:10000000  00000000  00000000  00000001  即:-1
        if(c==0xb6000000)
            printf("c\n");
        return 0;
    }
    

    例子20.整型提升的再一次证明

    img

    2. 算数转换

    如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类 型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

    long double 8byte

    double 8byte

    float 4byte

    unsigned long int 4byte

    long int 4byte

    unsigned int 4byte

    int 4byte

    如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算

    附:各类型变量在内存中占的字节(32位)

    int main() {
        printf("%d\n", sizeof(char));//1
        printf("%d\n", sizeof(int));//4
        printf("%d\n", sizeof(unsigned int));//4
        printf("%d\n", sizeof(long));//4
        printf("%d\n", sizeof(unsigned long));//4
        printf("%d\n", sizeof(long long int));//8
        printf("%d\n", sizeof(float));//4
        printf("%d\n", sizeof(double));//8
        printf("%d\n", sizeof(long double));//8
    }
    

    3. 操作符属性

    1. 操作符的优先级

    2. 操作符的结合性

    3. 是否控制求值顺序

    在 Github 上看更全的文章目录:

    https://github.com/hairrrrr/C-CrashCourse

    这个系列文章的代码都会上传上去,欢迎 star


    以上就是本次的内容。

    如果文章有错误欢迎指正和补充,感谢!

    最后,如果你还有什么问题或者想知道到的,可以在评论区告诉我呦,我可以在后面的文章加上你们的真知灼见。

    关注我,看更多干货!

    我是程序圆,我们下次再见。

    相关文章

      网友评论

        本文标题:C 语言 运算符 全网最全整理

        本文链接:https://www.haomeiwen.com/subject/ifbduhtx.html