C语言基础12 操作符

操作符

操作符的种类:

 - 算术操作符 : +  -  *  / 
 - 移位操作符 : >>   <<
 -   位操作符 : &  |  ^ 
 - 赋值操作符 : =  +=  -=  *=  /=  &=  ^=  |=  >>=  <<= 
 - 单目操作符 : !  -  +  &  sizeof  ~  --  ++  *  (类型) 
 - 逻辑操作符 : && ||
 - 条件操作符 : exp1 ? exp2 : exp3
 - 逗号表达式 : exp1 , exp2 , exp3
 - 下表引用、函数调用和结构成员:

(1)算术运算符

如果我想算9除以2,看看得到的是4还是4.5。

int main(){
  int a = 9/2;
  printf("%d\n",a);

  return 0;
}

控制台打印:
4
4.5000000

从上面的式子可以看到:用整型来接收,得到的值也是整型,向下取整。而我想得到4.5的话只能尝试着用浮点型来计算。

int mian(){
  float a = 9/2;
  printf("%f\n",a);

  return 0;
}

const:
4.0000000

而通过float可以看到,即使是用float来接收所算的值,也得到的是4.0而不是想要的4.5。所以我继续尝试使用小数来计算。

int main(){
 float a = 9/2.0;
 printf("%f\n",a);

 return 0;
}

Console:
4.5000000

从上面的代码可以看到用小数来计算可以实现精准的答案,所以我们可以得到一个结论:

若式子两边都是整数,则上面输出的数只会是整数4,即使你用浮点型来表示,输出的也是4.0,而不是想要的精确值4.5。若想要得到精确值4.5,则像c中有一边为小数,就可以得到,输出结果就会为4.5。

取模(取余)

如果我想对9取模的话,得到的值又是多少?

int mian(){
  int a = 9 % 2; //取模
  printf("%d\n",a);

  return 0;
}

Console:
1

(2)移位运算符:

左移操作符 :移动的是二进制位

例如:我想对2使用左移操作符,那得到的是什么结果?

int main(){
  int a=2;
  int b =a << 1;
  printf("%d\n",b);

  return 0;
}

 Console:
 4

由上图可以看到,对2使用左移操作符,得到的是4,为什么?

因为左移运算符的作用是移动二进制位,我定义的a是int型,而在C语言中,int型是4个字节,而一个字节又是8个比特位,所以在内存图中,应该是32个比特位,向前移动一个比特位,如下:

//2的内存图
00000000 00000000 00000000 00000010
//向左移动
00000000 00000000 00000000 00000100

而在移动过的内存图中,1代表的权重为2的2次方,所以为4

int main()
{
   int a = 10;
   //把a的二进制位向右移动1位    
   int b = a >> 1;

   printf("b = %d\n",b);

   return 0'
}

Console:

右移操作符的内存移动:

00000000 00000000 00000000 00001010
00000000 00000000 00000000 00000101 

右移操作符前补位有两种情况:

  • 算术右移
    右边丢弃,左边补原符号位
  • 逻辑右移
    右移丢弃,左边补0

(3)位操作符

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

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

按位异或: 两个相同的数按位异或等于0,0按位异或任何数都等于它本身

int mian()
{
    // a ^ a = 0;
    // 0 ^ a = a;
    return 0;
}

按位与:都为1,才为1

int mian()
{
    int a =3;
    int b =5;
    // & - 按(2进制) 位与(都为1才为1)
    //00000000000000000000000000000011
    //00000000000000000000000000000101
    //00000000000000000000000000000001
    int c = a & b;
    printf("c = %d\n",c);
}

Console:
1

按位或:若一个为1,则为1

int mian()
{
    int a =3;
    int b =5;
    // | - 按(2进制) 位或(有一个为1则为1)
    //00000000000000000000000000000011
    //00000000000000000000000000000101
    //00000000000000000000000000000111
    int c = a | b;
    printf("c = %d\n",c);
}

Console:
7

按位异或:相同为0,相异为1

int mian()
{
    int a =3;
    int b =5;
    // | - 按(2进制) 位或(有一个为1则为1)
    //00000000000000000000000000000011
    //00000000000000000000000000000101
    //00000000000000000000000000000110
    int c = a | b;
    printf("c = %d\n",c);
}

Consol:
6

练习:

交换两个int变量的值,不能使用第三个变量。即 a = 3,b = 5,交换之后,a = 5,b = 3。

int mian()
{
    int a = 3;
    int b = 5;

    printf("a = %d b = %d\n", a, b);
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    printf("a = %d b = %d\n", a, b); 
}

Console:
a=3 b=5
a=5 b=3

这道题涉及的底层实现:

这里二进制32位简写,写有效部分:

a = 3   b = 5
 011     101

第一步: a = a ^ b;  011 ^ 101 ——>  a = 110  b = 101 
第二步: b = a ^ b;  110 ^ 101 ——>  a = 110  b = 011
第三步: a = a ^ b;  101 ^ 011 ——>  a = 101  b = 011

