【C语言初阶】带你轻松玩转所有常用操作符(2) ——赋值操作符,单目操作符

news2024/11/14 19:55:51

在这里插入图片描述

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发


Hello,这里是君兮_,今天给大家带来的是有关操作符的第二部分内容,废话不多说,咱们直接开始吧!

  • 在正式开始之前,我们还是借助一张思维导图帮助大致简单回忆一下有关操作符的基础内容

在这里插入图片描述

  • 我们接着之前的内容朝下讲:

操作符详解2

  • 一.赋值操作符
    • 复合赋值符
  • 二.单目操作符
    • 1.单目操作符介绍
    • 2.逻辑反操作符 !
    • 3.求操作数的类型长度 sizeof
      • sizeof与数组
      • sizeof 在使用过程中常出的几种错误
    • 4.前置++与前置- -
    • 5.后置++与后置- -
      • 举例证明前置后置的优先级
    • 6. ~ 按补码二进制位取反
    • 7.取地址操作符&和解引用操作符*
    • 8.强制类型转换()
  • 总结

一.赋值操作符

赋值操作符是一个非常有用的操作符,它可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值。
  • 赋值操作符也可以连续赋值
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值
//但是同样的语义我们也可以下面这样
x = y+1;
a = x;
//这样的写法是不是更加清晰爽朗而且易于调试。
  • 所以我们一般都不是特别推荐连续赋值。

复合赋值符

  • 加等于 +=
  • 减等于 -=
  • 乘等于 *=
  • 除等于 /=
  • 取余等于 %=
  • 右移等于 >>=
  • 左移等于 <<=
  • 按位与等于 &=
  • 按位或等于 |=
  • 按位异或等于 ^=
  • 这些运算符都可以写成复合的效果。

比如:
int x = 10;
x = x+10;
x += 10;//复合赋值与上一行意思相同
//其他运算符一样的道理。这样写更加简洁

二.单目操作符

1.单目操作符介绍

逻辑反操作 !
负值 -
正值 +
取地址 &
操作数的类型长度(以字节为单位) sizeof
对一个数的二进制按位取反 ~
前置 --、后置 –
前置 ++、后置 ++
间接访问操作符( 解引用操作符) *
强制类型转换 (类型)

  • 先举几个简单的例子带大家认识一下,然后咱们在中间挑几个比较重要的讲解一下。

#include <stdio.h>
int main()
{
	int a = -10;
	int* p = NULL;
	printf("%d\n", !2);
	printf("%d\n", !0);
	a = -a;
	p = &a;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof a);//这样写行不行?
	//printf("%d\n", sizeof int);//这样写行不行?
}
  • 我们来看下结果:
    在这里插入图片描述

2.逻辑反操作符 !

  • 注意看我们上面的运行结果
printf("%d\n", !2);
printf("%d\n", !0);
  • 这两个输出结果我们可以看到分别是“0”和“1”
  • 也就是说!为假时(即值为0)时为真(非0),!不为假时才判为假(0)

3.求操作数的类型长度 sizeof

  • sizeof的基本用法是这样的
sizof(所求类型)
  • 但是,我们通过上面这个例子的结果可以看出来:
    printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof a);//这样写行不行?
  • 对于一个变量来说,sizof的括号是可省略的,但是如果所求长度为一个类型的话,这个括号就必须要加上!

sizeof与数组

  • 通常来说,我们的sizeof广泛用于求一个数组的长度与元素个数。
  • 下面举一个实战例子来说明

利用二分法在某个有序数组里具体找到某个数,并打印出该数的数组下标。

  • 二分法具体的使用方法和适用场景我已经写过详解博客,这里只是引用这个例子,具体不再展开讲,如果你感兴趣的话,请移步下方链接哦!
    【C语言】带你玩转经典算法用二分法在一个有序数组中查找某个数
  • 代码如下:
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//升序
	
	int k = 7;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//利用数组的总大小除以数组中一个元素的大小,得到数组中一共存放了几个元素
	//1
	int left = 0;
	int right = sz-1;//数组下标是数组元素个数-1
	int flag = 0;//flag的作用是标志是否找到了
	//2
	while (left<=right)//当左右都指向同一个数时还没找到,说明此数不存在
	{
		int mid = (left + right) / 2;
		if (arr[mid] == k)
		{
			printf("找到了,下标是:%d\n", mid);
			flag = 1;//令flag等于1
			break;
		}
		else if (arr[mid] < k)//mid就比k小,舍去比mid更小的数
		{
			left = mid + 1;
		}
		else//mid比k大,舍去比mid大的数
		{
			right = mid - 1;
		}
	}
	//1 2
	if (flag == 0)//判断是否找到k,如果找到,flag应等于1
		printf("没找到\n");

	return 0;
}
  • 请注意这里:
