C语言教程——操作符详解(1)

news2024/12/28 17:53:26

目录

前言

1.操作符的分类:

2.算数操作符

2.1除法

2.2取模

3.移位操作符

 3.1二进制相关知识

3.2左移操作符

3.2.1正数

3.2.2负数

3.2.3结论

3.3右移操作符

 4.位操作符

4.1 按位与

4.2按位或

4.3按位异或

​编辑

5.赋值操作符

6.复合赋值符

7.单目操作符

7.1单目操作符介绍

7.2单目操作符 !

7.3负号

7.4正号

7.5&取地址

7.6sizeof关键字(操作符)

7.7按位取反~

7.8前置(后置)++ --

7.9*解引用操作符

7.0强制类型转换

总结


前言

今天从开始讲解每个操作符的介绍,这里我有一个建议,关于操作符,我们可以不用硬背,我们可以通过敲代码,敲几次就自然而然就记住了。


1.操作符的分类:

算术操作符

移位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

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

这些操作符的分类和介绍有一些在文章前面的几篇介绍有所了解,但是但是并没有进行详细了解。 

2.算数操作符

+         -         *         /        %

算数操作符就是加减乘除还有一个取模,加减乘就不用说了,与数学中的大差不差,我们直接从除法和取模讲起:

2.1除法

#include <stdio.h>
int main()
{
	int a = 5/2;
	double b = 5.0 / 2;
	printf("%d\n", a);
	printf("%lf\n", b);
	return 0;
}

这是一个简单的除法运算,其中除号也叫做操作符(运算符),对于除法操作符来说,两边的操作数都是整数(这里5和2就是操作数),执行的是整数除法,如果想要计算出小数,那么除号两边至少有一个操作数是浮点数。上面就是如此,小数除以一个整数,之后还是等于小数,结果为2.500000,float和double类型用%f和%lf来打印的时候,默认是打印小数点后六位,如果想要打印1位那么就可以写成%.1lf,这样就是打印小数点后一位。

2.2取模

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

这里就是一个简单的取模(取余),计算的是整除之后的余数,但对于取余来说两边的操作数只能是整形类型,不能为其它类型,用其它类型就会报错。

1. 除了%操作符之外,其它的几个操作符都可以用于整数和浮点数

2. 对于/操作符如果两个操作数都为整数,执行整数除法,而只要有浮点数就执行浮点数除法。

3. %操作符的两个操作数必须为整数,返回的是整除之后的余数。

3.移位操作符

移位操作符,这里的位是二进制,移的其实是二进制,这里有两个操作符:

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

这里要注意,移位操作符的操作数只能是整数。

#include <stdio.h>
int main()
{
	int a = 10;
	int b = a << 2;   //左移
	int c = a >> 2;   //右移 
	printf("%d\n", b);
	printf("%d\n", c);
	return 0;
}

上面就是移位操作符的使用方法,结果输出的一个为40,一个为2。因为这里是移位的是二进制,所以这里再讲解一下二进制的有关内容。

 3.1二进制相关知识

整数的二进制形式有三种:

原码      反码       补码

 假如这里有一个数是12:

二进制:1100      2^0+0*2^1+1*2^2+1*2^3=4+8=12

八进制:14          4*8^0+1*8^1=4+8=12

十六进制:c        十六进制里面a=10   b=11    c=12

正数的反码、原码、补码都是相同的。这里给出一个正整数10,用二进制写出来就是32位,因为一个整形类型就是占4个字节,一个字节占8个比特。由于是正数,所以第一位是0,反之,如果为1的话,这个数就是负数。

 相对而言我们这里给出一个负数,它的原码就是第一位为1,剩下的按照二进制来实现,反码就是除了第一位符号位以外,都相对于原码按位取反,补码就是反码加1,得2进1。

相反也可以从补码得到原码, 第一种方法就是按原来的再走回去,补码先变成反码,反码再变成原码,第二种方法就是直接补码取反,加一,这样也可以直接从补码得到原码。

  内存中存储的起始是:补码的二进制

所以在参与移位的时候,移动的都是补码。

3.2左移操作符

3.2.1正数

#include <stdio.h>
int main()
{
	int a = 10;
	int b = a << 1;   //左移一位
	printf("%d\n", b);
	return 0;
}

这里给出一个整数10,我们希望它可以往左移动一位:

