C语言操作符与表达式小结

c语言操作符和表达式小结

本篇文章主要简述c语言操作符的一些基本用法,以及一些典型的问题的辨析。

目录

算数操作符

C语言中算数操作符包括:

+ - * / %

值得注意的是,在两个整数除法运算时, / 执行整除运算;在两个浮点数除法运算时, / 进行浮点型除法运算。在进行取模运算时, % 只接受整形数,不接受其他类型的数。

位移操作符

C语言中位移操作符包括:

 右移操作符 >> 左移操作符 <<

位移操作符的作用是,讲一个数值在二进制层面上,将它的位进行向左或是向右的移动。向左移动的过程当中,最前面的几位将会被丢弃,而后面将会按照丢弃的位数进行补0。向右移动的过程当中,后面的几位将会被丢弃,前面将会补1(在正数情况下)。右移操作时,若移动的数是负数,将进行逻辑移位,前面回补1。
这里写图片描述
*使用位移运算符时,向右移动n位,相当于除以 2^n;向左移动n位,相当于乘以2^n。
*位移运算比算数运算更加高效。
*在使用位移运算符时,通常不移动负数,例如:a<<-5。因为编译器没有对这类操作有详细的定义,在使用中应该避免这样用。

位操作符

位操作符有:

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

位操作符的使用是按照位来运算的,拿按位异或来说,上下对其的两个位进行异或运算,相同为0,不同为1。设 a = 0110 1110, b = 0010 1011。

小练习题

给定一个整数,返回这个整数的二进制形式的1的个数。

#include<stdio.h>
#include<process.h>
int main()
{
    int value = 0;
    int count = 0;
    scanf_s("%d", &value);
    while (value != 0)
    {
        if (value < 0)
        {
            value = -value;
             count = count + 1;// 负数的符号位加一
        }
        if ((value % 2) != 0)// 模2就相当于二进制表达剪掉一位
        {
            count = count + 1;
        }
     value = value >> 1;//向右位移一位
    }
    printf("这个数有%d个1\n", count);
    system("pause");
    return 0;
}

这里写图片描述
这里写图片描述
十进制层面:15 % 2 = 1,7 % 2 = 1, 3 % 2 = 1, 1 % 2 = 1;
二进制层面 : 1111>>1=0111,0111>>1=0011,0011>>1=0001,0001>>1=0000;

赋值运算符

赋值运算符,是将等号=右边的值储存于等号左边的值。
例如: a = b + 1;
这里需要注意的是,不建议进行连续赋值操作。虽然在语法上它是可行的,但是减弱了代码的可读性,使得调试和阅读产生了影响。
例如:r = s + ( t = u - v) / 3 可以拆成: t = u - v; r = s + t / 3;
而后者明显比前者更好理解。

复合运算符

复合运算符有如下:

+=  -=  *=  /=  %=  <<=  >>=  &=  ^=  !=    

复合运算符可以减少代码的书写量,可以更好的偷懒,另外编译器也可以产生紧凑的代码。
例如: y+(x/2-10+f(z)) = y+(x/2-10+f(z)) +1; 可写成 y+(x/2-10+f(z)) += 1;
编译器算前者要调用两次f(z)函数,而后者只需要一次f(z).

单目操作符

单目操作符如下:

!  ++   -(负号)   &   sizeof  ~  --  +(正号) *(指针)  (类型)

* 这里主要说说sizeof,sizeof可以用来判断变量和类型的大小,它的单位是字节(byte)。
当它判断类型时要加括号,例:sizeof(int),判断变量时可以不加括号。
在判断表达式长度的时候,sizeof( a = b + 1);对其整体进行判断,并不对其进行计算。
*(类型)操作符被称之为强制类型转换。如(float)a,这个操作符有很高的优先级,在对表达式使用的时候要用括号括起来,以免产生错误。
* 自增运算符需要注意的问题,++i,表示先加后用, i++,表示先用后加。

#include<stdio.h>
#include<process.h>
int main()
{
    int i = 0, a = 0, b = 0;
    a = i++;
    b = ++i;
    printf("a = %d, b = %d\n", a, b);
    system("pause");
    return 0;
}

