十一:C语言-操作符详解

news2024/11/14 1:53:46
1.了解二进制

其实二进制;八进制;十进制和十六进制都是数值的不同表示形式而已

  • 二进制:基数为2,由0和1两个数字组成,逢2进1。
  • 八进制:基数为8,由0~7八个数字组成,逢8进1。
  • 十进制:基数为10,由0~9十个数字组成,逢10进1。
  • 十六进制:基数为16,由0~9十个数字和A/a(10);B/b(11);C/c(12);D/d(13);E/e(14);F/f(15)六个数字共同组成,逢16进1。

(1)二进制转十进制

位权:以十进制为例

百位十位个位
十进制的位123
10^210^110^0
按权展开100101
求值1*100+2*10+3*1

注意:

  • 基数的多少次幂,这样的数被称为位权
  • 任何数的1次方都等于其本身;任何数的0次方都等于1

因此,二进制转十进制的做法如下:以二进制的111为例

二进制的位111
2^22^12^0
按权展开421
求值1*4+1*2+1*1

(2)十进制转二进制

口诀:转2除2,倒取余,从下往上依次排序

如:将十进制的10转为二进制

在这里插入图片描述

注意: 当里面的数小于外面的基数时,也就是除不开的时候,里面的数就是最后的余数

(3)二进制转八进制

方法:将3个二进制数划为一组,按421这个上标的顺序标上标(分组是从后往前分,标上标是从前往后标),不足3位的在最前边补0(0标上标后依旧是0,不参与运算)其余的每组上标相加得出结果,最后每个组的结果合并就是转换完成的八进制数

如:将二进制数1101111转换为八进制的数

二进制数:1101111
分组后001 101 111
上标421 421 421
八进制数结果1 + 5 + 7 = 157

注意: 以0开头的数字会被当做八进制

(4)二进制转十六进制

方法:将4个二进制数划为一组,按8421这个上标的顺序标上标(分组是从后往前分,标上标是从前往后标),不足4位的在最前边补0(0标上标后依旧是0,不参与运算)其余的每组上标相加得出结果,最后每个组的结果合并就是转换完成的十六进制数

如:将二进制数110110111转换为十六进制的数

二进制数:0001 1011 0111
分组后0001 1011 0111
上标8421 8421 8421
十六进制数结果1 + b + 7 = 0x1b7

注意:

  • 转换成十六进制时,10~15这些数字必须用字母表示
  • 表示十六进制的时候前面要加0x
2.原码、反码和补码

整数的二进制表示方法有3种:原码、反码和补码

这三种表示方法均有符号位和数值位两部分,符号位都是用0表示正、用1表示负;而数值位最高位的一位是被当做符号位,剩余的都是数值位。

正整数的原码、反码和补码都相同,但负整数的三种表示方法各不相同:

  • 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码
  • 反码:将原码的符号位(从左往右数第一位就是符号位)不变,数值位(除去符号位的其它位)依次按位取反就可以得到反码
  • 补码:反码+1就得到补码

如:int类型 5 的原码;反码和补码

在这里插入图片描述

如:int类型 -5 的原码;反码和补码

在这里插入图片描述

为什么表示5的是32位二进制数?

因为1字节等于8比特,而1个int类型占4个字节,也就是32比特位,所以用32个二进制数来表示

对于整型来说,数据存放内存中其实存放的是补码。 因为在计算机系统中,数值一律用补码来表示和存储。原因在于使用补码可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器);此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

示例:

int main()
{
	int a = 1;
	int b = -1;
	// 1 + (-1)
	
    // 0000000000 0000000000 000000000001 -- 1原码/补码
    
	// 1000000000 0000000000 000000000001 -- -1原码
	// 1111111111 1111111111 111111111110 -- -1反码
	// 1111111111 1111111111 111111111111 -- -1补码
}
3.移位操作符
  • << 左移操作符
  • >> 右移操作符

(1)左移操作符

移位规则:左边丢弃,右边补上0

代码示例:将num左移一位

#include <stdio.h>
int main()
{
    int num = 10;
    // num的二进制表示:0000000000 0000000000 0000001010
    int ret = num << 1;
    // num << 1的移位结果:000000000 0000000000 00000010100
    printf("num = %d\n",num);
    printf("ret = %d\n",ret);
    return 0;
}

注意:

  • 整个过程num本身的值是不会发生改变的,只有将移位过程赋值给num本身的时候值才会发生改变
  • 无论是正数还是负数,在内存中移位运算的都是补码

