详解C语言操作符(史上最全的重点总结!全在这里!)

简介: 详解C语言操作符(史上最全的重点总结!全在这里!)

文章目录

前言

C语言中操作符总共有10种,分别是:

算术操作符,移位操作符,位操作符,赋值操作符,单目操作符,关系操作符,逻辑操作符,条件操作符,逗号表达式,下标引用、函数调用和结构成员。


这里我挑了一些重点和易错点来说!

算术操作符,移位操作符,位操作符,复合运行算符,单目操作符、条件操作符,逗号操作符,下标引用、函数调用和结构成员

Let’s get it!

算术操作符

分为:

加:+

减:-

乘:*

除:/

取余:%

注意:

1、/ 如果是整型除法,其结果是

这里请注意,我说的是商!

a ÷ b = c …d,c叫做商,d叫做余数!例子: 9 / 4 = 2

如果两边有一个小数,则进行的就是小数除法,例子: 9 / 4.0 = 2.250000

2、% 代表求模运算,即余数,a % b = c,其中c的范围在 [0,b)

移位操作符

分为:

左移操作符 :<<

右移操作符:>>

在讲解移位操作符以前,这里要强调一个概念:原码反码补码

原反补

学了你就可以知道为char a=127, char b; b=a+1 这个时候你为什么b=-128

一个数在计算机内部如果是有符号数,则其最高位作为符号位,如果符号位为0,表示该数为正数,如果符号位为1,表示该数为负数。(0正1负)

以下求原反补的过程:

原码:最高位作为符号数,其余各位为数值位(0正1负)

反码:正数的反码与原码相同,负数的反码是在原码的基础上符号位不变,其余各位按位取反

补码:正数的补码与原码相同,负数的补码是在反码的基础上加1

这里看例题:

例:求+25和-25的原反补

  ①不考虑正负,将25转换成二进制
    25D=11001B
  ②     +25             -25
  原: 00011001   10011001
  反: 00011001   11100110
  补: 00011001   11100111

例:求+30和-30的原反补

  ①30D=11110B 
  ②   +30       -30
  原: 00011110   10011110
  反: 00011110   11100001
  补: 00011110   11100010

计算机中用的是补码,什么是补码,怎么去理解补码?

补码可以理解成一个循环。

8位二进制表示的有符号数范围是 -128~127

如果还有不懂的可以去百度一下!

这里我们回到移位操作符上

在计算机内存中,所操作的一切都是操作的 补码,补码,补码,补码!!!

重要的事情多说几遍,只是显示的时候才把补码还原回原码,然后转换成十进制

移位规则:

<<左移操作符不论算术移位还是逻辑移位,均将左边的数舍弃,右边空缺位补0(左边丢弃,右边补0)

image.png

>>右移操作符:当进行逻辑移位时,右边位丢弃,左边空缺位补0(右边丢弃,左边补0)

image.png

再次强调,计算机操作的是补码

总结:

右移一位具有 /2效果; 右移2位 具有 /4 效果;右移三位 具有 /8 效果;(右移效果只针对正数)…

左移一位 具有x2效果;左移两位 具有x4效果;左移三位 具有x8效果;(左移效果针对所有数)…

注意:

  1. 移位操作不改变原值
  2. 移位时不能移负数位

位操作符

符号:

& :按位与 (两个都是1才是1,否则0)

110101
101110
上面两个结果为 : 100100

| :按位或 (只要有1就是1)

1011011
0101100
上面两个结果为: 1111111

^ :按位异或 (相同为0,相异为1)

1010001
1010101
上面两个结果为:0000100

看到这里可能有点懵,所以我出两道关于位操作符的习题

1、数字交换

给出两个数字 a 和 b ,要求除了这两个变量以外,不准创建任何变量,达到ab交换

#include <stdio.h>
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    a = a^b;
    b = a^b;
    a = a^b;
    printf("%d %d", a, b);
    return 0;
}

是不是感觉没看懂?

image.png

我们以 a = 3,b = 5为例;

假设:a ^ b = m,那么我们反过来推导,m ^ a = b 或者 m^b = a

所以这段代码

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