这里我们知道正数的补码原码反码都一样,所以写出它的原码就相当于写出来了它的补码,接下来让补码左移一位,最左边的移出去了,最右面由于缺了一位,所以填一个0,这样就移完了,我们可以算出最后等于20,程序编译运行后也是输出20,但这个过程里a的值是不变的,而是a<<1这个表达式的结果是一位之后的效果。

所以是左边丢弃,右面补个0

3.2.2负数

#include <stdio.h>
int main()
{
	int a = -10;
	int b = a << 1;   //左移一位
	printf("%d\n", b);
	return 0;
}

这里给出一个负整数10,我们希望它可以往左移动一位:

首先得到负数10的原码,之后写出它的反码和补码,因为移位是移的是补码,向左移动一位,左侧的一位不要了,右侧补上一个0,现在就是得到了向左移动完一位的补码,接下来我们还需要将补码转化为原码,才能得到最后的数。

我们用第二种方法,补码取反加1后就是得到了最后的原码,所以读出来就是-20。(记住取反的时候符号位是不发生改变的)

3.2.3结论

我们可以发现,往左移一位有×2的效果。

3.3右移操作符

右移其实分为两种

1.算数右移(平时见到)

2.逻辑右移

到底是算数右移还是逻辑右移是取决于编辑器的,绝大部分右移都是算数右移。

#include <stdio.h>
int main()
{
	int a = -1;
	int b = a >> 1;   //右移一位
	printf("%d\n", b);
	return 0;
}

这里给出一个-1,它的原码反码和补码如下所示:

我们让它的补码向右移动一位,这时候就发现了一个问题,当向右移动一位的时候,最左侧就不知道补上什么了,这里给出定义:

算数右移:右边丢弃,左边补上原来的符号位

逻辑右移:右边丢弃,左边直接补0 

这个程序编译运行之后,还是-1,所以是用的算数右移,因为如果是逻辑右移,它将会变成整数,所以当前机器是按照算数右移来移动的。

这里注意:

应该在有效的范围内进行移动,不能太大,太大就一下子移没了,如果移动的位数是负数也不可以,因为这个标准是未定义的。

 4.位操作符

位操作符有:

&   //按位与

|     //按位或

^    //按位异或

它们的操作数必须是整数,同时也是针对二进制位进行计算的

4.1 按位与

& - 按2进制位与

对应的二进制有0,则为0,两个同时为1,才为1

#include <stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a & b;
	//内存中补码进行计算
	printf("%d\n", c);
	return 0;
}

这里给出一个正数和一个负数进行按位与计算,我们知道这些数的计算是放在内存中进行计算的,而计算机内存中存放的都是补码,所以还是要找出它们两个的补码,之后再进行按位与的计算。

 3的反码原码补码都一样,因为它是正数,即可得到3的补码。

这里通过运算也同样的得到了-5的补码。

按位与的计算规则是有0则为0,两个1才为1。

所以上面的两个数的补码进行按位与计算之后得到的补码就是上面的,因为符号位为0,所以是正数,正数的反码补码原码都相同,所以直接读出来就是3。通过编译获得的结果也为3,这就是按位与计算。

4.2按位或

| - 按2进制位或

对应的二进制有1,则为1,两个同时为0,才为0

按位或跟按位与恰恰相反。

#include <stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a | b;
	//内存中补码进行计算
	printf("%d\n", c);
	return 0;
}

所以还是针对上述的两个数进行按位或,因为我们知道了它们两个的补码,所以只需要进行按位或运算就可以的处境结果

这时候就出现了运算后的补码,这是个负数,所以取反加1即为最后的结果,我们发现这个补码和-5的补码一样,所以最后的结果就是-5,这就是按位或。

4.3按位异或

^ - 按2进制位异或

对应的二进制位:相同为0,相异为1

#include <stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a ^ b;
	//内存中补码进行计算
	printf("%d\n", c);
	return 0;
}

这里还是用之前的两个数:

因为这里得到的的符号位为1,所以就是负数,负数则需要将补码变回到原码,然后再进行读数,这里我们不用第二种方法了,用第一种方法,先变成反码,之后再变成原码,也就是原路返回。

也就是如上所示,先将补码减去1,之后再按位取反,最后就得到了最后的原码,读出原码就是按位异或的最后的值。