int sz = sizeof(arr) / sizeof(arr[0]);//利用数组的总大小除以数组中一个元素的大小,得到数组中一共存放了几个元素
  • 我们这里利用sizeof成功的拿到了数组元素的个数方便我们后一步进行二分法查找

sizeof 在使用过程中常出的几种错误

  • 我们这里还是通过代码带大家展开接下来的内容
#include <stdio.h>


void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//(4)
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));//(1)
	printf("%d\n", sizeof(ch));//(3)
	test1(arr);
	test2(ch);
	return 0;
}
/*问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少*/
  • 来看结果:

在这里插入图片描述

  • 怎么回事?我两个明明计算的是同一个数组的大小,怎么结果不一样呢?

  • 这里就是数组以及指针的知识啦,我来说明一下原因:

  • 1.数组在被当作参数在函数之间传递时,传过去的其实是首元素的地址,因此在计算的是首元素地址的大小!

  • 2.对于一个int整型数据来说占四个字节,10个就是40个字节,而一个char型数据只占1个字节,10个就是10个字节,这就是出现上面答案的原因。

  • 到这里,可能还有小可爱要问了,这里的char型为啥占4个字节啊?你不是说一个char型只占1个字节吗?

  • 嗯…
    在这里插入图片描述

  • 注意了,这里如果你是这么认为的话,那么说明你还是没有理解我上面的解释哈,建议再多看看指针相关内容哦!

  • 我们这里虽然写的传入形式是两个数组

void test1(int arr[])
void test2(char ch[])
  • 但实际我们说了,传进去的是首元素的地址,实际上是指针,因此我们也可以这么写:
void test1(int *arr)
void test2(char *ch)

在这里插入图片描述

  • 结果依然是对的。
  • 而对于指针的大小来说,在相同操作系统下,所有指针类型的大小都是相同的,我们这里采用的是32位操作系统,指针变量的大小统一都是4个字节,而64位则统一都是8个字节。

在这里插入图片描述

  • 现在,我想你应该明白上述结果出现的原因了吧!

4.前置++与前置- -

其实这一块没啥好讲的,我们唯一需要注意的是,在使用时,是先执行++或- -操作再进行下一步。

  • 举例说明:
//前置++和--
#include <stdio.h>
int main()
{
  int a = 10;
  int x = ++a;
  //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
  int y = --a;
  //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
  return 0;
  }

5.后置++与后置- -

与前置++和前置- -相反,后置的++ - -是等表达式执行完后,再执行++或- -操作

  • 举例如下:
//后置++和--
#include <stdio.h>
int main()
{
  int a = 10;
  int x = a++;
  //先对a先使用,再增加,这样x的值是10;之后a变成11;
  int y = a--;
  //先对a先使用,再自减,这样y的值是11;之后a变成10;
  return 0;
  }

举例证明前置后置的优先级

下面我们来通过一个具体例题来证明一下我上面讲述的内容

#include <stdio.h>
int main()
{
	int a, b, c;
	a = 5;
	c = ++a;
	b = ++c, c++, ++a, a++;
	b += a++ + c;
	printf("a = %d b = %d c = %d\n:", a, b, c);
	return 0;
}
  • 来判断一下上面这段代码的输出结果
  • 这里就不卖关子了直接公布答案:
    在这里插入图片描述
  • 和你想的结果一样吗?
  • 我们来具体讲解一下

int main()
{
	int a, b, c;
	a = 5;
	c = ++a;//前置++ c=6
	b = ++c, c++, ++a, a++;//逗号表达式整个表达式的结果是最后一个表达式的结果,这里先记住这个结论,具体解释我们后面再说
	//此时b=a++,由于后置这里就是a,但是前面执行了++a,此时a的值为7所有b就等于7
	//执行完b表达式后,开始执行后置的++,此时c等于8,a也等于8
	b += a++ + c;//这句话写清楚点就是b=b+a++ +c,此时b=7+8+8=23
	//最后再执行一次a后置++,a的值变为9
	printf("a = %d b = %d c = %d\n:", a, b, c);
	return 0;
}
  • 我这样分析,输出的结果是不是就与我们打印在屏幕上的结果对上啦!看完这个例子,有加深你对前置后置++(- -)的理解吗?

6. ~ 按补码二进制位取反

  • 我们前面就说了,整型在内存中是以二进制补码的形式存储的,你如果对这个概念不太了解,可以看看这篇博客:【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(1)?
  • 而~就是用来对某个整型进行二进制取反的
  • 代码如下:
//~ 按补码二进制位取反