(2)右移操作符

  1. 逻辑右移:左边用0填充,右边丢弃
  2. 算术右移:左边用原该值的符号位填充,右边丢弃

注意:

右移所采用的是逻辑右移,还是算术右移是不确定的,取决于编译器。但是大部分的编译器是采用算术右移的

代码示例:将num右移一位(逻辑右移)

#include <stdio.h>
int main()
{
    int num = -1;
    // num的二进制表示:1111111111 1111111111 1111111111
    int ret = num >> 1;
    // num >> 1逻辑右移的移位结果:01111111111 1111111111 111111111
    printf("num = %d\n", num);
    printf("ret = %d\n", ret);
    return 0;
}

代码示例:将num右移一位(算术右移)

#include <stdio.h>
int main()
{
    int num = -1;
    // num的二进制表示:1111111111 1111111111 1111111111
    int ret = num >> 1;
    // num >> 1算术右移的移位结果:1111111111 1111111111 1111111111
    printf("num = %d\n", num);
    printf("ret = %d\n", ret);
    return 0;
}

注意:

  • 移位操作符的操作数只能是整数,不能是浮点数
  • 对于移位操作符,不要移动负数位,这个标准是未定义的
//如:
int num = 10;
num >> -1; //移动负数位是错误的
4.位操作符

位操作符有:

&  // 按位与
|  // 按位或
^  // 按位异或
~  // 按位取反操作符

注意:

  • 以上位操作符的操作数只能是整数
  • 位指的是二进制位

多说无益,代码示例:

(1)按位与的运算规则:对应的二进制位上,有0则为0,两个同时为1才为1

#include <stdio.h>
int main()
{
    // &
    int a = 5;
    int b = -6;
    int c = a & b; // 按位与
    // a的二进制表示:0000000000 0000000000 0000000101
    // b的二进制表示:1111111111 1111111111 1111111010
    printf("%d\n",c);
    // a & b:0000000000 0000000000 0000000000
    return 0;
}

(2)按位或的运算规则:对应的二进制位上,有1则为1,两个同时为0才为0

#include <stdio.h>
int main()
{
    // |
    int a = 5;
    int b = -6;
    int c = a | b; // 按位或
    // a的二进制表示:0000000000 0000000000 0000000101
    // b的二进制表示:1111111111 1111111111 1111111010
    printf("%d\n",c);
    // a | b:1111111111 1111111111 1111111111
    return 0;
}

(3)按位异或的运算规则:对应的二进制位上,相同则为0,相异则为1

#include <stdio.h>
int main()
{
    // ^
    int a = 5;
    int b = -6;
    int c = a ^ b; // 按位异或
    // a的二进制表示:0000000000 0000000000 0000000101
    // b的二进制表示:1111111111 1111111111 1111111010
    printf("%d\n",c);
    // a ^ b:1111111111 1111111111 1111111111
    return 0;
}

(4)按位取反的运算规则:二进制是0的变成1,是1的变成0

#include <stdio.h>
int main()
{
    int n = 0; // 0000000000 0000000000 000000000000
    int a = ~n; //按位取反 1111111111 1111111111 111111111111
    printf("%d\n",a);
    return 0;
}

练习1:实现两个数的交换

#include <stdio.h>
int main()
{
    int a = 3;
    int b = 5;
    int tmp = 0;
    printf("交换前:a = %d b = %d\n",a,b);
    tmp = a;
    a = b;
    b = tmp;
    printf("交换后:a = %d b = %d\n",a,b);
    return 0;
}

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

// 第一种方法
#include <stdio.h>
int main()
{
    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);
    return 0;
}

注意: 第一种的这个方法有缺陷,当a和b的数特别大的时候会导致范围越界

// 第二种方法
#include <stdio.h>
int main()
{
    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);
    return 0;
}

1. 异或运算符的特点:

  • a ^ a = 0
  • 0 ^ a = a
  • a ^ a ^ b = b
  • a ^ b ^ a = b

通过以上的特点分析得出一个结论:异或是支持交换律的

2. 异或运算的局限性:

  • 异或只能用于整数交换
  • 代码的可读性较差
  • 代码的执行效率也是低于使用第3变量的方法的

练习3:求一个整数存储在内存中的二进制中1的个数

