avatar

zian

A text-focused Halo theme

  • Java
  • 面试
  • 首页
  • C语音
  • liunx
  • 数据结构与算法
  • 控制台
Home C语言运算符
文章

C语言运算符

Posted 2024-12-21 Updated 2024-12- 27
By Administrator
24~32 min read

表达式和表达式语句

表达式:通过一些操作有返回的值的 , a < b 返回 1 或者 0

赋值符号的也是表达式,这边表达的是的意思是要看,赋值之后的接受是零还是非零。零为 false , 非零为true

int a = 12;
int b = 10;
// 将 b 的值赋值给 a , 赋值后 a 的值如果是非零的就是 true ,如果是零就是 false 
if(a=b) {
   printf("a == b ");
}else {
   printf("a != b ");
}

表达式语句

表达式语句:执行一个表达式,但是不会返回任何结果。

常见的有:

  1. 初始化变量
  2. 条件语句 if
  3. 循环语句 while

运算符

算数运算符

包含:+,-,*,/,%

其中:

  1. 整数型数据使用除法时得到结果仍然是取整后的整数,浮点型想除得到的是小数
  2. % 取余数运算符只能针对整数

以上运算符都是二元运算符(双目运算符), 运算符要能执行左右两端都需要有表达式,左右各一个表达式相加等于二

自增自减运算符

解释:

  1. ++ 自增运算符,表示变量自身的值加一
  2. -- 自减运算符,表示变量自身的值加一

注意: ++a 表示先自增再取值 a++表示先取值再自增, --a先自减再取值 a--先取值再自减

自增自减运算符是一个一元运算符, 优先级口诀: 一般情况下一元运算符有限级高于二元运算符高于三元运算符

int i= 3

扩展: += -= *= /= 二元运算符

例子:

a += 2; // a = a + 2 简写 

a -= 1; // a = a - 1 简写 

a *= 3; // a = a * 3 简写 

a /= 2; // a = a / 2 简写 

逻辑运算符

用于条件判断的运算符,表达复杂的条件关系

  • 逻辑与 && (且),该运算符是一个二元运算符,左右两端表达式都要为真,结果才为真,有一个为假返回值就是假
int age = 18;
int money = 200;

if(age >= 18 && money >= 200) {
    printf("恭喜你成为本网吧的vip用户!");
}

注意: 且运算符逻辑两者都真才返回真,若且运算符第一项表达式已经为假后面的表达式将不会执行。通过这一特点在开发中经常会使用 && 运算符进行 惰性运算

int a = 1
int b = 2

int ret = a < b && a++
  • 逻辑或 || (且),该运算符是一个二元运算符,左右两端表达式只要有一个为真,结果就为真.两者都为假返回值才是假
int age = 18;
int money = 200;

if(age >= 18 || money >= 200) {
    printf("恭喜你成为本网吧的vip用户!");
}

注意: 逻辑或也支持惰性运算,若且运算符前面的表达式为真,后面的表达式不执行,

int id = 0;

id || (id = 5);

id || (id = 7);

id || (id = 9);

id || (id = 12);
id || (id = 24);

printf("%d \n", id); // 5
  • 逻辑非(!) 是一元运算符,将逻辑表达式的值取反
int age = 18;
if(!(age >= 18)) {
    printf("你还未成年\n");
}
bool show = true;
if(show) {
    printf("显示\n");
}

if(!show) {
    printf("隐藏\n");
}

优先级: ! > && > ||

关系运算符

包含

  • > 大于
  • < 小于
  • >= 大于等于
  • <= 小于等于
  • == 等于
  • != 不等于

以上全是二元运算符,在使用避免出错:

if( 100 >= score >= 90) // 错误代码,不能这么写
if( 100 >= score &&  score >= 90) // 正确写法

一定要区分 = 和 ==: =是赋值操作 == 判断两者是否相同

int a =1 , b =2 ;
a == b =2 ;  // 编译报错,原因: == 优先级比 = 的优先级高 , 所以  0 = 2 ,常量是不能作为左值的

位运算符

位运算符操作的对象是数据二进制编码中的每一位

&: 位逻辑与 a & b 将变量 a 和 b 逐位进行与操作(0与上任何数都为0)

12 & 15 // 1100 & 1111  -> 1100

