【C语言基础】:操作符详解(二)

news2024/10/2 14:33:37

文章目录

    • 操作符详解
      • 一、上期扩展
      • 二、单目操作符
      • 三、逗号表达式
      • 四、下标访问[]、 函数调用()
      • 五、结构成员访问操作符
      • 六、操作符的属性:优先级、结合性
        • 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 = 5
	b = a - b;// a = 8, b = 3
	a = a - b;// a = 5, b = 3
	printf("交换后:a = %d b = %d\n", a, b);
	return 0;
}

在这里插入图片描述
很明显,这种方法也存在着明显的不足,那就是当a和b的值比较大时,a和b可能会超出int的范围,会出现溢出的现象,导致无法进行值的互换。

方法二:按位异或实现
上次我们学习了位操作符,其中按位异或就是对应二进制位相同为0,相异为1。根据这个特性,我们也能实现这个功能。

分析

首先我们要了解按位异或中几种特殊的情况。比如a ^ aa ^ 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 = a
	a = a ^ b;
	// a = a ^ b ^ a, 因为a ^ a等于0
	// 现在a = b, b = a
	printf("交换后: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(类型)

  1. 正号 (+):用于表示正数,例如 +5 表示正数 5。
  2. 负号 (-):用于表示负数,例如 -5 表示负数 5。
  3. 递增 (++):用于将操作数的值增加 1。可以作为前缀 (++i) 或后缀 (i++) 使用。
  4. 递减 (–):用于将操作数的值减少 1。可以作为前缀 (–i) 或后缀 (i–) 使用。
  5. 取址 (&):用于获取变量的内存地址,例如 &x 表示变量 x 的地址。
  6. 解引用 (*):用于访问指针所指向的内存中的值。例如,*ptr 表示指针 ptr 指向的值。
  7. 逻辑非 (!):用于求取操作数的逻辑非,即取反。例如,!x 表示 x 的逻辑非。
  8. 按位取反 (~):用于对操作数执行按位取反操作。例如, ~ 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)是一种用户自定义的数据类型,用于将不同类型的数据组合成一个单独的实体。结构体能够将多个变量打包成一个整体,方便操作和传递。

结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:标量、数组、指针,甚⾄是其他结构体。

结构体的声明包括两个部分:结构体模板的定义和结构体变量的声明。

  1. 结构体模板的定义:
struct 结构体名称 {
    数据类型 成员1;
    数据类型 成员2;
    // 更多成员...
};

其中,“结构体名称” 是用户定义的结构体类型的名称,可以根据需要自行命名。“成员1”、“成员2” 等是结构体中的成员变量,每个成员变量都有自己的数据类型。

【示例】:坐标结构体的定义

struct Point {
    int x;
    int y;
};

这个结构体定义了一个名为 Point 的结构体类型,它有两个成员变量 x 和 y,都是 int 类型。

  1. 结构体变量的声明:
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 。
运算符的优先级顺序很多,下⾯是部分运算符的优先级顺序(按照优先级从高到低排列),建议大概记住这些操作符的优先级就行,其他操作符在使用的时候查看下面表格就可以了。

• 圆括号( () )
• ⾃增运算符( ++ ),⾃减运算符( – )
• 单⽬运算符( + 和 - )
• 乘法( * ),除法( / )
• 加法( + ),减法( - )
• 关系运算符( < 、 > 等)
• 赋值运算符( = )

由于圆括号的优先级最高,可以使用它改变其他运算符的优先级。

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

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

相关文章

测试C#使用ViewFaceCore实现图片中的人脸遮挡

基于ViewFaceCore和DlibDotNet都能实现人脸识别&#xff0c;准备做个遮挡图片中人脸的程序&#xff0c;由于暂时不清楚DlibDotNet返回的人脸尺寸与像素的转换关系&#xff0c;最终决定使用ViewFaceCore实现图片中的人脸遮挡。   新建Winform项目&#xff0c;在Nuget包管理器中…

Windows常用协议

LLMNR 1. LLMNR 简介 链路本地多播名称解析(LLMNR)是一个基于域名系统(DNS)数据包格式的协议,可用于解析局域网中本地链路上的主机名称。它可以很好地支持IPv4和IPv6&#xff0c;是仅次于DNS 解析的名称解析协议。 2.LLMNR 解析过程 当本地hosts 和 DNS解析 当本地hosts 和 …

安装python的docker库

文章目录 一、在线安装二、制作离线安装包2.1 报错处理 一、在线安装 先确定是否有pip命令。 yum install python-pip直接安装。 pip install docker查看docker库。 pip list二、制作离线安装包 在有互联网的环境下直接安装。 #docker为下载下来的包名。 pip download do…

CCF-A类ASE‘ 24 6月7日截稿!共同探讨软件工程领域的未来!

会议之眼 快讯 第39届ASE (International Conference on Automated Software Engineering)即自动化软件工程国际会议将于 2024 年 10月27-11月1日在美国加利福尼亚州萨克拉门托举行&#xff01; ASE会议作为自动化软件工程领域的首要研究会议&#xff0c;承载着全球自动化软件工…

《高考》期刊杂志投稿邮箱知网教育类期刊发表

《高考》杂志是由国家新闻出版总署批准的正规教育类期刊。主要宣传高中新课程改革的专业性&#xff0c;是教育管理工作者、高中一线教师交流经验、探讨问题的重要平台&#xff0c;期刊突出政策性、针对性、指导性&#xff0c;是一本以教育科研成果展示为主&#xff0c;兼具教育…

邀请函 | 2024年数据技术嘉年华集结号已吹响,期待您参会!