int main()
{
	int a = 0;
	printf("%d\n", ~a);//?
	//00000000000000000000000000000000 -a的补码
	//11111111111111111111111111111111 - ~取反后的补码
	//11111111111111111111111111111110
	//10000000000000000000000000000001 -1//打印时打印的是该数的原码
	return 0;
}

在这里插入图片描述


7.取地址操作符&和解引用操作符*

  • 这俩大多出现的地方在指针中,其实是没啥好讲的,我就不展开了,之后会出有关指针的相关博客的。

8.强制类型转换()

  • 我们在引用某个库函数或者别的什么函数时,可能会出现输入的数据类型与使用该函数定义的数据类型不太符合,这时候我们就需要吧我们输入的数据强制类型转换成所需的数据类型,但是俗话说强扭的瓜不甜,在某些情况下,使用强制类型转换是可能出现bug的。

  • 举例说明:

int main()
{
	int a = (int)3.14;//强制
	printf("%d\n", a);
	
	return 0;
}

在这里插入图片描述

  • 我们把一个浮点数强制类型转换为int型。
  • 但是我们也明显的看出来这段代码的缺陷,它把我们小数点后面的数据给丢了,也就是说在强制类型转换的过程中是很容易造成数据的丢失的!
  • 在函数中的应用
  • 我们在直接三子棋生成随机数中,曾经见过这样一段代码:
srand((unsigned int)time(NULL));//把时间函数置空传给srand同时由于srand要求参数必须为unsigned int型,把time(NULL)强制类型转换一下
  • 感兴趣随机数生成方法的可以去看看这篇博客:
    【C语言】三子棋详解(包教包会的那种)
  • 这就是在实际使用函数时对强制类型转换的应用。

总结

  • 今天的内容暂时讲到这里就结束了,我们今天讲了赋值操作符,单目操作符的具体使用,如果你还有所困惑不妨自己动手实操一下,这方面的知识是稍微有点抽象,需要咱们反复的练习熟悉起来才行。
  • 以上就是关于操作符的第二部分内容,后面其他的操作符应用详解会在近期分批次更新,敬请期待!!
  • 好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

在这里插入图片描述

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

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

相关文章

Docker-compose的使用

目录 Docker-compose 简介 docker-compose的安装 docker-compose.yaml文件说明 compose的常用命令 总结 Docker-compose 简介 Docker-compose 是用于定义和运行多容器的 Docker 应用程序的工具。可以使用YAML文件来配置应用程序的服务。&#xff08;通俗讲是可以通过yml文…

LeetCode108-将有序数组转换为二叉搜索树

题目来源 108. 将有序数组转换为二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵高度平衡 二叉搜索树。 高度平衡二叉树是一棵满足「每个节点的左右两个子树的高度差的…

智慧地下采矿,“像素游戏”智能呈现

在这个像素世界里&#xff0c;我们需要一个智能地下采矿可视化综合管理平台&#xff0c;来帮助我们管理和监控地下采矿全流程。 图扑软件依托自主研发的 HT for Web 产品&#xff0c;结合三维定制化渲染、动态模拟、物理碰撞、5G、物联网、云计算及大数据等先进技术&#xff0c…

从零开始理解Linux中断架构(8)---执行上下文之CPU上下文

1 CPU上下文的来由 CPU上下文是切换任务到CPU时需要保存和恢复的CPU寄存器。ARM64需要保存的寄存器如下图所示 X19-X29作为CPU上下文的依据是什么? 实际上这里使用了一个隐含的事实:Linux所有的任务切换都是在内核中__switch_to函数中进行的,当前任务通过__…

KubeSphere 社区双周报 | OpenFunction 发布 v1.1.1 | 2023.6.9-6.22

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.6.9-6.22。 …