为了更好理解我暂时用am代替 a^b 出来的值a(图中m

am = a ^ b

b = am ^ b (新得到的值其实是a,只是把值赋给了b)

a = am ^ b (am异或b,其实是异或的a,能理解吧?那么异或a得到的值就是b,所以赋值给a)

所以这样就是不要变量达到了完美的交换!

再问:数字的二进制(补码)有多少个1 ???

我们先不管二进制,假设给你一个数字a = 12334565,喊你求这个数字有几个3?

正常思路是不是 a%10 == 3 a = a/10 --> a%10 == 3 a = a/10 --> a%10 == 3 a = a/10这样循环下去计算?

那么我们二进制也是一样 a%2 == 1 a = a/2这样循环下去数

代码一:

#include <stdio.h>
int main()
{
    int n = 15;
    int count = 0;
    while (n)
    {
        if (n % 2 == 1)
            count++;
        n /= 2;
    }
    printf("%d", count);
    return 0;
}

但是这样写只能算正数,所以有缺陷

下面我就介绍 位操作

我们知道只有数字1 & 1 结果才是1

步骤一: 所以我们可以通过把一个数字的二进制与00000000000000000000000000000001 相&

步骤二: 如果结果为1,代表末尾为1

步骤三: 然后把该数字右移一位,再 与 000000000000000000000000000000001 相&

以此循环…

代码二:

#include <stdio.h>
int main()
{
    int n = -1;
    int count = 0;
  for(int i = 0;i<32;i++)
    {
        if (n & 1 == 1)
            count++;
        n = n >> 1;
    }
    printf("%d", count);
    return 0;
}

复合运算符

这个没什么讲的 ,就是组合起来操作

例子:

a = a + 3<==> a += 3

a = a & 2<==> a &= 2

a = a >> 1<==>a >>= 1

单目操作符

字面理解:目,眼睛;即这个操作符只需要一个操作数

例如:!3、-4、&a、a++

image.png

这里主要讲解一下 ++~sizeof(类型)

其中sizeof()strlen()的区别请看这里:sizeof和strlen的区别

例1:sizeof

#include <stdio.h>
int main()
{
    short s = 0;
    int a = 10;
    printf("%d\n", sizeof(s = a+5));
    printf("%d\n", s);
  return 0;
}

结果是多少???

2 0

因为sizeof里面的表达式中s不参与运算

例2:++

1、前置++:即先++,再使用

代码如下:

#include <stdio.h>
int main()
{
    int a = 5;
    printf("%d  ", a++);
    printf("%d", a);
    return 0;
}
//结果
5  6
//因为它先使用了a的值,然后再++

2、后置++:即先使用,再++

代码如下:

#include <stdio.h>
int main()
{
    int a = 5;
    printf("%d  ", ++a);
    printf("%d", a);
    return 0;
}
//结果
6  6

--的使用和++一样

例3:~

~ :按位取反

问题: 假设我想把 00001011 的倒数第三个0改为1 怎么用代码弄?

很简单,我们只有把它和00000100 相 |一下就行,那么00000100怎么来的??

数字1左移两位 1<<2

代码如下:

#include <stdio.h>
int main()
{
    /*1011代表的是 11*/
    int a = 11;
    int ret;
    ret = a | (1<<2);
    printf("%d", ret);
  return 0;
}
//结果是 15
1111刚好就是15

再问: 那如果我想把1111改回去呢???

  • 00000000 00000000 0000000 00001111
  • 我们需要把它和11111111 11111111 11111111 111110111 相&
  • 那11111111 11111111 11111111 111110111怎么得来的呢???
  • 00000000 00000000 00000000 00000100取反得来
  • 00000000 00000000 00000000 00000100而这个又是1左移两位
  • 00000000 00000000 00000000 00000001(数字1)

所以逻辑是:首先 1<<2,然后取反,最后相与

代码如下:

#include <stdio.h>
int main()
{
    int a = 15;
    int ret;
    ret = a & (~(1<<2));
    printf("%d", ret);
  return 0;
}
//结果是11

例4:(类型)(强制类型转换

srand((unsigned int)time(NULL)); 

注意:

1.sizeof是一个操作符,关键字,而不是函数,求的是操作数的类型长度(以字节为单位)

2.sizeof求类型的长度时不可省略括号,求变量的长度时可以省略括号

3.!操作符是对一个数做逻辑反操作,而~操作符是对一个数的二进制按位取反

4.前置++、前置–是先使用,再++;而后置++、后置–是先–,再使用

条件操作符

符号:exp1 ? exp2 : exp3

含义:表达式exp1如果成立,则返回表达式2的值,否则返回表达式3的值

例子: 例如我们需要把 a,b中的大值给max,小值给min

#include <stdio.h>
int main()
{
    int a = 15,b = 24;
    int max,min;
  max = a>b?a:b;
    min = a>b?b:a;
    printf("max = %d  min = %d", max,min);
  return 0;
}

逗号表达式

符号:exp1, exp2, exp3, ..., expN

含义:逗号表达式(用逗号隔开的表达式),从左往右依次执行;整个表达式的结果为最后一个表达式的结果

举例说明:

int a = 3,b = 4;

c = (a>b,a = b*4,b = a+2)

c等于多少呢? 答案:18

代码如下:

#include <stdio.h>
int main()
{
    a = get_val();
    count(a);
    while(a>0)
    {
        a = get_val();
      count(a); 
        //语句
    }
  return 0;
}
//上面这样写是不是重复了? 可以写成下面这样!
#include <stdio.h>
int main()
{    
    while(a = get_val(),a>0,count(a))
    {
        //语句
    }
  return 0;
}

注意:

逗号表达式的结果虽然是最后一个表达式的结果,但不可认为与前面的表达式就无关了,

因为前面表达式可能会影响最后一个表达式的结果

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

1、下标引用

符号:[ ]

符号说明:下标引用操作符,有两个操作数(数组名和索引值)

举例说明:

int arr[10] = {3,7,4,8,2,15,25,6,9,1};
arr[3] = 8;    //[ ]:下标引用操作符,其两个操作数为arr和3

注意:下标引用共有两个操作数(数组名和索引值)

2、函数调用

符号:()

符号说明:函数调用操作符,有一个或多个操作数(函数名和参数)。

举例说明:

void test1()
{
  printf("fine day!\n");
}
void test2(char *ch)
{
  printf("%s\n",ch);
}
int main()
{
  test1();    //():函数调用操作符
  test2("fine day!");    //():函数调用操作符
}

注意:函数调用操作符有一个或多个操作数

3、访问结构体成员

符号:.

符号说明:结构体对象

举例说明:

struct student
{
 char name[10];
 int age;
 char sex[10];
};
#include <stdio.h>
int main()
{
 struct student xiaoming = { "小明",25,"男人" };
 /*访问结构成员*/
 printf("姓名:%s\n", xiaoming.name);
 printf("年龄:%d\n", xiaoming.age);
 printf("性别:%s\n", xiaoming.sex);
 return 0;
}

4、结构体指针访问

符号:->

符号说明:结构体指针

举例说明:

struct student
{
char name[10];
int age;
char sex[10];
};
#include <stdio.h>
int main()
{
struct student xiaoming = { "小明",25,"男人" };
struct student* people = &xiaoming;
/*访问结构成员*/
printf("姓名:%s\n", people->name);
printf("年龄:%d\n", people->age);
printf("性别:%s\n", people->sex);
return 0;
}

注意:当结构体中有数组成员时,给该成员赋值用strcpy()函数,将目标串拷贝给该数组成员

see you!

相关文章
|
4月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
78 0
|
4月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
276 0
|
2月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
44 10
|
2月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
169 1
|
2月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
182 0
|
4月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
46 6
|
4月前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
61 0
十一:《初学C语言》—  操作符详解(上)
|
5月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
45 1
五:《初学C语言》—  操作符
|
6月前
|
C语言
C语言逻辑操作符的短路问题
C语言逻辑操作符的短路问题
|
6月前
|
编译器 C语言
【C语言】:中移位操作符,位操作符详运算规则详解
【C语言】:中移位操作符,位操作符详运算规则详解
47 1