使用 & 可以实现获取 char 类型的最后一半的字节比如 : 0x45 就可以获取到 0x05

     unsigend char temp = 0x45;

    // 0x45   --->      0100  0101
    // 0x0f   --->   &  1111  1111 
    // 0x05   --->      0000  0101   

    unsigned char lamp = temp & 0x0f;
    printf("灯:%#x \n", lamp);
   
    // 获取前面一半的字节使用 >>  , 无符号的 ,高位补零,低位溢出。
   // 0x45   --->     0100 0101
    //0x04    ---->   0000 0100   
    unsigend dour = temp >> 4;
    printf("灯:%#x \n", lamp);


|: 位逻辑或a | b将变量 a 和 b 逐位进行或操作(1或上任何数都为1)

12 | 15 // 1100 | 1111  -> 1111

~: 位逻辑反 ~a 将变量 a 中的每一位取反

 unsigned char a = 1;  // 0000 0001 

 printf("位运算或 %hu \n", ~a); // 1111 1111 1111 1110  -> 65534

^: 位逻辑异或 a ^ b将变量 a 和 b 逐位进行异或操作(相同为0,不同为1)

12 ^ 14 // 1100 ^ 1110  -> 0010

推导: a ^ a -> 0 , a ^ 0 -> a

利用位异或来实现两数交换

#include <stdio.h>

int main(int argc, const char* argv[]) {
  // 方案1 : 中间变量
  int a = 12, b = 15;
  int temp;

  // temp = a;
  // a = b;
  // b = temp;
  // printf("a = %d b =  %d ", a, b);


  // 方案二:加减法
  // a = a + b;  // 12 + 15
  // b = a - b ;  // 12 + 15 - 15   b = 12 
  // a = a - b;   // 12 + 15 - 12   a = 15 
  // printf("a = %d b =  %d ", a, b);


  // 方案三:异或
  a = a ^ b;  // a ^ b 
  b = a ^ b; // a ^ b ^ b   b = a 
  a = a ^ b;  // a ^ b ^ b => ( b = a )   ===>  a ^ b ^ a 

  printf("a = %d b =  %d ", a, b);

  return 0;
}

技巧:

  1. 任何数 ^ 自己都等于 0 ,(异或运算:相同为 0 )
  2. 任何数 ^ 0 都等于自己本身 ,(异或运算:相同为 0 , 所有的 1 都保留下来 a ^ a ^ a等于本身 )
  3. 任何数异或自己数据类型的最大值,等于 最大值 - 自己
   char   a = -1;
   char b = a ^ 128;
   printf("%d \n", b);  // 255 - 128 = 127
   return 0;

<<: 数据本身向高位(左)移动 n 位,溢出的被舍弃,低位补0

int a = 0x00112233

例子

    int r = 0xff;
    int g = 0xcc;
    int b = 0x00;
    int alph = 0x77; 
    //         0xff000000 | 0x00cc0000 |  0x0000 | 0x77  
    int color = r << 24 | g << 16 | b << 8 | alph;
  
    printf("%#x\n", color); // 0xffcc0077
    printf("%#x", 0x01<<2); 

技巧:

  1. 每一位相等于 * 2

示例:利用 << 和 | 来实现使用一个 int 数据类型的变量来存储一个颜色



   // 利用 int 来存储一个颜色 , int 每一个字节都存一个三原色

   // #fffc5531  a(透明度)r(红色)g(绿色)b(蓝色)
   // 这里一定无符号的,应为在 int 除了第一个字节,都是可以存储 0 - 255 的,这里由于要存储颜色颜色也是0 - 255,
   // 所有这里一定要使用 无符号的 char , 如果是有符号就会出现溢出问题
   unsigned char a = 0xff;
   unsigned char b = 0xfc;
   unsigned char c = 0x55;
   unsigned char d = 0x31;
   // 利用 << (左移) 将数据放在对应的位置,利用 | (位或) 拼接其他的数据 
   //   0xff000000  
   // | 0xfffc0000   // 利用位或来拼接其他的数据。
   int color = a << 24 | b  << 16 | c << 8   |  d ; 
   printf("%#x \n ", color);

>>: 数据本身向低位移动

  • 算数右移: 数据向低位移动, 越界低位被舍弃,高位补符号位
  • 逻辑右移: 数据向低位移动, 越界低位被舍弃,高位补0

注意: 不同操作系统采用右移方式是不同的
如: Ubuntu 和 windows 采用的算数右移