5.赋值操作符

赋值操作符可以让之前的一个值重新被赋值。

例如:

int a=10;
a=20;
double salary=1000;
salary=2000;

这里就是先定义一个变量的值,之后再进行重新赋值。

赋值操作符还可以连续使用,并且连续进行赋值:

int a=10;
int x=0;
int y=20;
a=x=y+1;//连续赋值

 这里先定义了a,x,y的变量,之后先运算y+1,将这个的值赋给x,然后再将x赋给a。但这样的写法有一些不好,不能直观的体现出到底怎么执行的。所以可以拆开写:

x=y+1;
a=x;

这样更加的容易调试。

6.复合赋值符

+=              -=                  *=                  /=                %=                  

>>=            <<=               &=                 |=                 ^=

这些运算符都可以写成复合的效果。

例如:

int main( )
{
    int a=3;
    a=a+2;
    a+=2;

    int b=10;
    b=b<<1;
    b<<=1;

    return 0;
}

其它的运算都可以这样写,这样更加的方便和简洁。

7.单目操作符

7.1单目操作符介绍

!                                                             逻辑反操作

-                                                                负值

+                                                               正值

&                                                               取地址

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

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

--                                                               前置、后置--

++                                                             前置、后置++

*                                                                间接访问操作符(解引用操作符)

(类型)                                                        强制类型转换

例如:

a+1;

这个有两个操作数,所以是双目操作符。

7.2单目操作符 !

而单目操作符只有一个操作数,例如下面:

int main( )
{
    int flag=5;
    if(flag)
    {
        printf("ok\n");
    }
    return 0;
}

C语言中0为假,非零为真,上述代码就是如果flag为真,就打印ok,也就是执行if语句里面的内容。

但如果我们想要把这个条件改成如果flag为假才执行就可以这么写:

int main( )
{
    int flag=5;
    if(!flag)
    {
        printf("ok\n");
    }
    return 0;
}

这样的话就不输出内容,但如果把flag赋值为0,0为假,那么就输出ok。

补充:布尔类型,布尔类型就是来表示真假的类型。例如下面:

#include <stdbool.h>

int main( )
{
    _Bool flag=true;
    if(flag)
    {
        printf("ok\n");
    }
    return 0;
}

 布尔类型要用到stdbool头文件。它是专门来写真假的。

7.3负号

就是把正数变成负数,负数可以变成正数。

7.4正号

正号一般都省略掉了,基本上没有什么要用到的地方。

7.5&取地址

int main( )
{
   int a=10;
    pritnf("%p\n",&a);
    int*pa=&a;
    return 0;   
}

上述代码就用了取地址的符号,取地址其实是取出来的一个对象,内存里的地址,我们可以把a这个地址打印出来,同时还可以放到一个整形的oa中。不仅可以取出来变量的地址,数组的地址,还可以取出来元素的地址。如果是常量字符串,那么取出来的地址就是字符串里第一个字符的地址。

只要是地址,就可以进行解引用*。但有一些是非法的,有一些地址还没分配,但解引用相当于强行访问。

7.6sizeof关键字(操作符)

它可以计算变量大小,数组大小或者类型大小等等。

int main( )
{
    int a=10;
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof a);
    printf("%d\n",sizeof(int));
    return 0;
}

上述代码都可以正常运行,并且都输出4。其中sizeof后面不加括号都可以,所以说明sizeof不是函数,sizeof后面是变量名的时候可以省略,如果是类型的话是不可以进行省略的。

sizeof在计算的时候有一个特点:

int a=10;
short s=5;
printf("%d\n",sizeof(s=a+3));
printf("%d\n",s);

因为sizeof内部的表达式是不参与计算的,不用进行真实的计算,这里面a+3赋给s这个动作是不发生的,因为s是短整型,但是a是整形,当一个整形放进一个短整型里面的时候,就会发生截断,所以sizeof算的是s类型的值,所以就是2,这时候s的值还是5,不会发生变化。

7.7按位取反~

对于二进制来说所有的按位取反。

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

上述代码最后的运行结果就是-1,因为它的最后算出来的补码全是1,补码全是1的话那么原码就是-1。

7.8前置(后置)++ --

int a=10;
int b=a++;

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

后置++,就是先使用,之后再++。上述代码结果就是a输出是11,b输出是10,而前置++,则是先++,之后再使用。

