一篇文章带你了解C语言操作符

编辑: admin 分类: c#语言 发布时间: 2021-12-12 来源:互联网
目录
  • 操作符和表达式
  • 操作符
    • 算数操作符
    • 移位操作符
    • 位操作符
      • 位操作符的应用
      • 一道面试题小试牛刀
    • 赋值操作符
      • 复合赋值操作符
        • 单目操作符
          • 关系操作符
            • 逻辑操作符
              • 条件操作符
                • 逗号表达式
                  • 其他操作符
                  • 总结

                    操作符和表达式

                    我们在初始C语言已经大致了解了操作符,我们今天一起详细解剖操作符。

                    操作符

                    C语言操作符很多,但大致进行分类后,有以下几种操作符

                    //算数操作符
                    + - * / %
                    //移位操作符
                    <<    >>
                    //位操作符
                    &  |
                    //赋值操作符
                    =  += -= *= /= ...
                    //单目操作符
                    sizeof() ! ++  -- & * 
                    //关系操作符
                    > >= < <= ==
                    //逻辑操作符
                    && ||
                    //条件操作符
                    ?:
                    //逗号表达式
                     ,
                    //其他操作符
                    [] ()  ->  .   ...
                    
                    

                    算数操作符

                    算数操作符再常见不过,

                    加减乘除,取余。

                    + - * /操作符和我们数学上的一样。

                    值得注意的是

                    /

                    int c=10/3; 
                       c=10.0/3;
                       c=10/3.0; //c结果为3
                       (double)c=10.0/3; //能计算出小数值
                    

                    C语言中,/需要至少一个操作数为浮点数,才能使结果为浮点数,并且记得存在浮点数中。

                    %求余(取模)操作符

                    只能计算两个整型之间的结果,结果也为整型。

                    在这里插入图片描述

                    移位操作符

                    这里说的移位,指的是移动二进制位。

                    有左移,右移操作符。

                    <<左移操作符

                    向左移动二进制位

                    在这里插入图片描述

                    可以看到二进制左移后,a<<1a2倍,所以我们可以知道,左移一位,扩大2倍。

                    左移n位扩大2^n倍。

                    >>右移操作符

                    可想而知,右移操作符,也与左移效果类似,二进制位向右移动一位。

                    右边的二进制丢弃,右边的二进制位,并不是添像左移操作符一样添零,需要分情况讨论。

                    移位又分为算数移位和逻辑移位。

                    算数移位就是右移时,左边添加那一位是需要看二进制的符号位,添加。添加的哪一位和符号位相同。

                    逻辑移位就是不管左移还是右移操作,添加哪一位都是添0。

                    但我们需要移动一个负数时,显然逻辑移位会改变原数值得正负。

                    所以在一般的编译器下都采用算数移位。

                    在这里插入图片描述

                    可以看到右移操作原来的值缩小了2^n倍。

                    注意:左移和右移都要考虑移位后是否会溢出。

                    移位操作是针对移动正数位,

                    a>>-1这样移位错误,C语言未定义。

                    位操作符

                    位操作,有&(按位与) , |(按位或),^(按位异或)~(按位取反)。

                    位操作符顾名思义,是针对二进制位的操作,有两个操作数进行,二进制位进行操作运算。

                    这里我们的二进制位都是指的补码,因为一个数以补码的形式存放在内存中。

                    //   00000000 00000000 00000000 00100010
                    //   00000000 00000000 00000000 11010110
                    // & 00000000 00000000 00000000 00000010  
                    // | 00000000 00000000 00000000 11110110
                    // ^ 00000000 00000000 00000000 11110100 
                    
                    位操作符 作用 & 两操作数二进制位都为真(1)结果为真(1)否者为假(0) | 两操作数二进制位为假(0)结果为假(0)否者为真(1) ^ 一真(1)一假(0)结果为真(1),否者为假(0) ~ 二进制位按位取反,1变0,0变1

                    位操作符的应用

                    //尝试写一下这个代码
                    include <stdio.h>
                    int main()
                    {
                        int num1 = 1; //00000000 00000000 00000000 00000001
                        int num2 = 2; //00000000 00000000 00000000 00000010
                        num1 & num2; // 00000000 00000000 00000000 00000000
                        num1 | num2; // 00000000 00000000 00000000 00000011
                        num1 ^ num2; // 00000000 00000000 00000000 00000011
                        return 0;
                    }
                    

                    一道面试题小试牛刀

                    不创建新的变量,实现两个变量的交换。

                    //方法一
                    #include<stdio.h>
                    int main()
                    {
                     int a=3; // 00000000 00000000 00000000 00000011
                     int b=5; // 00000000 00000000 00000000 00000101
                     a=a^b;  //  00000000 00000000 00000000 00000110
                     b=a^b;  //  00000000 00000000 00000000 00000011
                     a=a^b;   // 00000000 00000000 00000000 00000101
                    }
                    

                    有趣的一道代码,利用^按位异或实现了两数的交换。

                    ^异或操作符的性质

                    a^a=0;

                    a^0=a;

                    经常利用这两条性质解题,写出优秀的代码!

                    //方法二
                    #include<stdio.h>
                    int main()
                    {
                      int a=3;
                      int b=5;
                      a=a+b;  //a=8
                      b=a-b; // b=3
                      a=a-b; // a=5
                    }
                    

                    求一个整数存储在内存中二进制1的个数

                    //方法一
                    #include<stdio.h>
                    int main()
                    {
                     int n=10;
                     int count=0;
                     while(n)
                     {
                     	if(n%2==1)
                     	{
                     		count++;
                     	}
                     	n>>=1;
                     }
                     printf("输入二进制位1的个数:%d",count);
                    }
                    

                    在这里插入图片描述

                    思考上面的代码是否存在问题

                    当n为负数时?

                    在这里插入图片描述

                    可以看到程序将会一直死循环下去。

                    我们优化一下!

                    //方法二
                    #include<stdio.h>
                    int main()
                    {
                     	int i=0;
                     	int count=0;
                     	int num=-3;
                     	for(i=0;i<32;i++)
                     	{
                     		if((num>>i)&1==1)   //移位并且判断最后一位是否为1
                     			count++;
                     	}
                    	return 0;
                    }
                    

                    在这里插入图片描述

                    每次都要进行32次循环,我们是否可以再次优化一下!

                    //方法三
                    #include <stdio.h>
                    int main()
                    {
                        int num = -1; // 10000000 00000000 00000000 00000001
                                  //补码  11111111 11111111 11111111 11111111
                        int i = 0;
                        int count = 0;//计数
                        while(num)
                        {                    
                            count++;          
                            num = num&(num-1);//丢弃最后一位1
                        }
                        printf("二进制中1的个数 = %d\n",count);
                        return 0;
                    }
                    
                    

                    在这里插入图片描述

                    上面这个代码是不是很神奇,一般人想不到,这就是代码的魅力!

                    赋值操作符

                    赋值操作符,我们再熟悉不过了。

                    我们可以通过赋值操作符,将一个变量改变成你想要的值!

                    #include<stdio.h>
                    int main()
                    {
                     	int weight=180;
                     	weight=125;  //不满意可以改变
                     	//连续赋值
                     	int a=13,b=0,c=0;
                     	a=b=c=6;
                     	//连续赋值操作缺点不易调试
                    }
                    

                    复合赋值操作符

                    += -= *= /= %= …

                    可以看到很多复合赋值操作符

                       a+=2; ===>   a=a+2;
                       a*3;  ===>   a=a*3;
                         //其他运算符一个道理
                       ....
                    

                    这边是复合赋值操作符,使用起来很简单,也很方便!

                    单目操作符

                    //单目操作符就是只有一个操作数的操作符!
                    +   -   !   sizeof()   ++  --  ~  *  (类型)
                    

                    + -

                    这里的+ -都是单目操作符,并不是算数操作符中的+-!

                        a=-5;  //-5这里的-指的是单目操作符!
                        b=+5; //+5 +可以省略!
                    


                    逻辑反操作符

                     while(a!=0)   //这里就是!逻辑反操作符
                     {
                     	count++;   //a不为0count++;
                     }
                     while(!a)
                     {
                      count++;   //a为0count++;
                     }
                    

                    sizeof

                    是否感到很诧异,sizeof居然是操作符!

                    sizeof是比较特殊的一个操作符,并不是函数!

                    我们知道sizeof可以计算一个变量和类型的所占空间内存大小!

                    int main()
                    {
                        int a = -10;
                        int* p = NULL;
                        printf("%d\n", !2);
                        printf("%d\n", !0);
                        a = -a;
                        p = &a;
                        printf("%d\n", sizeof(a));
                        printf("%d\n", sizeof(int));
                        printf("%d\n", sizeof a);      //这样写行不行?
                        printf("%d\n", sizeof int);//这样写行不行?
                    	return 0;
                    }
                    

                    在这里插入图片描述

                    可以看到当sizeof计算一个类型时,不添加括号,就会报错,然而计算一个变量的大小时却可以省略括号!

                    总结:sizeof计算类型所占内存大小时,括号不可省略。sizeof(类型),计算变量所占内存大小时,sizeof(变量),sizeof变量

                    将错误更改一下,看一下运行结果!

                    在这里插入图片描述

                    sizeof和数组

                    我们知道sizeof可以计算变量的空间大小,所以我们经常通过sizeof计算一个数组的元素个数!

                    公式:sizeof(数组)/sizeof(数组的一个元素)

                    #include <stdio.h>
                    void test1(int arr[])
                    {
                        printf("%d\n", sizeof(arr));//(2)
                    }
                    void test2(char ch[])
                    {
                        printf("%d\n", sizeof(ch));//(4)
                    }
                    int main()
                    {
                        int arr[10] = {0};
                        char ch[10] = {0};
                        printf("%d\n", sizeof(arr));//(1)
                        printf("%d\n", sizeof(ch));//(3)
                        test1(arr);
                        test2(ch);
                        return 0;
                    }
                    

                    问:
                    (1)、(2)两个地方分别输出多少?
                    (3)、(4)两个地方分别输出多少?

                    我们先通过自己计算一下!

                    计算结果!

                    (1)40 (2) 40 (3)10 (4) 10

                    而运行结果!

                    在这里插入图片描述

                    可以看到,运行结果并不是那样!

                    我们在思考一下这个结果,为啥结果会是4?

                    我们明明是将数组,直接传参过去 ,而通过sizeof计算的内存大小却不是,难道我们只传参了一个地址过去?

                    在这里插入图片描述

                    我们调试一下,发现就是假设的这样,数组传参并没有将整个数组传参过去,而是传参了一个指针!

                    而我们在x86也就是32位平台下,指针所占内存空间大小为4个字节。

                    ++ --

                     //前置++和--:
                        #include <stdio.h>
                        int main()
                        {
                            int a = 10;
                            int x = ++a;
                            //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
                            int y = --a;
                            //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
                            return 0;
                        }
                        
                        //后置++和--
                        #include <stdio.h>
                        int main()
                        {
                            int a = 10;
                            int x = a++;
                            //先对a先使用,再增加,这样x的值是10;之后a变成11;
                            int y = a--;
                            //先对a先使用,再自减,这样y的值是11;之后a变成10;
                            return 0;
                        }
                    

                    总结: 前置++,--先进行自加操作,再使用!

                    后置++,--先使用再进行自加操作!

                    关系操作符

                    > >= < <= == (判断是否等于) !=(判断不等于)

                    这些这是基本的关系操作符!

                    我们已经很常见了,我们看一下关系操作符的运行结果!

                    可以看到,当判断结果为真是,vs用1代表真,用0代表假。

                    在这里插入图片描述

                    注意:我们在测试,结果是否相等时,用==而不是赋值操作符=。

                    逻辑操作符

                    逻辑操作符,有逻辑与&&,逻辑或||

                    当我们要测试两个表达式结果时,如果要同时满足,使用逻辑与&&只需满足其中一个表达式结果时使用逻辑或||

                    我们要区分逻辑操作符和位操作符按位与&,按位或|区别!

                    #include<stdio.h>
                    int main()
                    {
                         int a=3;//00000000 00000000 00000000 00000011
                    	 int b=1;//00000000 00000000 00000000 00000001
                    	printf("%d\n",a&b);
                    	printf("%d\n",a|b);
                    	printf("%d\n",a&&b);
                        printf("%d\n",a||b);
                    			
                    return 0;
                    }
                    

                    在这里插入图片描述

                    位操作符和逻辑操作符截然不同,一个是对整数的二进制进行操作,另一个是对表达式的结果进行判断!

                    && 只有当两个表达式结果同时为真,结果才为真!

                    || 只有当两个表达式结果同时为假,结果才为假!

                    逻辑表达式的特性!

                    #include<stdio.h>
                    int main()
                    {
                     int a=3,b=5,c=6,i=0;
                     i=a++&&++b;
                     printf("%d %d\n",a,b);
                     i=a++||++b;
                     printf("%d %d\n",a,b);
                    return 0;
                    }
                    

                    在这里插入图片描述

                    我们可以看到,逻辑或||第二个表达式,并没有执行。

                    这是为什么呢!

                    总结: 逻辑与&&当执行到表达式结果为假,便停止执行,后面的表达式!

                    逻辑或||当执行到表达式结果为真,便停止执行后面的表达式!

                    这就是我们常说的逻辑短路特点!

                    条件操作符

                    exp1 ? exp2 : exp3

                    条件操作符通常由3个表达式构成!又叫(三目操作符)!

                    如果exp1表达式结果为真,执行exp2,否者执行exp3

                    可以看到与我们的判断语句if类似!

                    #include<stdio.h>
                    int main()
                    {
                       int a=5,b=3,max=0;
                       //if判断语句求最大值
                    	if(a>b)
                    	{
                    	 max=a;
                    	}
                    	else
                    	{
                    	 max=b;
                    	}
                    	//条件表达式
                    	a>b?max=a:max=b;
                    return 0;
                    }
                    

                    可以看到条件表达式的优点,可以大大的简化代码!

                    逗号表达式

                    exp1,exp2,exp3...expN

                    表达式之间用,分隔开,这就是逗号表达式。

                    表达式特点

                    #include<stdio.h>
                    int main()
                    {
                    	int a=2,b=3,c=5;
                    	int i=(a++,b++,c);
                    	printf("a=%d b=%d c=%d i=%d",a,b,c,i);
                    return 0;
                    }
                    

                    在这里插入图片描述

                    可以看到表达式i=(a++,b++,c);结果i=5也就是最后一个表达式c的值。

                    逗号表达式运算特点:

                    表达式从左往右依次计算,最后一个表达式的值,便是整个逗号表达式结果的值!

                    其他操作符

                    []下标引用操作符 ()函数调用操作符 . ->结构成员访问操作符

                    []下标引用操作符

                    操作数:一个数组名+一个索引值

                    int arr[10];//创建数组
                        arr[9] = 10;//实用下标引用操作符。
                          // [ ]的两个操作数是arr和9。
                    

                    既然是两个操作数,那么两个操作数可以交换位置吗?

                    在这里插入图片描述

                    可以看到arr[9]等价9[arr]

                    但是我们并不介意用9[arr]

                    ()函数调用操作符

                    ( ) 函数调用操作符
                    接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

                    #include <stdio.h>
                        void test1()
                        {
                            printf("hehe\n");
                        }
                        void test2(const char *str)
                        {
                            printf("%s\n", str);
                        }
                        int main()
                        {
                            test1();//实用()作为函数调用操作符。
                            test2("hello bit.");//实用()作为函数调用操作符。
                            return 0;
                        }
                    

                    . :结构体.成员名
                    ->:结构体指针->成员名

                    #include <stdio.h>
                    struct Stu
                    {
                        char name[10];
                        int age;
                        char sex[5];
                        double score;
                    };
                    void set_age1(struct Stu stu)
                    {
                        stu.age = 18;
                    }
                    void set_age2(struct Stu* pStu)
                    {
                        pStu->age = 18;//结构成员访问
                    }
                    int main()
                    {
                        struct Stu stu;
                        struct Stu* pStu = &stu;//结构成员访问
                        
                        stu.age = 20;//结构成员访问
                        set_age1(stu);
                        
                        pStu->age = 20;//结构成员访问
                        set_age2(pStu);
                        return 0;
                    }
                    

                    总结

                    本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注海外IDC网的更多内容!

                    【来源:http://www.1234xp.com/hwgf.html 转载请保留连接】