【C语言基础】:操作符详解(二)
文章目录
- 操作符详解
- 一、上期扩展
- 二、单目操作符
- 三、逗号表达式
- 四、下标访问[]、 函数调用()
- 五、结构成员访问操作符
- 六、操作符的属性:优先级、结合性
- 1. 优先级
- 2. 结合性
操作符详解
上期回顾:【C语言基础】:操作符详解(一)
一、上期扩展
【练习一】:不能创建临时变量(第三个变量), 实现两个整数的交换。
方法一:我们可以运用加减法来实现这个功能。
分析:
交换前:a = 3,b = 5;
我们先让 a + b 然后把这个结果赋值给a,也就是a = a + b;
现在a的值变成了8,而b的值还是5;
接下来我们让a - b,把这个表达式赋值给吧,也就是b = a - b;
现在a的值是8,b的值是3;
最后我们只要将a - b这个表达式赋值给a就行啦,也就是a = a - b。
我们就会发现a和b的值发生了互换。
下面是代码实现:
#include<stdio.h>
int main()
{int a = 3;int b = 5;printf("交换前:a = %d b = %d\n", a, b);a = a + b;// a = 8, b = 5b = a - b;// a = 8, b = 3a = a - b;// a = 5, b = 3printf("交换后:a = %d b = %d\n", a, b);return 0;
}

很明显,这种方法也存在着明显的不足,那就是当a和b的值比较大时,a和b可能会超出int的范围,会出现溢出的现象,导致无法进行值的互换。
方法二:按位异或实现
上次我们学习了位操作符,其中按位异或就是对应二进制位相同为0,相异为1。根据这个特性,我们也能实现这个功能。
分析:
首先我们要了解按位异或中几种特殊的情况。比如a ^ a,a ^ 0等等。
1101
1101
按位异或后的结果就是0,而任何数与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; // b = a ^ b ^ b, b ^ b就等于0// 现在a = a ^ b, b = aa = a ^ b;// a = a ^ b ^ a, 因为a ^ a等于0// 现在a = b, b = aprintf("交换后:a = %d b = %d\n", a, b);return 0;
}

这种方法也存在着局限性,首先要知道按位操作符的操作数必须是整数,其次代码的可读性也不高,不方便他人理解。
【练习二】编写代码实现:求一个整数存储在内存中的二进制中1的个数。
方法一:通过不断的去模2,除2来获得二进制中1的个数。
注意:这里是指补码。
#include<stdio.h>
int count_one_of_bite(unsigned int n)
{int count = 0; // 计数while (n){if (n % 2 == 1)count++;n = n / 2;}return count;
}
int main()
{int n = 0;scanf("%d", &n);int ret = count_one_of_bite(n);printf("二进制中一的个数:%d\n", ret);return 0;
}

方法二:n & (n - 1)
#include<stdio.h>
int count_one_of_bite(unsigned int n)
{int count = 0; // 计数while (n){count++;n = n & (n - 1);}return count;
}
int main()
{int n = 0;scanf("%d", &n);int ret = count_one_of_bite(n);printf("二进制中一的个数:%d\n", ret);return 0;
}

二、单目操作符
单目操作符(Unary Operator)是一种只操作一个操作数的操作符。
!、++、–、&、、+、-、~*、sizeof(类型)
- 正号 (+):用于表示正数,例如 +5 表示正数 5。
- 负号 (-):用于表示负数,例如 -5 表示负数 5。
- 递增 (++):用于将操作数的值增加 1。可以作为前缀 (++i) 或后缀 (i++) 使用。
- 递减 (–):用于将操作数的值减少 1。可以作为前缀 (–i) 或后缀 (i–) 使用。
- 取址 (&):用于获取变量的内存地址,例如 &x 表示变量 x 的地址。
- 解引用 (*):用于访问指针所指向的内存中的值。例如,*ptr 表示指针 ptr 指向的值。
- 逻辑非 (!):用于求取操作数的逻辑非,即取反。例如,!x 表示 x 的逻辑非。
- 按位取反 (~):用于对操作数执行按位取反操作。例如, ~ x 表示对 x 的每个位取反。
这些是 C 语言中常用的一些单目操作符。它们可以用来执行各种不同的操作,如数值运算、递增递减、逻辑运算和位运算等。
三、逗号表达式
逗号表达式(Comma Expression)是一种由逗号操作符连接起来的表达式,其特点是依次计算每个子表达式,并返回最后一个子表达式的值作为整个表达式的值。逗号表达式的一般形式如下:
expr1, expr2, expr3, ..., exprN
在逗号表达式中,逗号操作符 , 用于连接多个子表达式。在计算逗号表达式时,每个子表达式都会按顺序依次执行,但整个表达式的值将是最后一个子表达式的值。
逗号表达式在 C 语言中可以用于一些特定的场景,如在 for 循环的初始化和迭代部分、函数调用参数中以及变量初始化等地方。例如,在 for 循环中使用逗号表达式可以同时初始化多个变量:
for (int i = 0, j = 10; i < 10; i++, j--) {// 循环体
}
在函数调用参数中使用逗号表达式可以依次计算多个表达式并将它们作为函数的参数:
int result = myFunction(a, b, c+1, d*2);
逗号表达式的使用要谨慎,因为它可能会使代码变得难以理解。在某些情况下,使用逗号表达式可能降低代码的可读性,因此应该根据具体情况慎重考虑是否使用。
【练习】
#include<stdio.h>
int main()
{int a = 1;int b = 2;int c = (a > b, a = b + 10, a, b = a + 1); // 逗号表达式printf("%d\n", c);return 0;
}
可以看到,第六行是一个逗号表达式,从左到右依次进行计算,最后返回最右边的结果。

