C语言 8 操作符详解 上

简介: C语言 8 操作符详解 上

操作符分类

1.算数操作符:+ - * / %

2.移位操作符:<< >>

3.位操作符:& | ^

4.赋值操作符:= += -= *= ......

5.单目操作符:! sizeof ++ -- ...

6.关系操作符:> < >= <= == !=

7.逻辑操作符:&& ||

8.条件操作符:? :

9.逗号表达式:,

10.下标引用操作符,函数调用操作符和结构成员访问操作符:[] ()  .->

1.算数操作符:+ - * / %

int main()
{
  int m = 7.0/ 2;
  double n = 7.0 / 2;
  printf("%d\n", m);
  printf("%lf\n", n);
  return 0;
}

%取模运算两端的必须是整数不能是小数

int main()
{
  int m = 7 % 2;
  printf("%d", m);
  return 0;
}

—————————————————移位操作符——————————————————//

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

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

移位操作符的操作数只能是整数

整数的二进制表示形式有3种:原码、反码、补码

原码:按照数值的正负,直接写出的二进制序列就是源码

对于一个整数是4个字节=32个bit位 一个整数写出2进制序列的时候 就是32个bit位

对于有符号的整数来说,最高位的一位是符号位

符号位1表示负数

符号位0表示正数

对于无符号整数来说 没有符号位 所有位都是有效位

原码:按照数值的正负,直接写出的二进制序列就是源码

反码:原码符号位不变,其他位置按位取反

补码:反码的二进制+1就是补码

对于正的整数,原码,反码,补码相同,无需计算

对于负的整数,原码,反码,补码需要计算

eg、 10  原码: 00000000000000000000000000001010  2的多少次方 从后往前 从0开始

        补码: 00000000000000000000000000001010

        反码: 00000000000000000000000000001010

eg、-10 原码:10000000000000000000000000001010

       补码:11111111111111111111111111110110

       反码:11111111111111111111111111110101

  整数在内存中存储的都是补码的二进制序列

  整数在计算机的时候也使用补码

 

int main()
{
  unsigned int num = 10;//无符号整型:unsigned
  int n = 7 << 1;
  //7:       00000000000000000000000000000111  
  //7 << 1:  00000000000000000000000000001110  左移运算符:最左边丢弃,最右边补个0 
  //7 << 1:  14
  //向左移动一位等于值乘2    
    //左移操作符运算规则:左边丢弃 右边补零
  int f = -7;
  //-7: 原码:10000000000000000000000000000111  
  //-7: 反码:11111111111111111111111111111000
  //-7: 补码:11111111111111111111111111111001
  int F = -7 << 1;
  //-7 << 1: 补码:11111111111111111111111111110010 左移之后
  //-7 << 1: 反码:原码=补码-1:11111111111111111111111111110001 
  //-7 << 1: 原码:符号位不变,其余位1/0转变 10000000000000000000000000001110 
  //-14
  printf("m:%d\n", n);
  printf("F:%d\n", F);
  return 0; 
}

右移操作符:

右移运算分两种:

1.逻辑移位:左边用0填充,右边丢弃  

2.算术移位:左边用该值原符号位填充,右边丢弃 大部分编译器都是算术移位

原来是负数,左边补1,原来是正数,左边补0

int main()
{
  int a = 10;
  //原码:00000000 00000000 00000000 00001010
  //反码:01111111 11111111 11111111 11110101
  //补码:01111111 11111111 11111111 11110110
  //10
  int b = -10;
  int c = b >> 1;
  //右移之后 补码:01111111 11111111 11111111 11111011
  //右移之后 反码:01111111 11111111 11111111 11111010
  //右移之后 原码:00000000 00000000 00000000 00000101
  //-5
  printf("%d ", a);
  printf("%d ", b);
  printf("%d ", c);
  return 0;
}

逻辑右移和算术右移的差别是编译器的不同

对于移位运算符,不要移动负数位,这个是标准未定义的   eg、6 << -2

———————————————————位操作符————————————————————//

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

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

按照操作符的特点 都可以用


按位与

int main()
{
    int a = 3;
    //补码:00000000 00000000 00000000 00000011
    //取最低位:00000000 00000000 00000000 00000001
    int b = -5;
    //原码:10000000 00000000 00000000 00000101
    //反码:11111111 11111111 11111111 11111010
    //补码:11111111 11111111 11111111 11111011
    int c = a & b;//按(2进制)位与 用补码进行运算
    //补码:00000000 00000000 00000000 00000011 a&5
    //原码:00000000 00000000 00000000 00000011 a&5 
    //3
    printf("%d\n", c);
    return 0;
}