(4)赋值操作符

赋值操作符可以让你自己重新赋值你之前不满意的值。

赋值操作符:=

int main(){
  int weight = 120; //体重
  weight = 90; //不满意就赋值
  double salary = 10000.0
  salary = 20000.0; //使用赋值操作符赋值。  
    
  return 0;
}

注意:
一个等号是赋值,两个等号为判断

 =  ——> 赋值
==  ——> 判断

复合赋值符
+= 、 -= 、 *= 、 /= 、 %= 、 >>= 、 <<= 、 &= 、 |=

(5)单目运算符

单目操作符:只有一个操作数

! -  +  &  sizeof  ~  ++  --  *  (类型)

!: 逻辑反操作

如果 a 为真,!a就为假,反之 a 为假,!a 就为真

int mian()
{
    int a = 0;
    //a为真,打印Yes
    if(a)
    {
       printf("Yes\n");
    }
    //a为假,打印hNo
    if(!a)
    {
       printf("No\n"); 
    }
    return 0;
}

- : 负值
+ : 正值

int mian()
{
    int a = 10;
    a = -a;
    printf("%d\n",a);
    a = +a;
    printf("%d\n",a);
    return 0;
}

Console:
-10
10

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

  • sizeof是一个操作符,不是函数!!
  • sizeof的作用是计算类型或者变量的大小的
  • sizeof括号中的表达式是不参与其他运算的
  • 注: sizeof计算变量是可以省略括号不写,计算类型时必须带有括号。
int mian()
{
    int a = 10;
    char arr[10] = {0};
    printf("%d\n",sizeof(a));  //计算a所占空间的大小,单位是字节
    printf("%d'n",sizeof(arr)); //计算char类型数组10个空间所占大小
    printf("%d\n",sizeof(int)); //计算int类型的大小
    
    short s = 5;
    int b = 10;
    printf("%d\n",sizeof(s = b+2)); //s是short类型,不会因为加了int类型的值而改变自身类型大小
    printf("%d\n",b);  //sizeof括号中的表达式是不参与运算的
    return 0;
}

Console:
4
4
10
2
5

sizeof在计算变量大小可以省略括号,但是在计算变量时不能省略括号

int mian()
{
    int a = 10;
    char arr[10] = {0};
    printf("%d\n",sizeof a); 
    printf("%d\n",sizeof int); //err
    return 0;
}

使用sizeof计算数组

int main()
{
  int arr[10] ={0};
  printf("%d\n",sizeof(arr));  //计算的是数组的总大小,单位是字节
  printf("%d\n",sizeof(arr[0]));  //计算第0个元素的大小(这里定义的是整型)
  int sz = sizeof(arr)/sizeof(arr[0]); //计算数组元素个数
  printf("%d\n",sz);
  
  return 0;
}

Console:
40 //数组总大小
4  //第0个元素的大小
10 //元素个数

~ : 按位取反

按(二进制位)位取反:把所有二进制位中数字,1变成0,0变成1

例如整数a=0
二进制就为:

//a=0
00000000 00000000 00000000 00000000 
//~a
11111111 11111111 11111111 11111111

对0取反:

int main()
{
  int a =0;
  printf("%\n",~a);

  return 0;
}

Console:
-1

前置++

先++,后使用

int main(){
  int a =10;
  int b = ++a; //前置++
 
  printf("%d\n",b);
  ptintf("%d\n",a); 

  return 0;
}

Console:
11
11

后置++

先使用,再++

int mian()
{
   int a =10;
   int b =a++;  //后置++

   printf("%d\n",a);
   printf("%d\n",b);
   
   return 0; 
}

Console:
11
10

后置 - -

先使用,后- -

int mian()
{
   int a =10;
   int b =a--;  //后置--

   printf("%d\n",a);
   printf("%d\n",b);
   
   return 0; 
}

Console:
9
10

前置 - -
先使用,后- -

int mian()
{
   int a =10;
   int b =--a;  //前置--

   printf("%d\n",a);
   printf("%d\n",b);
   
   return 0; 
}

Console:
9
9

& :取地址操作符

&:取地址操作符

int mian()
{
    int a = 10;
    printf("%p\n",&a);

    return 0;
}

Console:
00CFF9D4

’ * ': 星号,解引用操作符 (间接访问操作符)

int mian()
{
    int a = 10;
    printf("%p\n",&a);  //&取地址
    int* pa = &a; //pa是用来存放地址的——>pa就是一个指针变量
    *pa = 20; //解引用操作符 ——>间接访问操作符
    printf("%d\n",a);
    
    return 0;
}

Console:
20

(类型) 强制类型转换

不建议使用,有的转换会丢失精度。类比java类型转换

int mian()
{
  //强转
  int a = (int)3.14;
  
  printf("%d\n",a);
  
  return 0;
}

(6)关系操作符

关系运算符在平时最常用到,也比较简单,在使用的过程中要注意的是一些运算的陷阱。