前置--和后置--也与这一样,可以类比。

7.9*解引用操作符

这个是和那个取地址操作符是一对的,可以通过地址来进行访问数据,后期遇到可以再讲。

7.0强制类型转换

int a=(int)3.14;

这就是把小数强制类型转化成了整形,这里就是把整数部分取出来了,小数部分就不要了。

之前有一个:

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

这里就用到了一个强制类型转换,因为time()返回类型是time_t,而srand接收类型是整形,所以就可以强制类型转化成整形,这样srand就可以接受。


总结

今天介绍了关于单目操作符的使用和方法,以及一些要注意的地方,后续将会继续讲解其中的一些需要注意的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2231231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mfc140u.dll丢失怎么办? mfc140u.dll文件缺失的修复技巧

mfc140u.dll 是 Microsoft Foundation Classes (MFC) 库的一部分&#xff0c;它是 Visual Studio 2015 的组件之一&#xff0c;主要服务于使用 C 编写的 Windows 应用程序。这个动态链接库文件包含了 MFC 14.0 Unicode 版本的实现代码&#xff0c;为应用程序提供运行时支持。当…

Golang | Leetcode Golang题解之第520题检测大写字母

题目&#xff1a; 题解&#xff1a; func detectCapitalUse(word string) bool {// 若第 1 个字母为小写&#xff0c;则需额外判断第 2 个字母是否为小写if len(word) > 2 && unicode.IsLower(rune(word[0])) && unicode.IsUpper(rune(word[1])) {return f…

专题九——哈希表

目录 0简介 1两数之和 2判定是否互为字符重排 3存在重复元素 4存在重复元素 II 5字母异位词分组 0简介 1两数之和 oj链接&#xff1a;两数之和 解法1 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int nnums.size()…

unet中的attn_processor的修改(用于设计新的注意力模块)

参考资料 文章目录 unet中的一些变量的数据情况attn_processorunet.configunet_sd 自己定义自己的attn Processor &#xff0c;对原始的attn Processor进行修改 IP-adapter中设置attn的方法 参考的代码&#xff1a; 腾讯ailabipadapter 的官方训练代码 unet中的一些变量的数据…

客户端时间 与 服务器时间

对客户端时间和服务器有概念&#xff0c;但从来没有这么直观地观察过。直到有一天打开了长久未使用的mac&#xff0c;第一次对时间有了直观的概念&#xff1a; 打开之后就有了上面这样的提示“您的时钟慢了”… 我看了下电脑的时间&#xff0c;然后打开F12获取了下时间&#x…

VLAN高级特性:VLAN聚合

一、VLAN聚合的概述 在一般的三层交换机中&#xff0c;通常是采用一个VLAN对应一个VLANIF接口实现广播域之间的互通&#xff0c;这导致了在一些情况下造成了IP地址的浪费。 因为一个VLAN对应的子网中&#xff0c;子网号&#xff0c;子网广播地址、子网网关地址不能用作VLAN内…

Rust 力扣 - 2653. 滑动子数组的美丽值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们遍历长度为k的的窗口 因为数据范围比较小&#xff0c;所以我们可以通过计数排序找到窗口中第k小的数 如果小于0&#xff0c;则该窗口的美丽值为第k小的数如果大于等于0&#xff0c;则该窗口的美丽值为0 题…

2024网鼎杯青龙组wp:Crypto1