// 第一种方法
#include <stdio.h>
int main()
{
    int a = 15;
    int count = 0;
    while(a)
    {
        if(a % 2 == 1)
        {
            count++;
        }
        a = a / 2;
    }
    printf("count = %d\n",count);
    return 0;
}
// 第二种方法
#include <stdio.h>
int main()
{
    int a = 0;
    scanf("%d",&a);
    int i = 0;
    int count = 0;
    for(i<0; i<32; i++)
    {
        if(((a>>i) & 1) == 1)
        {
            count++;
        }
    }
    printf("count = %d\n",count);
    return 0;
}
// 第三种方法
#include <stdio.h>
int main()
{
    int n = 0;
    int count = 0;
    scanf("%d",&n);
    while(n)
    {
        n = n & (n-1);
        count++;
    }
    printf("count = %d\n",count);
    return 0;
}

练习4:判断一个数是否是2^n次方

#include <stdio.h>
int main()
{
    int n = 0;
    scanf("%d",&n);
    
    if(n & (n - 1) == 0)
    {
        printf("yes\n");
    }
    else
    {
        printf("no\n");
    }
    return 0;
}

练习5:将a = 13的二进制位中第五位数字改为1,并且其它位保持不变

#include <stdio.h>
int main()
{
    int a = 13;
    // 0000000000 0000000000 000000001101
    // 0000000000 0000000000 000000010000
    // 1 << 4
    // 0000000000 0000000000 000000011101
    
    a = a | (1 << 4);
    printf("a = %d\n",a);
    return 0;
}

练习6:将a = 29的二进制位中第五位数字改为0,并且其它位保持不变

#include <stdio.h>
int main()
{
    int a = 29;
    // 0000000000 0000000000 000000011101
    a = a & ~(1 << 4);
    // 1111111111 1111111111 111111101111
    printf("a = %d\n",a);
    // 0000000000 0000000000 000000001101
    return 0;
}
5.逗号表达式
  • 逗号表达式就是用逗号隔开的多个表达式
  • 逗号表达式从左向右依次执行,整个表达式的结果是最后一个表达式的结果
  • 逗号操作符(,)的优先级是最低级的

代码示例:

#include <stdio.h>
int main()
{
    int a = 1;
    int b = 2;
    int c = (a > b, a = b + 10, b = a + 1);
    printf("%d\n",c);
    return 0;
}
6.下标访问和函数调用

(1)下标引用操作符:[]

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

#include <stdio.h>
int main()
{
	int arr[5] = {1,2,3,4,5}; // 创建一个数组
	printf("%d\n",arr[4]); // 使用下标引用操作符
    // 下标引用操作符( [] )的两个操作数就是 arr 和 4
	return 0;   
}

在上述的代码中,下标引用操作符([])的两个操作数就是 a 和 9

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

可以接收一个或者多个操作数:第一个操作数是函数名;剩余的操作数就是传递给函数的参数

#include <stdio.h>
int Add(int x, int y)
{
    return x+y;
}

int main()
{
    //函数的调用
    int ret = Add(1,2); // 使用函数调用操作符
    // 这个函数调用操作符:( () )的操作数就是 Add, 1, 2
    printf("%d\n",ret);
    return 0;
}

注意:

  1. 函数调用操作符至少要有一个操作数

  2. sizeof()不是函数,是操作符,因为sizeof后面的括号是可以省略掉的,而函数后面的括号是坚决不可以省略的。

// 代码示例:
#include <stdio.h>
int main()
{
    int a = 10;
    int n = sizeof a;
    printf("%d\n", n);
    return 0;
}
7.操作符的属性

C语言的操作符有两个重要的属性:优先级和结合性。这两个属性一定程度上决定了表达式求值的计算顺序。

(1)优先级

优先级指的是如果一个表达式包含多个运算符,那么哪个运算符应该优先执行。每种运算符的优先级是不一样的

常用运算符的优先级顺序(从上到下,优先级是由高到低的):

  1. 圆括号:()
  2. 自增运算符:++ ;自减运算符:--
  3. 单目运算符:+-
  4. 乘法:* ;除法:/
  5. 加法:+ ;减法:-
  6. 关系运算符:<>
  7. 赋值运算符:=

注意:

  1. 关于优先级,我们一般讨论的是两个相邻运算符的优先级

  2. 由于圆括号的优先级最高,因此可以使用它来改变其它运算符的优先级

(2)结合性

如果两个运算符的优先级相同,没办法确定先计算哪个,这时候就要看结合性了。根据运算符是左结合;还是右结合,决定执行顺序。大部分的运算符都是左结合(从左到右执行);只有少数运算符是右结合(从右到左执行)。