计算写出二进制序列

原码 取反 得到反码 +1 得到补码

补码取反+1得到原码

按位或

int main()
{
  int a = 3;
  //补码:00000000 00000000 00000000 00000011
  int b = -5;
  //原码:10000000 00000000 00000000 00000101
  //反码:11111111 11111111 11111111 11111010
  //补码:11111111 11111111 11111111 11111011
  int c = a | b;
  //补码:11111111 11111111 11111111 11111011 
  //反码:11111111 11111111 11111111 11111010
  //原码:10000000 00000000 00000000 00000101
  printf("%d", c);
  //-5
  return 0;
}

按位异或

异或运算:相同为0,相异为1

int main()
{
  int a = 3;
  //补码:00000000 00000000 00000000 00000011
  int b = -5;
  //原码:10000000 00000000 00000000 00000101
  //反码:11111111 11111111 11111111 11111010
  //补码:11111111 11111111 11111111 11111011
  int c = a ^ b;
  //补码:11111111 11111111 11111111 11111000
  //反码:11111111 11111111 11111111 11110111
  //原码:10000000 00000000 00000000 00001000
  printf("%d\n", c);
  //-8
  return 0;
}

a^a = 0   两相同数字都相同,所以异或

0^a = a  


创建临时变量(第三个变量),实现两个数的交换

int main()
{
  int a = 3;
  int b = 5;
  int t = 0;//中间变量
  printf("a=%d,b=%d\n", a, b);
  t = a;
  a = b;
  b = t;
  printf("a=%d,b=%d\n", a, b);
  return 0;
}

不能创建临时变量(第三个变量),实现两个数的交换

int main()
{
  int a = 3;
  int b = 5;
  int t = 0;//中间变量
  printf("a=%d,b=%d\n", a, b);
  a = a ^ b;     //a = 3^5
  b = a ^ b;     //b = a ^ b ^ b;    b = 3 ^ 5 ^ 5;    b = a = 3;    b = 3;
  a = a ^ b;     //a = a ^ a ^ b;    a = 3 ^ 3 ^ 5;    a = b = 5;    a = 5;
  //异或操作符支持交换律,不产生空间,不会进行溢出,只适用于整形,可读性差,效率不高
  printf("a=%d,b=%d\n", a, b);
  return 0;
}

编写代码实现:求一个整数存储在内存中的二进制中1的个数

一个整数在内存中有32个比特位,&1就能得到最低位

>>1

int main()
{
  int num = 0;
  printf("请您输入一个整数\n");
  scanf("%d", num);
  int a = 1;
  int count = 0;
  int i = 32;
  while (i <= 32 || i > 0)
  {
    if ((num & a) == 1)
    {
      count++;
    }
    num >> 1;
    i--;
  }
  return 0;
}

———————————————————赋值操作符——————————————————//

赋值操作符可以重新给一个值赋值,给自己重新赋值,在变量创建好后对变量进行修改

int main()
{
  int a = 0;//变量的初始化
  a = 10;//赋值操作符
  return 0;
}

     a = x = y + 1;   支持连续赋值

写成: x = y + 1;a = x;这样的代码更加清晰而且便于调试

———————————————————复合操作符——————————————————//

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


———————————————————单目操作符——————————————————//

!逻辑反操作符   -负值   +正值  &取地址  sizeof操作数的类型长度(以字节为单位)  

~对一个数的二进制按位取反  --前置、后置减  ++前置、后置加  (类型)强制类型转换



逻辑反操作符

int main()
{
  int a = -10;
  if (a != 1)
  {
    a = 20;
  }
  printf("%d", a);
  return 0;
}

-负值   +正值

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

& 取地址

int main()
{
  int a = 10;
  int* p = &a;
  &a;//a变量的地址
  int arr[10];
  &arr;//数组的地址
  int(*pa)[10] = &arr;
  printf("%d\n", *p);
  printf("%d\n", *pa);
  *p;//对p进行解引用操作,*p是通过p中存放的地址,找到p指向的对象。*p其实是a。
  return 0;
}


sizeof是计算类型创建变量或者变量的大小,单位是字节

sizeof 计算的结果是size_t类型

size_t是无符号整形

size_t类型的数据进行打印,用%zd

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

sizeof后面的括号中写的不是类型的时候,括号可以省略,这样就说sizeof不是函数

sizeof是操作符-单目操作符


 