int a = 1;
int b = 2;
//if(a == b)
//if(a != b)
//if(a >= b)
//if(a <= b)
//if(a > b)
//if(a < b)
//{

//}

注意:

  • 在编程过程中切勿弄错 == 与 =,两个运算结果完全不同。
  • 比较两个字符串相等与否,不能使用 ==

(7)逻辑运算符

 && :两个都为真才为真
 || :只要一个为真,就为真

区分逻辑与按位与逻辑或按位或

1 & 2  ----->0
1 && 2 ----->1

1 | 2 ------>3
1 || 2 ----->1

逻辑与、逻辑或的使用

int mian()
{
   int a =0;
   int b =5; 
   int c = a && b;//&&:两个都为真才为真
   int d = a || b;//||:只要一个为真,就为真
   
   printf("%d\n",c);
   printf("%d\n",d);   

   return 0;
}

Console:
0
1

练习题

求下列代码输出的值为多少?

int mian()
{
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++ && ++b &&d++;
    //i = a++ || ++b || d++;
    printf("a = %d\nb = %d\nc = %d\nd = %d\n",a,b,c,d);

    return 0; 
}

假如有3个数,a,b,c

int c = a && b。

在 && 操作符运算下,只要一边为假,就为假,所以如果这个式子中,a为假,则这个表达式得到的值就为假,所以不用去计算b的值,计算完a就直接终止,返回假给c,同理:

上面这道题a=0,所以不去考虑后面bd的值,直接返回假给i,所以真正进行运算的只有a,而a进行了一个后置++,所以答案为:

Console:
1 2 3 4

如果把这题改为下面的代码,求输出的值为多少

int mian()
{
    int i = 0, a = 1, b = 2, c = 3, d = 4;
    //i = a++ && ++b &&d++;
    i = a++ || ++b || d++;
    printf("a = %d\nb = %d\nc = %d\nd = %d\n",a,b,c,d);

    return 0; 
}

同样的,当a=1时,a为真,而 || 操作符只要有一边为真,则为真,后面的b、d都不需要计算了,直接返回真。

所以这题答案为:

Console:
2 2 3 4

(8)条件操作符(三目操作符)

                 ?:

java中的三元运算符。

三目操作符语法

 exp1 ? exp2 : exp3
  |      |      |
表达式1 表达式2 表达式3

exp1 成立,exp2计算,整个表达式的结构是 : exp2的结果
exp1 不成立,exp3计算,整个表达式的结构是 : exp3的结果
int mian()
{
    int a=0;
    int b =3;
    int max =0;

    //if(a>b)
    //   max = a;
    //else
    //   max = b;   
       
    //用三目操作符表示
    max = a > b ? a : b;

    return 0;
}

console:
3

上面例子的条件表达式中:
a>b就等于exp1,问号后的a为exp2,b为exp3。
如果a>b成立,则表达式的值为a,否则为b

(9)逗号表达式

逗号表达式 : exp1 , exp2 , exp3
逗号表达式要从左向右依次计算,但是整个表达式的结果是最后一个表达式的结果

int main()
{
   //(2, 4 + 5, 6);
   int a = 3;
   int b = 5;
   int c = 0;
          //c=10        a=8        b=4
   int d = (c = 5, a = c + 3, b = a - 4, c += 5);
   //逗号表达式,是从左向右依次计算的
   //整个表达式的结果是最后一个表达式的结果
   
   printf("%d\n",d);
   return 0;
}

Console:
10

(10)下表引用、函数调用和结构成员

1.下标引用操作符 [ ]

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

下标引用操作符语法:

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

常在数组使用

int mian()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    printf("%d\n",arr[5]);  //[]为下标引用操作符

    return 0;
}

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

int main()
{
   //调用函数的时候,函数名后边的()就是函数调用操作符
   printf("hello!\n");  //传一个参数
   printf("%d",100);   //传俩参数

    return 0;
}

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

3.结构成员访问操作符

访问一个结构的成员

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

. 操作符

#include <stdio.h>

struct Book
{
    //结构体的成员(变量)
    char name[20];
    char id[20];
    int price;
};

int mian()
{
    //结构体变量名.成员名
    struct Book b = {"C程序设计","C59989",50};
    printf("书名: %s\n",b.name);
    printf("书号: %s\n",b.id);
    printf("定价: %d\n",b.price);

    return 0;
}

Console:
书名:C程序设计
书号:C59989
定价:50

-> 操作符

#include <stdio.h>

struct Book
{
    //结构体的成员(变量)
    char name[20];
    char id[20];
    int price;
};

int mian()
{
    //结构体指针->成员名
    struct Book b = {"C程序设计","C59989",50};
    struct Book * pb = &b;
    printf("书名: %s\n",pb->name);
    printf("书号: %s\n",pb->id);
    printf("定价: %d\n",pb->price);

    return 0;
}

Console:
书名:C程序设计
书号:C59989
定价:50
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值