C语言程序设计——操作符

一、算术操作符

                  +             -          *          /          %

Tips:1.%操作符的两个操作数必须为整数,其他几个可以用于整数和浮点数

          2./操作符若两个操作数为整数,则执行整数除法,求商;只要有浮点数执行的就是浮点数除法。

二、移位操作符

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

移位操作符针对的是二进制位。

右移操作符:

1.算术右移:右边丢弃,左边补原符号位(一般情况)

2.逻辑右移:右边丢弃,左边补0

再重复一次,整数以补码的形式储存在内存当中,正数的原码、补码、反码相同,负数的反码是原码除符号位按位取反,补码是反码+1。 而移位操作都是针对其存储二进制位进行操作。

左移操作符:

左边丢弃,右边补0

※对于移位操作符,不要移动负数位,这个标准是未定义的。 (num>>-1  ——错误的)

特殊要求运算:左移n位等价于乘以2^n,右移则等价于除以2^n 。

三、位操作符

               

位操作符按位与按位或按位异或
符号&|^
效果全1则1,有0则0全0则0,有1则1相同为0,不同为1

操作数必须为整数

特殊要求运算(X为0或1任意一个):

按位与

1)指定一个或多个二进制位清零(0 & X=0)。将原数按位与一个数字,该数字清零位为0,其余位为1 。

按位或

1)将指定二进制位变为1(1 | X=1)。将原数按位或一个数字,指定位为1,其余位为0 。

按位异或

1)指定位翻转(1 ^ X = !X , 当X=1时!X=0,当X=0时!X=1)(0 ^ X = X)。将原数按位异或一个数字,指定位为1,其余位为0 。

2)将两个值互换(X ^ X=0)

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

        除此之外还有加减法(存在溢出风险)互换两个值:

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

小练习—— 统计num的补码中有几个1

int main()
{
    int num = 0;
    int count = 0;
    scanf("%d",&num);
    
    while(num)
    {
        if(num % 2 == 1)
            count++;
        num = num / 2;
    }
    printf("%d\n",count);
    return 0;
}

 这种方法很容易想到,但是缺点在于无法统计负数。

int main()
{
    int num = 0;
    int count = 0;
    scanf("%d",&num);
    
    int i = 0;
    for(i=0;i<32;i++)
    {
        if(i == ((num >> i) & 1))
            count++;
    }
    printf("%d\n",count);
    return 0;
}

这种方法考虑了负数在内,但是算法不够简单。

int main()
{
    int num = 0;
    int count = 0;
    scanf("%d",&num);
    
    while(num)
    {
        count++;
        num = num & (num - 1);
    }
    printf("%d\n",count);
    return 0;
}

对于二进制计算,减1意味着两种结果:①其他位不变,最右位由1变为0;②其他位不变,最后一位由0变为1,同时向上借位。这样将减前减后两个数字进行一次与运算,必然会清掉二进制位中的一个1。不可谓不精妙!

四、赋值操作符

 注意点:1)赋值语句执行顺序是从右向左。

a = x = y+1;         <=>        x = y+1;        a = x;

 2)复合赋值符(+=   -=  等)。

五、单目操作符

符号名称及作用
!逻辑反操作
-负值
+正值
&取地址
sizeof操作数的类型长度(以字节为单位)
~对一个数的二进制位按位取反
--前置、后置--
++前置、后置++
*间接访问操作符(解引用操作符)
(类型)强制类型转换

 逻辑非(!)

                !a:当a为0时,结果为1;当a为非零时,结果为0。

取地址操作符(&) 解引用操作符(*)

int main()
{
    int a = 10;
    int* p = &a; //取地址操作符
    *p = 20; //解引用操作符
    return 0;
}

 取长度(大小)操作符( sizeof() )

                sizeof 计算变量或类型所占空间的大小,单位是字节。

void test(char ch[])
{
    printf("%d\n",sizeof(ch)); //4 因为ch为首元素地址,32位机器地址大小位4个字节
}

int main()
{
    int a = 10;
    char c='r';
    char* p =&c;
    int arr[10]={0};
    char ch[10]={0};

    printf("%d\n",sizeof a);//4
    printf("%d\n",sizeof(int));/4

    printf("%d\n",sizeof(c));//1
    printf("%d\n",sizeof(char));//1
    
    printf("%d\n",sizeof(p));//4
    printf("%d\n",sizeof(char*));//4

    printf("%d\n",sizeof(arr));//40
    printf("%d\n",sizeof(int [10]));//40
    
    test(ch)
    return 0;
}

 注意点:

int main()
{
    short s = 0;
    int a = 10;
    printf("%d\n",sizeof(s = a + 5));
    printf("%d\n",s);
}

 以上代码输出结果为2  , 0 。非常关键的一点就是,sizeof中的表达式不参与运算,而只进行判断最后结果类型,所以这里sizeof计算short类型大小并且表达式没有运算,s仍然为0 。

按位取反(~) 