龙腾四海内&#xff0c;风云际会时&#xff0c;2024年中国数据嘉年华如约而至。从起初小范围的网友聚会&#xff0c;到如今面向全国各地从业者、爱好者的年度集会&#xff0c;纵使岁月更迭&#xff0c;我们初心依旧。我们在各自最好的年华里共同见证了中国数据库行业的蓬勃发展…

MySQL-JDBC

1. JDBC介绍 JDBC&#xff08;Java Database Connectivity&#xff09;是 Java 连接数据库的标准接口&#xff0c;它提供了一种与数据库交互的统一方式&#xff0c;使得 Java 程序能够通过标准 API 访问和操作各种关系型数据库。 2. JDBC使用步骤 第0步&#xff1a;导bao 第1步…

TensorRT推理时,如何比对中间层的误差

TensorRT推理时,如何比对中间层的误差 有二种方案第二种方案的实现1.运行环境的搭建2.实现代码(compare_trt_onnxrt.py)3.运行4.输出 本文演示了TensorRT推理时,如何比对中间层的误差。 在做TensorRT推理加速时,可能会遇到精度问题,希望定位到是哪一个节点引起的误差,还是累计误…

10.vue学习笔记(组件数据传递-props回调函数子传父+透传Attributes+插槽slot)

文章目录 1.组件数据传递2.透传Attributes&#xff08;了解&#xff09;禁用Attributes继承 3.插槽slot3.1.插槽作用域3.2.默认内容3.3.具名插槽3.4.插槽中的数据传递3.5.具名插槽传递数据 1.组件数据传递 我们之前讲解过了组件之间的数据传递&#xff0c;props 和 自定义事件…

【IDEA】java 项目启动偶现Kotlin 版本问题 error:Kotlin:module was

一、问题描述&#xff1a; error:Kotlin:module was compiled with an incompatible version of kotlin the binary version of its metadata is二、问题原因&#xff1a; jar包版本冲突 三、解决方式&#xff1a; 1、Rebuild Project&#xff08;推荐☆&#xff09; 重新构…

小迪安全30WEB 攻防-通用漏洞SQL 注入CTF二次堆叠DNS 带外

#知识点&#xff1a; 1、数据库堆叠注入 根据数据库类型决定是否支持多条语句执行 2、数据库二次注入 应用功能逻辑涉及上导致的先写入后组合的注入 3、数据库 Dnslog 注入 解决不回显(反向连接),SQL 注入,命令执行,SSRF 等 4、黑盒模式分析以上 二次注入&…

2024.2.21 模拟实现 RabbitMQ —— 实现转发规则

目录 需求分析 直接交换机&#xff08;Direct &#xff09; 主题交换机&#xff08;Topic &#xff09; 扇出交换机&#xff08;Fanout &#xff09; Topic 交换机转发规则 routingKey 组成 bindingKey 组成 匹配规则 情况一 情况二 情况三 实现 Router 类 校验 b…

【AIGC大模型】跑通wonder3D (windows)

论文链接&#xff1a;https://arxiv.org/pdf/2310.15008.pdf windows10系统 显卡&#xff1a;NVIDIA rtx 2060 一、安装anaconda 二、安装CUDA 11.7 (CUDA Toolkit 11.7 Downloads | NVIDIA Developer) 和 cudnn 8.9.7(cuDNN Archive | NVIDIA Developer)库 CUDA选择自定…

【Android】坐标系

Android 系统中有两种坐标系&#xff0c;分别为 Android 坐标系和 View 坐标系。了解这两种坐标系能够帮助我们实现 View 的各种操作&#xff0c;比如我们要实现 View 的滑动&#xff0c;你连这个 View 的位置都不知道&#xff0c;那如何去操作呢&#xff1f; 一、Android 坐标…

【Spring Cloud】高并发带来的问题及常见容错方案

文章目录 高并发带来的问题编写代码修改配置压力测试修改配置&#xff0c;并启动软件添加线程组配置线程并发数添加Http取样配置取样&#xff0c;并启动测试访问message方法观察效果 服务雪崩效应常见容错方案常见的容错思路常见的容错组件 总结 欢迎来到阿Q社区 https://bbs.c…

《极简C++学习专栏》之结束语

朋友们&#xff0c;经过这么长的时间&#xff0c;《极简C学习专栏》的文章创作就要结束了&#xff0c;感谢你们一路陪伴&#xff01; 也希望你们能支持我接下来的其他专栏的创作&#xff01; 专栏的初衷 《极简C学习》专栏的初衷源自于我个人的学习笔记&#xff0c;记录下自己…

【刷题】牛客 JZ64 求1+2+3+...+n

刷题 题目描述思路一 &#xff08;暴力递归版&#xff09;思路二 &#xff08;妙用内存版&#xff09;思路三 &#xff08;快速乘法版&#xff09;思路四 &#xff08;构造巧解版&#xff09;Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01…

Java 面向对象进阶 18 JDK8、9开始新增的方法;接口的应用;适配器设计模式;内部类(黑马)

一、JDK8开始新增的方法 默认方法不是抽象方法&#xff0c;所以不强制被重写&#xff1a; 但是如果被重写&#xff0c;就要去掉default关键字&#xff1a; public可以省略&#xff0c;但是default不可以省略&#xff1a; public是灰色的&#xff0c;代表可以省略 但是default是…

怎么把pdf转换成word?

怎么把pdf转换成word&#xff1f;Pdf和word在电脑上的使用非常广泛&#xff0c;pdf和word分别是由 Adobe和Microsoft 分别开发的电脑文件格式。PDF 文件可以在不同操作系统和设备上保持一致的显示效果&#xff0c;无论是在 Windows、Mac 还是移动设备上查看&#xff0c;都能保持…

使用Docker部署MinIO并结合内网穿透实现远程访问本地数据

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…