参考链接: C 运算符优先级 - cppreference.com

级和结合性。这两个属性一定程度上决定了表达式求值的计算顺序。

(1)优先级

优先级指的是如果一个表达式包含多个运算符,那么哪个运算符应该优先执行。每种运算符的优先级是不一样的

常用运算符的优先级顺序(从上到下,优先级是由高到低的):

  1. 圆括号:()
  2. 自增运算符:++ ;自减运算符:--
  3. 单目运算符:+-
  4. 乘法:* ;除法:/
  5. 加法:+ ;减法:-
  6. 关系运算符:<>
  7. 赋值运算符:=

注意:

  1. 关于优先级,我们一般讨论的是两个相邻运算符的优先级

  2. 由于圆括号的优先级最高,因此可以使用它来改变其它运算符的优先级

(2)结合性

如果两个运算符的优先级相同,没办法确定先计算哪个,这时候就要看结合性了。根据运算符是左结合;还是右结合,决定执行顺序。大部分的运算符都是左结合(从左到右执行);只有少数运算符是右结合(从右到左执行)。

参考链接: C 运算符优先级 - cppreference.com

在这里插入图片描述

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

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

相关文章

猫头虎 分享:Python库 SymPy 的简介、安装、用法详解入门教程 ‍

猫头虎 分享&#xff1a;Python库 SymPy 的简介、安装、用法详解入门教程 &#x1f431;‍&#x1f464; 今天猫头虎带您 深入了解 Python库 SymPy&#xff0c;这是一个强大且广泛应用于符号数学计算的库。最近有粉丝问猫哥&#xff1a;如何利用 SymPy 进行数学公式的符号化处…

【Maps JavaScript API】基础地图的创建与实现详解

文章目录 一、概述1. Google Maps JavaScript API 简介2. Simple Map 示例概述 二、创建一个基础地图1. 引入 Google Maps JavaScript API2. 初始化地图(1) 定义地图的 HTML 容器(2) 编写 JavaScript 代码初始化地图 3. 将地图集成到网页中 三、代码分析与关键点1. 地图中心点的…

32 增加系统调用(1)

系统调用在 数据手册中的描述 这是在 GDT 中的描述符 这个系统调用 segment selector 指向的时 内核的代码段。因为系统调用需要的权限比较高。 offset 指的时 在内核代码中的具体的函数的地址。

SQL Server 查询语句中,对索引列做CONVERT的影响

通常&#xff0c;在做SQL Server查询语句优化的时候&#xff0c;如果发现语句对索引列做了函数计算&#xff0c;都会建议改写&#xff0c;将计算的逻辑转移到筛选条件列上。但这种对索引列的计算&#xff0c;有时却会带来一些额外的好处。请看以下的例子&#xff1a; --测试数…

【Linux开发板pip安装库时报错解决】Error 28:No space left on device报错需要更换库的安装路径

之前在Linux开发板上尝试运行pytorch框架&#xff0c;但是需要安装torch和torchvision的库&#xff0c;很奇怪的是我按照之前pip3 install torch -i http://pypi.douban.com/simple --trusted-host pypi.douban.com的安装方式却出现了以下的报错&#xff1a; 系统报错提示说No …

R 语言学习教程,从入门到精通,R 绘图饼图(23)

1、R 绘图 条形图 条形图&#xff0c;也称为柱状图条形图&#xff0c;是一种以长方形的长度为变量的统计图表。 条形图可以是水平或垂直的&#xff0c;每个长方形可以有不同的颜色。 R 语言使用 barplot() 函数来创建条形图&#xff0c;格式如下&#xff1a; barplot(H,xlab,…

FastAPI+React18开发通用后台管理系统用户功能实战

最近开发了一个React18的后台管理系统&#xff0c;登录界面如下&#xff1a; 如果登录成功了则提示并跳转到首页&#xff1a; 点击注销按钮则提示退出系统成功&#xff1a; 没有登录就访问首页则提示请先登录。 这些功能是怎么实现的呢&#xff1f; 先看看登录功能使用…

JNA实践之Java模拟C结构体、结构体指针、结构体数组

目录 1 JNA模拟C结构体1.1 结构体本身作参数1.2 结构体指针作参数1.3 结构体内部嵌套结构体(结构体本身作参数)1.4 结构体指针作参数 2 结构体中嵌套结构体数组2.1 用作输入2.2 用作输出 3 结构体数组作参数典型错误1--内存不连续典型错误2--误用ByValue 4 Java映射C中char[]类…