示例:


  // 右移:无符号:高位补零 ,低位溢出舍去
   unsigned int a = 0x7f000000;
   printf("%#x \n", a);
   printf("%#x \n", a >> 8);


   // 右移:  有符号,高位补符号位,低位溢出舍去 
   int  a1 = 0x8f000000; // 0x8f000000 的符号位是 1 
   printf("%#x \n", a1);  // 0x8f000000
   printf("%#x \n", a1 >> 8); // 高位补符号位: 也就是 1 , (1111 = 0xf ) 0xff8f0000   

   // 右移:  有符号,高位补符号位,低位溢出舍去
   int a2 = 0x7f000000; // 0x7f000000 的符号位是 0 
   printf("%#x \n", a2); // 0x7f000000 
   printf("%#x \n", a2 >> 8); // 高位补符号位 :也就是 0 , 0000 0000 0000 0000 0111 1111 0000 0000 0000 

扩展 >>= <<= 自身右移自身左移

a <<= 2 等价 a = a << 2
a >>= 2 等价 a = a >> 2

作业

  1. 一个整数a,
    要求把a的第五个二进制位变成0(无论是否为0),其他二进制不允许改变
   1011 1001
   &1110 1111
   ~0001 0000 等于上者
   // 答案: a & ~0x10
要求把a的第五个二进制位变成1(无论是否为1),其他二进制不允许改变   
   1011 1001
   |0001 0000
   答案: a | 0x10
要求把a的第五个二进制位取反(0变成1,1变成0),其他二进制不允许改变
   1011 1001
   ^0001 0000
   答案: a ^ 0x10
  1. 0x01 << 5 的16进制结果是多少??
0000 0001 -> 0010 0000
0x20
  1. 以下程序的执行结果是
         int x='f';
         printf("%c\n",'a'+(x-'a'+1));  // g
  1. 以下程序的执行结果是
          int a=4,b=5,c=0,d;
          d=!a&&!b||!c;  
          printf("%d\n",d); // 1
  1. 以下程序的执行结果是
         int a,b,c,d;
         a=10;
         b=a++; // 10
         c=++a; // 12
         d=10*a++; // 120
         printf("b,c,d:%d  %d  %d\n",b,c,d);

三目运算符

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

首先先判断表达式1,若为真返回表达式2的值,若为假返回表达式3的值

int is_adult = age >= 18 ? 1 : 0;

// 求两者的最大值
int max = a > b ? a : b

sizeof运算符

求数据类型,变量的大小

sizeof(bool);
int a = 4;
sizeof(a)

逗号运算符

符号: ,

作用:将多行代码写成一行,从前往后执行。

如果涉及到赋值,返回值是最后一个逗号的。

示例:

int a ;
int b;
 
// 不使用 ,逗号
a = 20 ;
b = 20 ;

// 使用逗号 
a = 20 , b = 20;

int c = (a++, 10 + 5);
printf("%d %d \n" , a , c  ); // 21  12

优先级

小技巧:

  1. 一元 > 二元 > 三元
  2. 越精确优先级越高
  3. 赋值最低。
  4. 一般:算数运算( + 、 - 等 ) > 关系运算 (&& 、|| 等 ) > 赋值运算 ()

优先级.png

C语音
License:  CC BY 4.0
Share

Further Reading

Jan 7, 2025

C语言 其他

作用域 关键字 register 在C语言中,register 关键字是一种存储类说明符,用于建议编译器将变量存储在CPU寄存器中,而不是内存中。这样做可以提高访问变量的速度,因为寄存器的访问速度通常比内存快得多。然而,这个关键字只是一个提示,编译器可以选择忽略它。 使用register关键字的变量

Jan 6, 2025

C语言 结构体

结构体 问题的引入 多个相同数据类型的数据可以用数组表示,那么,如果多个不同数据类型的数据如何用一个集合表示呢?? 前面我们所介绍的普通数据类型实际上远远未能满足我们对实际应用中的要求,比如说一个学生,可能包含的属性有年龄、姓名、分数等等,不可能用一个基本数据类型(int 、float 、char)

Dec 28, 2024

C语言 内存

内存 什么是内存 软件在运行是,临时用来存储数据的 操作系统会将内存按照字节划分为 N 多个小格子 什么是内存地址 其实就是格子的编号 32 位操作系统:以 32 位的二进制表示 64 位操作系统:以 64 位的二进制表示 内存地址的作用 快速操作内存中存储的数据 C 语言中如何获取内存地址 &变量

OLDER

进制转换

NEWER

Linux系统软件安装

Recently Updated

  • 其他
  • Elasticsearch 面试
  • Spring 面试
  • RabbitMQ 面试
  • Redis 面试

Trending Tags

ruoyi docker java

Contents

©2025 zian. Some rights reserved.

Using the Halo theme Chirpy