深度剖析C语言符号篇

news2024/11/13 15:11:08

致前行的人:    

        人生像攀登一座山,而找寻出路,却是一种学习的过程,我们应当在这过程中,学习稳定冷静,学习如何从慌乱中找到生机。

目录

1.注释符号:

2.续接符和转义符:

3.回车与换行:

4.单引号和双引号:

5.计算机为何存在字符:

6.逻辑运算符:

7.位运算符:

8.如何理解整型提升

9.左移和右移 

10++、--操作

10.1深刻理解 a++

10.2++,--使用时会存在的问题

11.符号

1.注释符号:

注:注释在预处理的时候本质上是被替换成空格 

C分格的注释不支持嵌套:

 /*总是离它最近的*/匹配

注释与指针:

 当/*在一起的时候编译器会默认为注释符号,为了避免应该加上():

2.续接符和转义符:

1.续行功能:

\:这里\充当续行的功能

注意:\的后面不能出现任何任何字符包括空格

 2.转义功能:

1.字面转特殊:

2.特殊转字面:

 

3.回车与换行:

回车:是将光标从当前的位置移动到开始位置   \n

换行:是移动到下一行                                       \r

验证:倒计时

4.单引号和双引号:

单引号是字符,双引号是字符串:

5.计算机为何存在字符:

为何会存在ASCCII表?
1.数据在内存中存储是以二进制的形式存储的,而为了让用户在显示器上清楚易懂的读取,则创造了不同的二进制对应不同的字符。

2.每一种字符又是英语是因为计算机最早是美国人发明的,而他们的语言又是英语,为了简单则用不同的英文字母来对应二进制数据

6.逻辑运算符:

&&:并且 两个条件为真则为真

||:或       有一个条件为真则为真

 短路:

&&:当前面的条件为假时后面的表达式不进行

||:   当前面的条件为真时后面的表达式不执行

7.位运算符:

&:按位与 相同则为1,相异则为0

|:按位或  有一个为1则为1

^:按位异或 相异则为1,相同则为0

~:按位取反 

^的理解:

^:逐比特位,相同则为0,相异为1

任何数和0异或,都是它本身 

支持结合律和交换律 

 交换两个整数:

方法1:创建临时变量

void swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
int main()
{
	printf("before:a = %d,b = %d\n", a, b);
	int a = 10;
	int b = 20;
	swap(&a, &b);
	printf("after:a = %d,b = %d\n", a, b);
	return 0;
}

方法2: 不创建临时变量

int main()
{
	int a = 10;
	int b = 20;
	printf("before:a = %d,b = %d\n", a, b);
	a = a + b;
	b = a - b;
	a = a - b;
	printf("after:a = %d,b = %d\n", a, b);
	return 0;
}

存在的问题:当a和b是两个非常大的数时,由于相加就可能会存在整型溢出的问题

方法3:用异或解决整型溢出的问题

int main()
{
	int a = 10;
	int b = 20;
	printf("before:a = %d,b = %d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("after:a = %d,b = %d\n", a, b);
	return 0;
}

 图例解释:

将指定bit位置为1 :

将指定bit位置为0:

#define SETBIT(x,n) (x |= (1 << (n - 1))) //将指定bit位置为1
#define CLRBIT(x,n) (x &= (~(1 << (n-1)))) //将指定bit位置为0
void show_bits(int x)
{
	int num = sizeof(x) * 8 - 1;
	while (num >= 0)
	{
		if (x & (1 << num))
			printf("1 ");
		else
			printf("0 ");
		num--;
	}
}
int main()
{
	int x = 10;
	SETBIT(x, 5);
	CLRBIT(x, 5);
	show_bits(x);
	return 0;
}

8.如何理解整型提升

无论任何位运算符,目标都是要计算机进行计算的,而计算机中只有CPU具有运算能力(先这样简单理解),但计算的数据,都在内存中。故,计算之前(无论任何运算),都必须将数据从内存拿到CPU中,拿到CPU哪里呢?毫无疑问,在CPU 寄存器中。
而寄存器本身,随着计算机位数的不同,寄存器的位数也不同。一般,在32位下,寄存器的位数是32位。可是,你的char类型数据,只有8比特位。读到寄存器中,只能填补低8位,那么高24位呢?就需要进行“整形提升”。

#include<stdio.h>
int main()
{
	char c = 0;
	printf("sizeof(c): %d\n", sizeof(c)); 
	printf("sizeof(c): %d\n", sizeof(~c)); 
	printf("sizeof(c): %d\n", sizeof(c << 1)); 
	printf("sizeof(c): %d\n", sizeof(c >> 1));
	return 0;
}

9.左移和右移 

<<(左移): 最高位丢弃,最低位补零
>>(右移):
1. 无符号数:最低位丢弃,最高位补零[逻辑右移]
2. 有符号数:最低位丢弃,最高位补符号位[算术右移]

int main()
{
	//左移
	unsigned int a = 1;
	printf("%u\n", a << 1);
	printf("%u\n", a << 2);
	printf("%u\n", a << 3);
	return 0;
}

int main()
{
	// 逻辑右移
	unsigned int b = 100;
	printf("%u\n", b >> 1);
	printf("%u\n", b >> 2);
	printf("%u\n", b >> 3);
	return 0;
}

 

int main()
{
	// 算术右移,最高位补符号位1,虽然移出了最低位1,但是补得还是1
	int c = -1;
	printf("%d\n", c >> 1);
	printf("%d\n", c >> 2);
	printf("%d\n", c >> 3);
	return 0;
}

 

int main()
{
	unsigned int d = -1;
	printf("%d\n", d >> 1);
	printf("%d\n", d >> 2);
	printf("%d\n", d >> 3);
	return 0;
}

 

结论:
左移,无脑补0
右移,先判定是算术右移还是逻辑右移,判定依据:看自身类型,和变量的内容无关。

10++、--操作

int main()
{
	int a = 10;
	int b = ++a; //前置++, 先自增在使用
	printf("%d, %d\n", a, b); //11,11
	int c = 10;
	int d = c++; //后置++,先使用在自增
	printf("%d, %d\n", c, d); //11,10
	//--同上
	return 0;
}

10.1深刻理解 a++

int main()
{
	int a = 10;
	int b = a++;

	int c = 20;
	c++;
	return 0;
}

结论:a++完整的含义是先使用,在自增。如果没有变量接收,那么直接自增

10.2++,--使用时会存在的问题

int main()
{
	int i = 1;
	int j = (++i) + (++i) + (++i);
	printf("%d\n", j);
	return 0;
}

上面代码,分别在不同的编译器下试试,可能会得到不同结果

在Linux下测试结果为10,在VS上测试结果为12

本质:是因为上面表达式的"计算路径不唯一"(为什么?编译器识别表达式,是同时加载至寄存器,还是分批加载,完全不确定)导致的,类似这种复杂表达式,不推荐使用。

表达式匹配:贪心算法

编译器在处理复杂表达式的时候,会尽可能将多个运算符组成表达式进行运算

int main()
{
	int a = 10;
	int b = 20;
	//printf("%d\n", a++++ + b);//自动匹配失败 err
	printf("%d\n", a++ + ++b); //自行分离匹配,非常不推荐,不过能看出空格的好处 31
	return 0;
}

11.符号

深度理解取余/取模运算

step 1:向0取整

int main()
{
	int i = -2.9;
	int j = 2.9;
	printf("%d\n", i); //结果是:-2
	printf("%d\n", j); //结果是:2
	return 0;
}

 如图所示:

在库中有一个trunc取整函数,同作用:

#include<math.h>
int main()
{
	printf("%d\n",(int)trunc(-2.9));
	printf("%d\n", (int)trunc(2.9));
	return 0;
}

step 2:向-∞取整

如图所示:

int main()
{
	//本质是向-∞取整,注意输出格式要不然看不到结果
	printf("%.1f\n", floor(-2.9));
	printf("%.1f\n", floor(-2.1));
	printf("%.1f\n", floor(2.9));
	printf("%.1f\n", floor(2.1));
	return 0;
}

 step3:向+∞取整

如图所示:

int main()
{
	//本质是向+∞取整,注意输出格式要不然看不到结果
	printf("%.1f\n", ceil(-2.9));
	printf("%.1f\n", ceil(-2.1));
	printf("%.1f\n", ceil(2.9));
	printf("%.1f\n", ceil(2.1));
	return 0;
}

 

step4:四舍五入 

int main()
{
	//本质是四舍五入
	printf("%.1f\n", round(2.1));
	printf("%.1f\n", round(2.9));
	printf("%.1f\n", round(-2.1));
	printf("%.1f\n", round(-2.9));
	return 0;
}

 取模概念:

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 且0 ≤ r < d。其中,q被称为商,r 被称为余数。

int main()
{
	int a = 10;
	int d = 3;
	printf("%d\n", a % d); //结果是1
	//因为:a=10,d=3,q=3,r=1   0<= r <d(3)
	//所以:a = q*d+r -> 10=3*3+1
	return 0;
}

如果是下面的代码呢?

int main()
{
	int a = -10;
	int d = 3;
	printf("%d\n", a % d); //结果是-1
	return 0;
}

python环境:

 结论:很显然,上面关于取模的定义,并不能满足语言上的取模运算

因为在C中,现在-10%3出现了负数,根据定义:满足 a = q*d + r 且0 ≤ r < d,C语言中的余数,是不满足定义的,因为,r<0了。

故,大家对取模有了一个修订版的定义:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且
0 ≤ |r|< |d|。其中,q 被称为商,r 被称为余数。

有了这个新的定义,那么C中或者Python中的“取模”,就都能解释了。
解释C: -10 = (-3) * 3 + (-1)
解释Python:-10 = (?)* 3 + 2,其中,可以推到出来,'?'必须是-4(后面验证).即-10 = (-4)* 3 + 2,才能满足定义。

所以,在不同语言,同一个计算表达式,负数“取模”结果是不同的。我们可以称之为分别叫做正余数 和 负余数

由上面的例子可以看出,具体余数r的大小,本质是取决于商q的。而商,又取决谁呢?取决于除法计算的时候,取整规则。

本质 1 取整:
取余:尽可能让商,进行向0取整。
取模:尽可能让商,向-∞方向取整。

故:
C中%,本质其实是取余。
Python中%,本质其实是取模。

理解链:
对任何一个大于0的数,对其进行0向取整和-∞取整,取整方向是一致的。故取模等价于取余
对任何一个小于0的数,对其进行0向取整和-∞取整,取整方向是相反的。故取模不等价于取余

同符号数据相除,得到的商,一定是正数(正数vs正整数),即大于0!故,在对其商进行取整的时候,取模等价于取余。

计算数据同符号:

C:

int main()
{
	printf("%d\n", 10 / 3);
	printf("%d\n\n", 10 % 3);
	printf("%d\n", -10 / -3);
	printf("%d\n\n", -10 % -3);
	return 0;
}

 python:

print(10 // 3)
print(10 % 3)
print(-10 // -3)
print(-10 % -3)

注:python中 / 默认是浮点数除法,//才是整数除法,并进行-∞取整 

通过对比试验,更加验证了,参与取余的两个数据,如果同符号,取模等价于取余

如果参与运算的数据,不同符号呢?

C:

int main()
{
	printf("%d\n", -10 / 3); //结果:-3
	printf("%d\n\n", -10 % 3); //结果:-1 -> -10=(-3)*3+(-1)
	printf("%d\n", 10 / -3);//结果:-3
	printf("%d\n\n", 10 % -3);//结果:1 -> 10=(-3)*(-3)+1
	return 0;
}

python:

print(-10 // 3)
print(-10 % 3)
print(10 // -3)
print(10 % -3)

重新看看定义:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|< |d|。其中,q 被称为商,r 被称为余数。

a = q*d + r 变换成 r = a - q*d 变换成 r = a + (-q*d) ,对于:x = y + z,这样的表达式,x的符号 与 |y|、|z|中大的数据一致

而r = a + (-q*d)中,|a| 和 |-q*d|的绝对值谁大,取决于商q的取整方式。
c是向0取整的,也就是q本身的绝对值是减小的。
如:
-10/3=-3.333.33 向0取整 -3.  a=-10 |10|, -q*d=-(-3)*3=9 |9|
10/-3=-3.333.33 向0取整 -3.  a=10 |10|, -q*d=-(-3)*(-3)=-9 |9|
绝对值都变小了
python是向-∞取整的,也就是q本身的绝对值是增大的。
-10/3=-3.333.33  '//'向-∞取整 -4.  a=-10 |10|, -q*d=-(-4)*3=12 |12|
10/-3=--3.333.33 '//'向-∞取整 -4.  a=10 |10|, -q*d=-(-4)*(-3)=-12 |12|
绝对值都变大了

结论:如果参与取余的两个数据符号不同,在C语言中(或者其他采用向0取整的语言如:C++,Java),余数符号,与被除数相同。

总结:

浮点数(或者整数相除),是有很多的取整方式的。
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|< |d|。其中,q 被称为商,r 被称为余数。
在不同语言,同一个计算表达式,“取模”结果是不同的。我们可以称之为分别叫做正余数和负余数
具体余数r的大小,本质是取决于商q的。而商,又取决于除法计算的时候,取整规则。
取余vs取模: 取余尽可能让商,进行向0取整。取模尽可能让商,向-∞方向取整。
参与取余的两个数据,如果同符号,取模等价于取余
如果参与取余的两个数据符号不同,在C语言中(或者其他采用向0取整的语言如:C++,Java),余数符号,与被除数相同。(因为采用的向0取整)

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

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

相关文章

独立产品灵感周刊 DecoHack #050 - 基于 ChatGPT 的 API 能做什么产品

ChatGPT 的 API 3.5 开放过去了一周&#xff0c;果然和预想的一样&#xff0c;接入 API 的产品爆炸式地出现了非常多&#xff0c;很多产品已经做的非常好用了&#xff0c;在很多场景方便了太多。本期整理了一些做的很不错的产品。 本周刊记录有趣好玩的独立产品设计开发相关内容…

一款好的风险管理软件可以做什么

风险管理软件哪个好&#xff1f;使用Zoho Projects易于使用的项目风险管理软件&#xff0c;最大限度地减少收入损失并快速调整您的投资组合&#xff0c;保护您的项目投资。Zoho Projects的高级风险管理软件可在您最需要的时候安全的保护您的业务。使用Zoho Projects强大的风险管…

【springmvc】视图

SpringMVC的视图 SpringMVC中的视图是View接口&#xff0c;视图的作用渲染数据&#xff0c;将模型Model中的数据展示给用户 SpringMVC视图的种类很多&#xff0c;默认有转发视图和重定向视图 当工程引入jstl的依赖&#xff0c;转发视图会自动转换为JstlView 若使用的视图技…

内核性能评估测试及具体修改操作步骤记录

步骤记录前言一、查看环境配置二、LRU缓存空间调整三、进程扫描时间间隔四、与其他内核对比的工作负载测试&#xff08;另一个内核的编译&#xff09;总结前言 记录的相关操作有&#xff1a;查看服务器硬件环境、LRU缓存大小修改、内核命名、内核编译以及进程执行周期的设置。…

操作系统——17.进程同步与进程互斥

这篇文章我们来讲一下进程同步与进程互斥的问题 目录 1.概述 2.什么是进程同步 3.什么是进程互斥 4.小结 1.概述 首先&#xff0c;我们来看一下本篇内容的大体框架&#xff1a; 2.什么是进程同步 知识点回顾:进程具有异步性的特征。 异步性是指&#xff0c;各并发执行的…

vue里使用driver.js实现项目功能向导指引

介绍 https://github.com/kamranahmedse/driver.js driver.js 是一个轻量级、无依赖的原生JavaScript引擎&#xff0c;在整个页面中驱动用户的注意力&#xff0c;强大的、高度可定制的原生JavaScript引擎&#xff0c;无外部依赖&#xff0c;支持所有主流浏览器。 安装 npm …

CHAPTER 1 Linux Filesystem Management

Linux Filesystem Management1 文件系统是什么2 文件系统的组成3 inode详解1. inode到底是什么2. inode的内容3. inode的大小4. inode的号码5. 硬链接6. 软链接4 存储区域5 常见文件系统的类型1. 根文件系统2. 虚拟文件系统3. 真文件系统4. 伪文件系统5. 网络文件系统1 文件系统…

2023年网络安全最应该看的书籍,弯道超车,拒绝看烂书

学习的方法有很多种&#xff0c;看书就是一种不错的方法&#xff0c;但为什么总有人说&#xff1a;“看书是学不会技术的”。 其实就是书籍没选对&#xff0c;看的书不好&#xff0c;你学不下去是很正常的。 一本好书其实不亚于一套好的视频教程&#xff0c;尤其是经典的好书…

Java 面试常见项目问题回答

之前整理了好几期&#xff0c;我面试时遇到的面试候选人&#xff0c;我是如何我去筛选的&#xff0c;这一期&#xff0c;我们来看下一些 面试常问的业务性的问题 你们公司权限认证是如何实现的? 这其实是个通用性的问题&#xff0c;大部分公司 小型公司&#xff0c;或者中型公…

Praat之基频分析

Praat之基频分析 测量基频F0的方法 自相关 Autocorrelation&#xff08;易出现pitch-halving\pitch-double&#xff09;窄带谱图 Narrowband spectrogram&#xff08;第一谐波就是基频&#xff09;倒谱分析 Cepstral analysis测量声门波 glottal pluse&#xff08;通过波形&a…

拥抱数字时代 | 第十六届中国大数据技术大会成功举办

2月26日&#xff0c;由中国计算机学会&#xff08;CCF&#xff09;主办&#xff0c;苏州市吴江区人民政府支持&#xff0c;CCF大数据专家委员会、苏州市吴江区工信局、吴江区东太湖度假区管理办公室、苏州市吴江区科技局、苏州大学未来科学与工程学院、DataFountain数联众创承办…

史上最全最详细的Java架构师成长路径图,程序员必备

从新手码农到高级架构师&#xff0c;要经过几步&#xff1f;要多努力&#xff0c;才能成为为人倚重的技术专家&#xff1f;本文将为你带来一张程序员发展路径图&#xff0c;但你需要知道的是&#xff0c;天下没有普适的道理&#xff0c;具体问题还需具体分析&#xff0c;实践才…

JavaScript基础三、数据类型

零、文章目录 文章地址 个人博客-CSDN地址&#xff1a;https://blog.csdn.net/liyou123456789个人博客-GiteePages&#xff1a;https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee&#xff1a;https://gitee.com/bluecusliyou/TechLearnGithub&#xff1a;https:…

nest.js学习笔记(一)

nest.js学习笔记&#xff08;一&#xff09;一、安装nest.js前置条件运行项目目录介绍二、nest.js cli 常用命令三、RESTful 风格设计1.接口url2.RESTful 版本控制四、获取前端传过来的参数1.获取Get请求参数2.获取Post请求参数3.动态路由4.获取Header信息5.自定义状态码nest.j…

Kotlin lateinit 和 lazy 之间的区别 (翻译)

Kotlin 中的属性是使用var或val关键字声明的。Late init 和 lazy 都是用来初始化以后要用到的属性。 由于这两个关键字都用于声明稍后将要使用的属性&#xff0c;因此让我们看一下它们以及它们的区别。 Late Init 在下面的示例中&#xff0c;我们有一个变量 myClass&#xff0…

【前缀和】截断数组、K倍区间、激光炸弹

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

小目标识别——基于K近邻的白酒杂质检测算法实现

文章目录实现思路配置opencv位置剪裁实现代码自适应中值滤波实现代码动态范围增强实现代码形态学处理实现代码图片预处理效果计算帧差连续帧帧差法原理和实现代码实现代码K近邻实现基本介绍实现过程参考实现思路 使用C进行实现&#xff0c;开发平台是clion&#xff0c;并没有使…

zencart/opencart/wordpress外贸独立站最少需要多少钱

以程序员的职位进入跨境电商行业已经有10年了&#xff0c;接触过不少大大小小的老板客户&#xff0c;我遇到最多的问题就是搭建一个站要多少钱&#xff1f;实话说这问题问的有些粗糙。如果我遇到不负责的公司他可能会直接报价1W&#xff0c;2W或更多&#xff0c;也有可能遇到兼…

【STM32MP157应用编程】3.控制PWM

目录 PWM文件 指令操作PWM 程序操作PWM 程序说明 程序代码 3_PWM_1.c 启动交叉编译工具 编译 拷贝到开发板 测试 PWM文件 在/sys/class/pwm目录下&#xff0c;存放了PWM的文件。 pwmchip0和pwmchip4目录对应了MP157 SoC的2个PWM控制器&#xff0c;pwmchip0对应的是M…

【Python】torch.norm()用法解析

【Python】torch.norm()用法解析 文章目录【Python】torch.norm()用法解析1. 介绍1.1 p-范数1.2 Frobenius 范数1.3 核范数2. API3. 示例1. 介绍 torch.norm()是对输入的tensor求对应的范数。tensor的范数有以下三种&#xff1a; 1.1 p-范数 1.2 Frobenius 范数 即&#xff…