scrapy--json结构数据-存储

免责声明:本文仅做演示与分享... 目录 基于命令存储的解析方法: settings.py blibli.py 基于管道存储的解析方法: 1-在爬虫文件中进行数据解析 2-在items.py定义相关属性 3-在 爬虫文件中 把 解析的数据存储封装到item类型对象中 4-把item类型对象提交给管道 5-在管道文件中…

软件设计之MySQL(6)

软件设计之MySQL(6) 此篇应在JavaSE之后进行学习: 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 Navicat可以在软件管家下载 使用navicat连接mysql数据库创建数据库、表、转储sql文件&#xff0c;导入sql数据 MySQL数据库入门到大牛&#xff0c;my…

【吊打面试官系列-Memcached面试题】memcached 能接受的 key 的最大长度是多少?

大家好&#xff0c;我是锋哥。今天分享关于 【memcached 能接受的 key 的最大长度是多少&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; memcached 能接受的 key 的最大长度是多少&#xff1f; key 的最大长度是 250 个字符。需要注意的是&#xff0c;250 是 m…

KEIL中分散加载文件基础知识

一、分散加载文件基本概念 1、分散加载文件&#xff1a;&#xff08;即scatter file 后缀为.scf&#xff09;是一个文本文件&#xff0c;通过编写一个分散加载文件来指定ARM连接器在生成映像文件时如何分配RO,RW,ZI等数据的存放地址。如果不用分散加载文件指定&#xff0c;那么…

区域形态学demo发布

demo实现了halcon中threshold、connection、fill_up、union、difference、intersection、dilation、erosion、opening、closing等算子功能&#xff0c;区域使用行程编码表示。目前可选择的结构元有圆形、矩形、十字&#xff08;实际接口没有限制&#xff09;&#xff0c;所有结…

Flutter-->Widget上屏之路

本文主要介绍Flutter中创建一个Widget到屏幕上渲染出Widget内容的路程. 拾用本文您将获得: Widget是什么Element是什么RenderObject是什么 附加Buff: Widget直接渲染成图片文本String的绘制图片ui.Image的绘制 这一切都要从runApp方法开始说起, 如果你还不知道runApp是什么…

【非常简单】 猿人学web第一届 第12题 入门级js

这一题非常简单&#xff0c;只需要找到数据接口&#xff0c;请求参数 m生成的逻辑即可 查看数据接口 https://match.yuanrenxue.cn/api/match/12 查看请求对应的堆栈中的 requests 栈 list 为对应的请求参数 list 是由 btoa 函数传入 ‘yuanrenxue’ 对应的页码生成的 bto…

安装torchvision==0.5.0

安装pytorch 1.4 但是在当前配置的镜像源中找不到 torchvision0.5.0 这个版本的包。 直接找资源下载 网址添加链接描述 直接运行该命令&#xff0c;成功。 然后重复运行上面的命令就可以了 # CUDA 9.2 conda install pytorch1.4.0 torchvision0.5.0 cudatoolkit9.2 -c pyto…

Spring Boot(快速上手)

Spring Boot 零、环境配置 1. 创建项目 2. 热部署 添加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional> </dependency&…

Linux下进程间的通信--消息队列

System V IPC的概念 System V IPC&#xff08;System V Interprocess Communication&#xff09;是Unix和类Unix操作系统中一套传统的进程间通信机制&#xff0c;它包括三种主要的通信方式&#xff1a;消息队列、信号量和共享内存。这些机制提供了一种在不同进程之间交换数据和…

llamaindex+Internlm2 RAG实践 #书生谱语大模型实战营#

1.打卡任务&#xff1a; 本次的打卡任务是llamaindexInternlm2 RAG实践&#xff0c;我们需要基于 LlamaIndex 构建自己的 RAG 知识库&#xff0c;寻找一个问题 A 在使用 LlamaIndex 之前InternLM2-Chat-1.8B模型不会回答&#xff0c;借助 LlamaIndex 后 InternLM2-Chat-1.8B 模…

Axure设计之下拉单选框教程(中继器)

在Axure RP中&#xff0c;使用中继器&#xff08;Repeater&#xff09;可以实现许多复杂而动态的用户界面组件&#xff0c;比如下拉单选框。本文将详细介绍如何通过中继器创建一个美观且功能丰富的下拉单选框。 一、案例预览 预览地址&#xff1a;https://1zvcwx.axshare.com …