对任意一个数字m,有 m + ~m = -1, m | ~m = -1成立。

前置、后置++/--

int main()
{
    int a = 10;
    int b = 10;
    printf("%d\n",++a); //11 前置++,先++,后使用
    printf("%d\n",b++); //10 后置++,先使用,后++
    return 0;
}

强制类型转换(        (type)        )   

int a = (int)3.14;  //a = 3 

六、关系操作符

>        <        >=        <=        !=        == 

七、逻辑操作符

&&        逻辑与                                        ||        逻辑或

int main()
{
    int i = 0,a=0,b=2,c=3,d=4;
    i = a++ && ++b && d++; //a=1,b=2,c=3,d=4
    //i = a++ || ++b || d++; //a=1,b=3,c=3,d=4
    return 0;
}

 当&&运算时,若出现一个假,则其后表达式不再运算;

当||运算时,若出现一个真,则其后表达式不再运算。

八、条件操作符

 三目操作符:  expr1 ? expr2 : expr3

九、逗号表达式

 逗号表达式,就是用逗号隔开的多个表达式。逗号表达式的执行顺序是自左向右,整个表达式的结果是左后一个表达式的结果。

int ()
{
    int a = 1;
    int b = 2;
    int c = (a > b,a=b+10,a,b=a+1);  //c=13
    return 0;
}

十、下标引用、函数调用和结构成员

1.下标引用操作符——[ ] 

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

arr[9] = 10;   //  两个操作数是arr和9

2.函数调用操作符——( ) 

操作数:一个或多个操作数,包含函数名和参数。

3.访问一个结构的成员——       .    和   ->

结构体 . 成员名

//创建一个结构体类型 (struct)
struct Stu
{
    char name[20];
    int age;
    char id[20];
};

int main()
{
//使用struct Stu这和类型创建一个对象s1,并初始化
    struct Stu s1 = {"张三", 20 , "2022123456"}
    printf("%s\n",s1.name);
    printf("%d\n",s1.age);
    printf("%s\n",s1.name);

    return 0;
}

结构体指针 ->  成员名

//创建一个结构体类型 (struct)
struct Stu
{
    char name[20];
    int age;
    char id[20];
};

int main()
{
//使用struct Stu这和类型创建一个对象s1,并初始化
    struct Stu s1 = {"张三", 20 , "2022123456"}
    struct Stu* ps = &s1;

    printf("%s\n",ps->name);
    printf("%d\n",ps->age);
    printf("%s\n",ps->name);

    return 0;
}

表达式求值

隐式类型转换——整型提升

在C语言中,为了扩大精度,在算术运算和逻辑运算的过程中将表达式中的长度可能小于int型的整型值(short、char等)转换为int或unsigned,再进行运算,运算结束后结果被截断,存于原变量内。

整型提升过程:按原变量的符号为提升,即在左补符号位的数字直到长度达到int。

1:        00000001  =》00000000000000000000000000000001

-2:       111111110  =》11111111111111111111111111111110

 运算结束后,截断,即取原有长度而舍弃左边的多余位。

char a = 0xb6;

short b = 0xb600;

int c = 0xb6000000;

a == 0xb6;            //假

b == 0xb600;        //假

c == 0xb60000;    //真

当对char类型时,0xb6是一个十六进制的数字,是个正数,但是赋值给char类型后,其符号位成为了1,导致在是否相等的判断中,a变量整型提升,成为一个负数,此时a变量为0xffffffb6而判断数字为0x000000b6,二者不相等。

对于short类型同理。

对于int类型,因为没有整型提升的变化,所以逻辑等于两边的值二进制位相同(尽管他们所表达的值不同),所以判断为真。

char c = 1;

sizeof(c);  /1

sizeof(+c);  /4

sizeof(!c);  /4

可以通过sizeof看到整型提升确实在算术运算和逻辑运算中发挥了作用。

隐式类型转换——算术转换

在使用操作符时操作数类型不同且需要同一类型,即按照一定优先级改变某一操作数的类型。

long double > double > float > unsigned long int > long int > unsigned int > int

int a = 1;

float  = 2.0;

a + b;  //这里则会根据级别,将a由int变为float

 操作符的属性

1.优先级

有关优先级的问题,可以参考本人另一篇博客博客

2.结合性

即考虑从左向右结合(运算)或者从右向左结合。

3.是否控制求值顺序

a = b*c+d*e+f*g;

 对于该表达式运算路径不唯一,a = (b*c+d*e)+f*g 或a = (b*c)+(d*e)+(f*g)。在一些情况下可能造成歧义,应该避免。

a  =  (++i)+(++i)+(++i);

 对于该表达式,不同编译器运算结果不同,是非常不合理,无意义的表达式。对于诸如此类运算路径不唯一,可移植性极差的语句应该杜绝。

本文为学习C语言心得与笔记记录,部分举例来源于B站C语言教学up主鹏哥

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

犀利卓

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

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

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

打赏作者

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

抵扣说明:

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

余额充值