这里写图片描述

关系操作符

关系操作符如下:

>  >=  <  <=  !=  ==

这里需要注意的是:在进行while(),if()判断的时候,将==号错写成=号。
例如: if(x==5) 错写成 if(x=5)
以上在编译器编译的时候并不会报错,但程序的逻辑是错误的,所以建议将其写成:
if ( 5 == x) 数字在前,变量在后。

逻辑操作符

&&  ||

逻辑操作符存在一个行为:短路求值
其表述如下:&&操作符的左操作符总是首先进行求值,如果它的值为真,然后就对右操作数进行求值。如果左操作数的值为假,那么右操作数就不必求值,因为整个表达式肯定为假;同理||操作符如果做操作数为真,那么整个表达式就为真。

小练习题

这是一道非常典型的题。

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

答案
程序执行到第二行的时候,碰到a++,这时是先用后加,所以0与右操作数,表达式为假,然后
0&&d++还是假,程序结束。根据短路求值,只有a++执行了操作,b和d都没有执行,所以结果如图所示。请读者朋友自行换掉注释来算得答案。

条件操作符

条件操作符如下:

   ?  :

条件操作符很特殊,它是一个三目操作符。它所表达的是 if……else的关系。

if(a>5)                         
    c[2*b + e(d/5)] = 1;
else
    c[2*b + e(d/5)] = 2;
           ||
c[2*b + e(d/5)] = a > 5 ? 1 : 2;

它也可以减少代码量,少打一次表达式,就少了出错的可能性。

逗号操作符

逗号操作符如下:

    代码1 , 代码 2 ,……, 代码 n

逗号表达式使得编译器自左向右,依次处理代码,整个式子的表达式的值依照最后一个逗号为准。
使用逗号操作符可以做到一些骚操作,例如对于条件,和循环语句的简化。

    a = f1(x);
    b = f2(x + a);
    for (c = f3(a, b); c > 0; c = f3(a, b))
    {
        a = f1(++x);
        b = f2(x + a);
    }
        ||
    for (c = f3(f1(x), f2(x + a);); c > 0; c = f3(f1(++x), f2(x + a)))

小练习题

下面的程序将打印几次呢?

#include<stdio.h>
#include<process.h>
int main()
{
    int i = 0, j = 0;
    for (i = 0, j = 0; j = 0; i++, j++)
    {
        printf("hehe\n");
        j++;
    }
    system("pause");
    return 0;
}

答案是零次。因为初始条件中 i = 0 , j = 0,所以最终的判定是最后一个逗号后的表达式。for的终止条件是 j = 0。所以程序不执行。

表达式求值

1.整形提升
在表达式求值的过程中,字符型和短整型操作数在使用之前会被转换为普通的整形。

char a, b, c;
    a = b + c;// b,c先被提升为普通整形,然后将计算结果截断,再传给a.

2.优先级顺序
下面这段话是《c和指针》里的:
两个相邻操作符的执行顺序由他们的优先级决定。如果他们的优先级相同,它们的执行顺序由它们的结合性决定。除此之外,编译器可以自由的决定热河顺序表达式进行求值,只要他不违背逗号、&&、||和条件操作符所施加的限制。

小练习题

这段代码会输出什么?

#include<stdio.h>
#include<process.h>
int fun()
{
    static int count = 1;
    return ++count;
}
int main()
{

    int a;
    a = fun() - fun()*fun();
    printf("%d\n", a);
    system("pause");
    return 0;
}

当初我在这里想的是4 - 2 * 3 = -2;但是实际结果确是 -10。这里或许执行了 2 - 3 * 4 = - 10;
在书上说,不同编译器对函数调用的顺序是不同的,如果它们的执行具有副作用,比如一些I/O任务或是修改全局变量,那么函数顺序调用的不同可能会产生不同结果。
所以这里也可能执行了 2 - 4 * 3 = -10;

谢谢大家在百忙之中,阅读本片文章,这篇文章的大部分内容来自于《c和指针》的学习。

PS:第一个小练习题已修改,原题不能处理负数。

猜你喜欢

转载自blog.csdn.net/H_Strong/article/details/79690496