题目 附件内容如下 from Crypto.Util.number import * from secret import flag from Cryptodome.PublicKey import RSAp getPrime(512) q getPrime(512) n p * q d getPrime(299) e inverse(d,(p-1)*(q-1)) m bytes_to_long(flag) c pow(m,e,n) hint1 p >> (51…

《JVM第2课》类加载子系统(类加载器、双亲委派)

类加载系统加载类时分为三个步骤&#xff0c;加载、链接、初始化&#xff0c;下面展开介绍。 文章目录 1 类加载器1.1 引导类加载器&#xff08;BootStrapClassLoader&#xff09;1.2 拓展类加载器&#xff08;ExtClassLoader&#xff09;1.3 应用类加载器&#xff08;AppClas…

记住电机原理及几个重要公式,搞清楚电机so easy

电机作为电力转换设备&#xff0c;在现代工业、交通以及生活中发挥着无处不在的作用。无论是微型电动机还是大型发电机&#xff0c;它们的工作原理均基于一定的物理学和电磁学原理。 一、电机的基本原理 电机的基本原理可以概括为电能与机械能之间的相互转换。电动机通过电流在…

软件(2)

操作系统 windows、unix、linux、dos都属于操作系统 操作系统的核心部分的主要特点是【常驻内存】 【多用户分时系统】是当今计算机操作系统中最普遍使用的一类操作系统 操作系统的主要功能是【调度】、【监控】和【维护】计算机系统 负责管理计算机中各种独立的硬件&#xff0…

深度学习常用开源数据集介绍【持续更新】

DIV2K 介绍&#xff1a;DIV2K是一个专为 图像超分辨率&#xff08;SR&#xff09; 任务设计的高质量数据集&#xff0c;广泛应用于计算机视觉领域的研究和开发。它包含800张高分辨率&#xff08;HR&#xff09;训练图像和100张高分辨率验证图像&#xff0c;每张图像都具有极高…

计算机图形学中向量相关知识chuizhi

一、向量加法 平行四边形法则 两个向量统一起点&#xff0c;构成平行四边形&#xff0c;对角线为向量加和的结果 三角形法则 两个向量尾首相连&#xff0c;从a起点连接到b终点&#xff0c;为向量加法的结果 多向量首尾相连的加法结果为第一个向量的起点到最后一个向量的终点…

[LitCTF 2023]只需要nc一下~-好久不见6

先nc一下&#xff0c;连接上 ls打开查看里面有什么文件 cat 查看里面有什么内容 这个 Dockerfile 构建了一个基于 Python 3.11 的镜像&#xff0c;将当前目录的文件复制到镜像的 /app 目录&#xff0c;设置了一个环境变量 FLAG&#xff0c;并将其值写入 /flag.txt 文件。工作目…

软考高级之系统架构师之安全攻防技术

攻防包括攻击和防御两部分。 攻击 安全威胁 信息系统的安全威胁来自于&#xff1a; 物理环境&#xff1a;对系统所用设备的威胁&#xff0c;如&#xff1a;自然灾害&#xff0c;电源故障&#xff0c;数据库故障&#xff0c;设备被盗等造成数据丢失或者信息泄露通信链路&…

VLAN间通信以及ospf配置

目录 1.基础知识介绍 1.1 什么是VLAN&#xff1f; 1.2 VLAN有什么用&#xff1f; 1.3 不同VLAN如何实现通信&#xff1f; 1.4 什么是路由汇总&#xff1f; 1.4.1 路由汇总的好处&#xff1a; 2. 实验 2.1 网络拓扑设计 2.2 实验配置要求 2.2.1 三层交换配置&#xff…

ChatGPT变AI搜索引擎!以后还需要谷歌吗?

前言 在北京时间11月1日凌晨&#xff0c;正值ChatGPT两岁生日之际&#xff0c;OpenAI宣布推出最新的人工智能搜索体验&#xff01;具备实时网络功能&#xff01;与 Google 展开直接竞争。 ChatGPT搜索的推出标志着ChatGPT成功消除了即时信息这一最后的短板。 这项新功能可供 …

使用python画一颗圣诞树

具体效果&#xff1a; 完整代码&#xff1a; import random def print_christmas_tree(height): # 打印圣诞树的顶部 for i in range(height): # 打印空格&#xff0c;使树居中 for j in range(height - i - 1): print(" ", end"") # 打印星号&…

省级-碳排放相关数据(1990-2022年)

关键指标&#xff1a; 地区&#xff1a;数据涵盖了中国各省级行政区&#xff0c;为我们提供了一个全面的视角来观察不同地区的碳排放情况。年份&#xff1a;数据跨越了1990年至2022年&#xff0c;这为我们提供了一个长期的时间序列&#xff0c;以观察碳排放的变化趋势。总碳排…

评估 机器学习 回归模型 的性能和准确度

回归 是一种常用的预测模型&#xff0c;用于预测一个连续因变量和一个或多个自变量之间的关系。 那么&#xff0c;最后评估 回归模型 的性能和准确度非常重要&#xff0c;可以帮助我们判断模型是否有效并进行改进。 接下来&#xff0c;和大家分享如何评估 回归模型 的性能和准…