【C语言】 操作符详解

135 阅读6分钟

操作符(上)

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

1.算术操作符
      • / %

🔧+、-、*、/这四个运算符均可用于整数及浮点数的运算。

🔧 当使用/运算符时,如果两个操作数均为整型,那么执行整数除法,运算结果也为整型;如果两个操作数至少一个为浮点数,那么执行浮点数运算,运算结果 为浮点型。

🔧 %运算符只能用于两个整数相除,返回余数。

2.移位操作符

注:移位操作符的操作数只能是整数,一个整数在内存中存储的是补码,一位操作针对的是补码

1.左移操作: 左边抛弃、右边补0(相当于左移一位,乘以2)

image-20220522201622579

实际上,a在没赋值的情况下,自身的值不会发生变化

2.右移操作

🔧算术右移 (右边丢弃,左边补原来的符号位数)

🔧逻辑右移 (右边丢弃,左边不用考虑符号位数,直接用0补充)

到底是 算术右移还是 逻辑右移,取决于编译器,我们常见的编译器大多都是算术右移

image-20220522202413803

对于移位运算符还需要注意的一点是:不要移动负位数,这是标准未定义的,c语言并没有规定负移位数该怎么做,所以不能写成负数

3.位操作符

& //按位与

| //按位或

^ //按位异或

注:他们的操作数必须是整数

一个奇数(十进制)位与1的结果是1,一个偶数(十进制)位与1的结果是0

& ----同时1则为1,否则为0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9h9shO5w-1653740404383)(../../../../../picture/Snipaste_2022-05-22_20-29-55.png)]

| -----有1则1,否则为0

^ ---相同为0,相异为1

例题一 : 不能创建临时变量实现两个数的交换

#include<stdio.h>
 
int main()
{
    int a = 5;
    int b = 3;
    printf("交换前:a=%d  b=%d\n", a, b);
    //3^ 3 = 0
    //011^ 011 = 000
    //0 ^  5 = 5
    //000^ 101 = 101
    //3 ^ 5^ 3 =5
    a = a ^ b;            //3^5
    b = a ^ b;            //3^ 5 ^ 3 = 5
    a = a ^ b;            //3^ 5^ 5 = 3
    printf("交换后:a=%d  b=%d\n", a, b);
    return 0;
}

image-20220522204215855

4.赋值操作符

=

复合类型

+= a = a+ 1

-= a= a- 1

*= ....

/= ....

%=

&=

|=

^=

5.单目操作符

! 逻辑反操作

  • 负值

  • 正值

& 取地址

sizeof 操作数的类型长度(以字节为单位)

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

-- 前置、后置--

++ 前置、后置++

  • 间接访问操作符(解引用操作符)
  1. !

    //C语言中0表示假,非零表示真

    int flag = 0;
    //当flag为假的时候打印haha
    if (!flag)  //只需用上逻辑反操作符 ! 就能打印了
    {
        printf("haha\n");
    }
  1. &

    int a= 2;
    printf("%p",&a); //取出a的地址
    

3 . sizeof

    int a = 10;
    printf("%d\n", sizeof(a));   //计算a所占内存空间的大小为4个字节
    printf("%d\n", sizeof(int)); //计算int类型为4个字节
    int arr[5] = { 1,2,3,4,5};
    printf("%d\n", sizeof(arr));  // 数组名arr单独放在sizeof代表的是整个数组,
                                  //因为arr数组是int型且里面有5个元素,
                                  //int型大小是4个字节,所以总大小为20个字节
  1. ~
int a=0;
 
printf("%d\n",~a);
 
//  0000 0000 0000 0000 0000 0000 0000 0000  -因为0是正数,原反补相同
//  1111 1111 1111 1111 1111 1111 1111 1111  - 把0的补码每一位进行取反
 
//又因为要打印出来,得把补码转换成原码
//  1111 1111 1111 1111 1111 1111 1111 1111  - 补码
//  1111 1111 1111 1111 1111 1111 1111 1110  - 反码
//  1000 0000 0000 0000 0000 0000 0000 0001  - 原码
 
//  打印出来的结果为 -1

5 -- + +

#include <stdio.h>
int main()
{
    int a = 10;
    int m =++a;//先加后赋值
    int n =--a;//先减后赋值
    int x = a++;//先赋值后加
    int y = a--;//先赋值后减
    return 0;   
    }
  1. *解引用操作符

    int a=10;
    int *p=&a;
    *p=20;  // p是指针变量存的是a的地址,*p 解引用操作符通过p存放的地址找到a,并重新给a赋值成20; 
    printf("%d\n",a);   // 因此a最终的结果为20
    

6.关系操作符

<

<=

!= 用于测试“不相等”

== 用于测试“相等”

7.逻辑操作符

&& 逻辑与

|| 逻辑或

逻辑与与逻辑或只关注真假,不关注二进制位,非零为真

1&&2---->1 全真则真,一假则假(并且)

0 ||2---->0 一真则真,全假则假(或者)

笔试题:

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

解析:

(1) 首先执行a++,先使用a,a = 0即为假,则&&后边的表达式不进行计算,然后a自加可以得到 a = 1, b =2 ;c =3 ;d = 4

(2) 首先执行a++,先使用a,a为真,则进行||运算后,结果为真,故||后边不再进行计算,然后a自加可以得到,a = 2, b = 2, c =3, d = 4;

8.条件操作符

表达式1 ? 表达式2:表达式3

逻辑展示:

image-20220602194432197

举例:求两个数最大值

int a = 5;
int b = 8;
max = (a > b ? a : b);  //a如果大于b的话会把a赋值给max,如果a不大于b 的话则会把b赋值给max
printf("%d\n", max);

image-20220602194750183

9.逗号表达式

exp1, exp2, exp3, …expN

逗号表达式,就是用逗号隔开的多个表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

    int a = (1, 2, 3, 5);   //逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
                            //整个表达式的最后是5,5最终赋值给a
    printf("%d\n", a);

故可得 a = 5

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

[] () . ->

  1. 下标引用操作符

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

int arr[10] = { 1,2,3,4,5,6,7,8,9,10};  //创建数组
printf("%d\n", arr[5]);    //打印数组下标为5的元素

image-20220602195413838

arr[7] ----> *(arr+7) ---> *(7+arr) ---> 7[arr]

  1. ( ) 函数调用操作符
#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;
 }

image-20220602195906206

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

struct stu
{
    char name[20];
    int age;
};
int main()
{
    struct stu s1 = { "李四", 19 };
    printf("%s  %d\n", s1.name, s1.age);    // .是用来访问结构体成员的
    return 0;
}

image-20220602200347006

struct stu
{
    char name[20];
    int age;
};
int main()
{
    struct stu s1 = { "李四", 19 };,
    struct stu* p = &s1;
    printf("%s  %d", p->name, p->age);      //结构体指针->成员名,打印结构体指针指向的成员
    return 0;
}

结果同上