int main()
{
  int a = 10;
  printf("%zd\n", sizeof(a));
  printf("%zd\n", sizeof a);//sizeof后面的括号中写的不是类型的时候,括号可以省略
  printf("%zd\n", sizeof(int));
  int arr[10] = { 0 };
  printf("%zd\n", sizeof(arr));
  printf("%zd\n", sizeof(arr[0]));
  printf("%zd\n", sizeof(arr) / sizeof(arr[0]));//数组的元素个数
  return 0;
}


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


int main()
{
  int a = 0;
  printf("%d\n", ~a);
  //0
  //00000000000000000000000000000000
  //11111111111111111111111111111111
  //10000000000000000000000000000000
  //10000000000000000000000000000001
  //-1 负1的补码是全1 0的补码全是1
  return 0;
}
int main()
{
  int a = 5;
  a++;
  printf("a:%d\n", a);
  int b = 5;
  ++b;
  printf("b:%d\n", b);
  //前置++:计算口诀:先加一,后使用
  //int c = ++a;
  //后置++:计算口诀:先使用,后加一
  int d = a++;
  //printf("c:%d\n", c);
  printf("d:%d\n", d);
  return 0;
}
int main()
{
  int a = 5;
  a++;
  printf("a:%d\n", a);
  int b = 5;
  ++b;
  printf("b:%d\n", b);
  //后置++:计算口诀:先使用,后加一,先赋值给d,再进行加一,
  int d = a++;
  printf("a:%d\n", a);
  printf("d:%d\n", d);
  return 0;
}
int main()
{
  int a = 5;
  int b = --a;
  //前置--:先-1,后使用
  printf("a = %d\n", a);//4
  printf("b = %d\n", b);//4
  return 0;
}
int main()
{
  int a = 5;
  int b = a--;
  //后置--:先使用,后--
  printf("a = %d\n", a);//4
  printf("b = %d\n", b);//5
  return 0;
}

(类型)强制类型转换

int main()
{
  int a = (int)3.14;
  srand((unsigned int)time(NULL));
  rand();
  return 0;
}

sizeof和数组

void test1(int arr[])
{
  printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
  printf("%d\n", sizeof(ch));
}
int main()
{
  int arr[10] = { 0 };
  char ch[10] = { 0 };//数组传参的本质是求数组首元素的地址
  test1(arr);//x64是8 x86是4
  test2(ch);//传的本质是一个指针,指针变量用于存放地址,sizeof算出的是指针变量的大小
  return 0;//不管是什么类型的指针都是4/8个字节的 
}

———————————————————关系操作符——————————————————//

———————————————————逻辑操作符——————————————————//

           &&  逻辑与  并且       ||  逻辑或  或者

int main()
{
  int month = 0;
  scanf("%d", &month);
  if (month >= 3 && month <= 5)
  {
    printf("春季\n");
  }
  if (month == 12 || month == 1|| month == 2)
  {
    printf("冬季\n");
  }
  return 0;
}
int main()
{
  int i = 0, a = 1, b = 2, c = 3, d = 4;
  i = a++ || ++b || d++;
  printf("%d\n", i);
  printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//2 2 3 4 1
  return 0;
}
int main()
{
  int a = 1, b = 2, c = 3, d = 4;
  int j = a++ && ++b && d++;
  printf("%d\n", j);
  printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//1 2 3 3 5
  return 0;
}

&&——左边操作数如果为假,右边无需计算,整体都为假

||——左边操作数如果为真,右边无需计算,整体都为真

短路操作:左边数字确定后,右边无需计算,就可确定真假,称作短路

int main()
{
  int i = 0, a = 0, b = 2, c = 3, d = 4;
  i = a++ && ++b && d++;//赋值运算符优先级最低 i = a++ 已经为假 后置+:先使用后++
  printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d); 
  printf("i = %d\n", i);
  //1 2 3 4 0
  return 0;
}


目录
相关文章
|
30天前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
|
30天前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
|
1月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
33 6
|
1月前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
43 0
十一:《初学C语言》—  操作符详解(上)
|
2月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
34 1
五:《初学C语言》—  操作符
|
3月前
|
C语言
C语言逻辑操作符的短路问题
C语言逻辑操作符的短路问题
|
3月前
|
编译器 C语言
【C语言】:中移位操作符,位操作符详运算规则详解
【C语言】:中移位操作符,位操作符详运算规则详解
27 1
|
3月前
|
存储 编译器 C语言
|
3月前
|
存储 C语言 索引
【C语言基础】:操作符详解(二)
【C语言基础】:操作符详解(二)
|
3月前
|
编译器 C语言
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)二
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)二
38 3