Elisp之定时器run-with-timer、run-with-idle-timer、run-at-time 区别(二十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

libevent(11)libevent中的循环和退出函数

一、libevent基本原理介绍 一个 event_base 对象相当于一个 Reactor 实例&#xff08;不了解Reactor的读者可自行查询相关文章&#xff09;。libevent默认情况下是单线程的&#xff0c;每个线程有且只有一个event_base&#xff0c;对应一个struct event_base结构体以及附于其上…

由于找不到msvcp120.dll无法继续执行代码怎么办?

msvcp120.dll是微软软件包的一部分。它是一个库文件&#xff0c;可用于支持软件运行时&#xff0c;msvcp120.dll的作用是提供计算机程序所需的标准库&#xff0c;msvcp120.dll还负责管理堆内存、线程和异常处理函数等。在使用windows编写的应用程序中&#xff0c;通常需要使用此…

android 如何分析应用的内存(八)——malloc debug

android 如何分析应用的内存&#xff08;八&#xff09; 接上文&#xff0c;介绍六大板块中的第三个————malloc调试和libc回调 上一篇文章中&#xff0c;仅仅是在分配和释放的时候&#xff0c;拦截对应的操作。而不能进一步的去检查内存问题。比如&#xff1a;释放之后再…

深入理解Android Jetpack Compose的Box

Box是一个提供了一种快速、简便的方式来对其子元素进行层叠布局的布局组件。 一、什么是Box? 二、如何使用Box? 三、Box中的contentAlignment属性 四、使用Modifier在Box内进行更复杂的布局 一、什么是Box? 在Compose中&#xff0c;Box是一个简单的布局组件&#xff0c…

如何写出高效、准确的会议记录?

在企业或组织中&#xff0c;会议是一种常见的沟通和决策方式。作为参会人员之一&#xff0c;撰写一份高效、准确的会议记录显得尤为重要。会议记录不仅记录了会议的主题、议题和讨论结果&#xff0c;还能帮助参与者回顾会议过程、梳理思路、明确职责&#xff0c;同时也为后续工…

快速入门JavaScript异步编程:从回调到async/await的跨越

文章目录 I. 介绍异步编程的背景和基本概念本文主要讨论JavaScript中的异步编程 II. 回调函数回调函数的定义、作用以及使用场景回调地狱的问题及解决方案 III. PromisePromise的定义、作用以及使用场景Promise的状态及状态转换Promise的链式调用和错误处理 IV. async/awaitasy…

深度学习之目标检测Fast-RCNN模型算法流程详解说明(超详细理论篇)

1.Fast-RCNN论文背景 2. Fast-RCNN算法流程 3.Fast R-CNN 问题和缺点 这篇以对比RCNN来说明&#xff0c;如果你对RCNN网络没太熟悉&#xff0c;可访问这链接&#xff0c;快速了解&#xff0c;点下面链接 深度学习之目标检测R-CNN模型算法流程详解说明&#xff08;超详细理论篇…

合宙Air724UG Cat.1模块硬件设计指南--原理图设计注意事项

在设计原理时注意以下几点&#xff1a; 严格按照模块硬件手册设计原理图 1.调试接口&#xff1a; 调试务必留出usb&#xff08;烧录脚本&#xff0c;升级用&#xff09; ,1.8v&#xff08;开机标志&#xff09;&#xff0c;uboot&#xff08;强制烧录用&#xff09;测试点&…

软件测试面试,大厂上岸究竟有什么秘诀?

最后&#xff0c;总结一下个人认为比较重要的知识点&#xff1a;接口自动化测试 &#xff1a;测试框架&#xff0c;多个有关联的接口的用例编写&#xff0c;用例的组织及存储&#xff0c;接口测试的覆盖率&#xff0c;RESTAssured 的封装等。UI 自动化测试 &#xff1a;iOS 和 …

Web自动化测试之滑动验证码的解决方案

目录 滑动验证破解思路 案例讲解 实现代码 运行效果&#xff1a; 根据传入滑块&#xff0c;和背景的节点&#xff0c;计算滑块的距离 滑动滑块进行验证 总结&#xff1a; 在Web自动化测试的过程中&#xff0c;经常会被登录的验证码给卡住&#xff0c;不知道如何去通过验证…

Prompt不等于编程,“提示词工程师”淘汰程序员也是伪命题

Original 李建忠 李建忠研思 最近ChatGPT及基于大语言模型&#xff08;Large Language Model&#xff0c;以下简写为LLM&#xff09;的Github Copilot等工具出来之后&#xff0c;在软件开发领域也带来了非常大的震撼。著名的观点有Fixie创始人、前Google工程总监Matt Welsh在AC…

解决onblur()失去焦点事件在刚登陆页面(尚未有任何操作)时就触发的问题

文章目录 一、原始错误&#xff1a;1.1 原始代码1.2 访问页面&#xff08;仅访问页面&#xff0c;不进行任何操作&#xff09; 二、解决错误2.1 解决办法2.2 再次访问页面2.2.1 输入错误格式2.2.2 输入正确格式 最近笔者在编写代码时遇到刚访问页面&#xff0c;什么都没有操作&…

JavaWeb学习笔记-1

学习路线 Web开发–介绍&#xff08;画大饼&#xff09; 什么是Web&#xff1f; Web&#xff1a;全球广域网&#xff0c;也成为万维网&#xff0c;能通过浏览器访问的网站 Web网站的工作流程 网站大致是由三个部分组成的 第一部分就是我们能看到的网页程序&#xff0c;也叫做…

React 组件中怎么做事件代理

React 并不会把所有的处理函数直接绑定在真实的dom节点上&#xff0c;而是把所有的事件绑定到结构的最外层&#xff08;合成事件层&#xff09;&#xff0c;使用一个统一的事件监听器&#xff0c;这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。 当组…