四、下标访问[]、 函数调用()
[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值(下标)
【举例】
int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
[]的两个操作数是arr和9。
函数调用操作符
接受一个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。
【举例】
#include <stdio.h>
void test1()
{printf("hehe\n");
}
void test2(const char *str)
{printf("%s\n", str);
}
int main()
{test1(); //这⾥的()就是作为函数调⽤操作符。test2("hello world");//这⾥的()就是函数调⽤操作符。return 0;
}
五、结构成员访问操作符
结构体
结构体(Struct)是一种用户自定义的数据类型,用于将不同类型的数据组合成一个单独的实体。结构体能够将多个变量打包成一个整体,方便操作和传递。
结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:标量、数组、指针,甚⾄是其他结构体。
结构体的声明包括两个部分:结构体模板的定义和结构体变量的声明。
- 结构体模板的定义:
struct 结构体名称 {数据类型 成员1;数据类型 成员2;// 更多成员...
};
其中,“结构体名称” 是用户定义的结构体类型的名称,可以根据需要自行命名。“成员1”、“成员2” 等是结构体中的成员变量,每个成员变量都有自己的数据类型。
【示例】:坐标结构体的定义
struct Point {int x;int y;
};
这个结构体定义了一个名为 Point 的结构体类型,它有两个成员变量 x 和 y,都是 int 类型。
- 结构体变量的声明:
struct 结构体名称 变量名称;
在结构体定义之后,可以通过声明结构体变量来创建实际的结构体对象。
【示例】:使用上述定义的 Point 结构体来声明一个名为 p 的结构体变量
struct Point p;
现在,变量 p 是一个具有两个成员变量的结构体对象。可以通过 . 运算符来访问结构体的成员变量,例如 p.x 或 p.y。
另外,C 语言还提供了一种更简洁的方式来声明结构体变量,即使用 typedef 关键字:
typedef struct {数据类型 成员1;数据类型 成员2;// 更多成员...
} 结构体名称;
这样就可以直接使用 结构体名称 来定义结构体变量,而不需要再写 struct 关键字。例如:
typedef struct {int x;int y;
} Point;
Point p;
这里的 Point 就是一个结构体类型,并且可以直接用于声明结构体变量。
//代码1:变量的定义
struct Point
{int x;int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2//代码2:初始化。
struct Point p3 = { 10, 20 };struct Stu //类型声明
{char name[15];//名字int age; //年龄
};struct Stu s1 = { "zhangsan", 20 };//初始化
struct Stu s2 = { .age = 20, .name = "lisi" };//指定顺序初始化//代码3
struct Node
{int data;struct Point p;struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化
结构体成员的直接访问
结构体成员的直接访问是通过点操作符( .) 访问的。点操作符接受两个操作数。如下所示:
#include <stdio.h>
struct Point
{int x;int y;
}p = { 1,2 };
int main()
{printf("x: %d y: %d\n", p.x, p.y);return 0;
}

使用方式:结构体变量.成员名
结构体成员的间接访问
有时候我们得到的不是⼀个结构体变量,而是得到了⼀个指向结构体的指针。如下所示:
#include <stdio.h>
struct Point
{int x;int y;
};
int main()
{struct Point p = {3, 4};struct Point *ptr = &p;ptr->x = 10;ptr->y = 20;printf("x = %d y = %d\n", ptr->x, ptr->y);return 0;
}

使用方式:结构体指针->成员名
综合举例:
#include <stdio.h>
#include <string.h>
struct Stu
{char name[15];//名字int age; //年龄
};
void print_stu(struct Stu s)
{printf("%s %d\n", s.name, s.age);
}
void set_stu(struct Stu* ps)
{strcpy(ps->name, "李四");ps->age = 28;
}
int main()
{struct Stu s = { "张三", 20 };print_stu(s);set_stu(&s);print_stu(s);return 0;
}

六、操作符的属性:优先级、结合性
C语⾔的操作符有2个重要的属性:优先级、结合性,这两个属性决定了表达式求值的计算顺序。
1. 优先级
优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执⾏。各种运算符的优先级是不⼀样的。
3 + 4 * 5;
上⾯⽰例中,表达式 3 + 4 * 5 ⾥⾯既有加法运算符( + ),⼜有乘法运算符( * )。由于乘法的优先级⾼于加法,所以会先计算 4 * 5 ,⽽不是先计算 3 + 4 。


2. 结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执行顺序。⼤部分运算符是左结合(从左到右执行),少数运算符是右结合(从右到左执行),比如赋值运算符( = )。
5 * 6 / 2;
上面示例中, * 和 / 的优先级相同,它们都是左结合运算符,所以从左到右执行,先计算 5 * 6 ,再计算 6 / 2 。
运算符的优先级顺序很多,下⾯是部分运算符的优先级顺序(按照优先级从高到低排列),建议大概记住这些操作符的优先级就行,其他操作符在使用的时候查看下面表格就可以了。
• 圆括号( () )
• ⾃增运算符( ++ ),⾃减运算符( – )
• 单⽬运算符( + 和 - )
• 乘法( * ),除法( / )
• 加法( + ),减法( - )
• 关系运算符( < 、 > 等)
• 赋值运算符( = )
由于圆括号的优先级最高,可以使用它改变其他运算符的优先级。
相关文章:
【C语言基础】:操作符详解(二)
文章目录 操作符详解一、上期扩展二、单目操作符三、逗号表达式四、下标访问[]、 函数调用()五、结构成员访问操作符六、操作符的属性:优先级、结合性1. 优先级2. 结合性 操作符详解 上期回顾:【C语言基础】:操作符详解(一) 一、上期扩展 …...
模型训练基本结构
project_name/ │ ├── data/ │ ├── raw/ # 存放原始数据 │ ├── processed/ # 存放预处理后的数据 │ └── splits/ # 存放数据集划分(训练集、验证集、测试集等) │ ├── noteboo…...
Redis 数据结构详解:底层实现与高效使用场景
String(字符串) 底层实现细节: 动态字符串(SDS): SDS相比于C语言的原生字符串,提供了自动内存管理和预分配机制。当字符串长度增加时,SDS会预先分配额外的空间,以减少内存重新分配…...
Vue2:router-link的replace属性
一、情景说明 我们在用浏览器访问网站的时候 知道浏览器会记录访问的历史路径,从而,可以退回到之前的页面 那么,Vue项目中的路由组件,通过router-link跳转,也是可以退回的 这里,我们用replace来屏蔽退回的…...
普中51单片机(DS18B20温度传感器)
DS18B20温度传感器原理 内部结构 64位(激)光刻只读存储器 光刻ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列号。64位光刻ROM的排列是:开始8位(28H)是产品类型标号,接着的48位是该DS18B20自身…...
2.23C语言学习
P1480 A/B Problem 高精度数除以非高精度数 #include<bits/stdc.h> long long b[66660],c[66660],sum0; char a[66660]; int n; int main(){scanf("%s",a);scanf("%d",&n);int lenstrlen(a);for(int i1;i<len;i){b[i]a[i-1]-0;}for(int i1;…...
origin/master master
这里实际上有三件事:origin master是两件事,origin/master一件事。共计三件事。 两个分支: master 是一个本地分支 origin/master是远程分支(它是名为“origin” 的远程分支的本地副本,名为“master”) 一个…...
【数据结构】时间复杂度与空间复杂度
目录 时间复杂度 空间复杂度 时间复杂度 算法的时间复杂度并不是指一个代码运行时间的快慢,因为在不同机器上运行的时间肯定不同,因此算法的时间复杂度指的是基本操作的执行次数,他是一个数学意义上的函数。这个函数并不是C语言中那种函数&…...
分别使用js与jquery写 单击按钮时出现内容 点击删除按钮不会再向下出现
HTML部分 <body><button id"btn">单击我</button><button id"delAll">删除所有事件</button><div id"test"></div> </bady>jQuery代码 <script type"text/JavaScript" src"…...
【Git】Git命令的学习与总结
本文实践于 Learn Git Branching 这个有趣的 Git 学习网站。在该网站,可以使用 show command 命令展示所有可用命令。你也可以直接访问网站的sandbox,自由发挥。 一、本地篇 基础篇 git commit git commit将暂存区(staging areaÿ…...
前端工程化面试题 | 18.精选前端工程化高频面试题
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
大公司的工程师是怎么废掉的...
大家好,我是砖一。 此文作者以嵌入式工程师为基本视角,细说了从初阶到高阶工程师的资质需求,并提示工程师职业道路上的陷阱。可供参考。 一,基础知识 一个嵌入式工程师,很多都是从51单片机或者STM32单片机开始&…...
将yolov8权重文件转为onnx格式并在c#中使用
yolo模型转ONNX 在yolov8中,我们将训练结果的.pt权重文件转换为onnx格式只需要使用ultralytics库中的YOLO类,使用pip安装ultralytics库,然后执行下面python代码 from ultralytics import YOLO# 加载YOLOv8模型 model YOLO("best.pt&q…...
在Spring Boot启动时禁止自动配置数据源相关的组件、@SpringBootApplication
一、SpringBootApplication(exclude {DataSourceAutoConfiguration.class})注解 在Spring Boot启动时禁止自动配置数据源相关的组件。 SpringBootApplication(exclude {DataSourceAutoConfiguration.class})注解的使用案例 这个注解通常应该写在微服务项目的主启动类上&…...
程序人生:不积跬步无以致千里
程序人生 癸卯年冬月,往渭南韩城,拜访司马迁祠。入门攀爬而上,至人有困乏之时,抬头现:高山仰止。归路下山,始现三官洞,遥想西汉时三官洞,出口处刻意再拜别:高山仰止。泪…...
通过二叉树例题深入理解递归问题
目录 引入: 例1:二叉树的前序遍历: 例2: N叉树的前序遍历: 例3:二叉树的最大深度: 例4:二叉树的最小深度 例5:N叉树的最大深度: 例6:左叶子…...
【Android 协程常见用法】
我们这里只讲解一下,协程在Android项目中常见用法,原理知识不在进行说明了。 依赖 lifecycleScope只能在Activity、Fragment中使用,会绑定Activity和Fragment的生命周期。依赖库: implementation androidx.lifecycle:lifecycle…...
python 进程笔记一 (概念+示例代码)
1. 进程的概念 进程是资源分配的最小单位,也是线程的容器,线程(python 线程 (概念示例代码))是CPU调度的基本单位,一个进程包括多个线程。 程序:例如xxx.py是一个程序 进程…...
各中间件数据库默认访问端口总结
说明 在生态丰富的开发环境下,我们常常需要接触很多中间件产品,中间件默认的连接端口以及可视化ui访问端口也时不时的需要用到,这里循序渐进做好登记,以备查阅! 中间件/数据库名称默认端口管理台端口默认账号密码rabbi…...
鲲鹏arm64架构下安装KubeSphere
鲲鹏arm64架构下安装KubeSphere 官方参考文档: https://kubesphere.io/zh/docs/quick-start/minimal-kubesphere-on-k8s/ 在Kubernetes基础上最小化安装 KubeSphere 前提条件 官方参考文档: https://kubesphere.io/zh/docs/installing-on-kubernetes/introduction/prerequi…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
Java多线程实现之Runnable接口深度解析
Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...
Python第七周作业
Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt,并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径,并创建logs目录(若不存在) 3.递归遍历目录data,输出所有.csv文件的路径…...
轻量安全的密码管理工具Vaultwarden
一、Vaultwarden概述 Vaultwarden主要作用是提供一个自托管的密码管理器服务。它是Bitwarden密码管理器的第三方轻量版,由国外开发者在Bitwarden的基础上,采用Rust语言重写而成。 (一)Vaultwarden镜像的作用及特点 轻量级与高性…...
电脑定时关机工具推荐
软件介绍 本文介绍一款轻量级的电脑自动关机工具,无需安装,使用简单,可满足定时关机需求。 工具简介 这款关机助手是一款无需安装的小型软件,文件体积仅60KB,下载后可直接运行,无需复杂配置。 使用…...
