【深度解刨C语言】符号篇(全)

文章目录

  • 一.注释
  • 二.续行符与转义符
    • 1.续行符
    • 2.转义符
  • 三.回车与换行
  • 四.逻辑操作符
  • 五.位操作符和移位操作符
  • 六.前置++与后置++
  • 七.字符与字符串
  • 八./和%
    • 1.四种取整方式
    • 2.取模与取余的区别和联系
    • 3./两边异号的情况
      • 1.左正右负
      • 2.左负右正
  • 九.运算符的优先级

一.注释

注释的两种符号:

  1. // +内容
  2. /*+内容 */
  3. 说明:/*只会与最近的 */进行匹配。
int main()
{
	//这是一段注释
	/*这是一段注释*/
	return 0;
}

说明:注释在预处理阶段(准确的来说是预编译)就被删除了,而与之代替的是空格,所以注释的本质上其实是空格。注释的意义在于提高代码的可读性
4. 补充:
1.空格:C语言中空格是用来当做符号识别的分割符
2:预处理器识别符号的基本方式是贪心法,所谓贪心指的是,编译器会尽可能的识别多的字符,(也就是说编译器将程序分解成符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么就再读一个字符,判断已经读入的两个字符组成的字符串是否可能是一个字符的组成部分;如果可能,继续读入下一个字符,判断已经读入的两个字符是否可能是一个符号的组成部分;如果可能继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已经不再可能组成一个有意义的字符)——<<C陷阱与缺陷>>,这样做是为了满足大多数的情况,而少数的情况需要我们自己对符号进行分割,那具体如何分割,当然用空格了。

例1:

#include<stdio.h>
int main()
{	
	int a = 1;
	int* p = &a;
	int b = a/ *p;//注意:这里的/*之间需加一个空格,否则会被编译器判断为注释符号
	return 0;
}

例2:

int main()
{
	int a = 1;
	int b = 2;
	int c = a-- - b;//是a后置减减再减去b
	printf("%d\n", c);//答案是-1
	a = 1;
	b = 2;
	c = a - --b;//是b前置--,然后a再减去b
	printf("%d\n", c);//答案:0
	return 0;
}

说明:像这类准二义性的问题,有时候会给我们带来麻烦。

不好的注释方式:
例1:

#if 0
int main()
{
	printf("hello world\n");
	return 0;
}
#endif

例2:

int main()
{
	if (0)
	{
		printf("hello world\n");
	}
	return 0;
}

说明:这样注释的方式并不明显,所以阅读代码时,并不确定这段代码是否是一段注释,所以不建议这样进行注释。

二.续行符与转义符

1.续行符

逻辑表达式:

#include<stdio.h>
int main()
{
	int a = 1;
	int b = 1;
	int c = 0;
	int d = 1; 
	if (a == 1 &&\
		b == 1 &&\
		c == 0 &&\
		d == 1)
	{
		printf("hello world\n");
	}
	return 0;
}

说明:不带续行符也是可以的,但这就好像不写函数参数默认为int一样,所以严格一点,还是建议带上续行符号
注意:续行符后不能带空格

字符串:

int main()
{
	char* p = "abcd\
efg";//这是为了处理比较长的字符串而准备的,我们这里就暂且用一下。
	printf("%s\n", p);//字符串的续行符是不会被打印出来的
	return 0;
}

2.转义符

在这里插入图片描述

说明:\在这里是改变原字符的意思,具体有以上14种。
注意:单个\出现是不能被打印,要想打印需把\转义也就是\\。

例1:

#include <stdio.h>
int main()
{
	 printf("c:\code\test.c\n");
	 int len = strlen("c:\code\test.c\n");//这里的\是打不出来的
	 printf("%d",len);//len是13
    return 0;
}

解释:

1——c,
2——:
3——\c(注意在vs 2019中 \加上字符被编译器认为是一个转义字符),
4——0,
5——d;
6——e,
7——\t,
8——e,
9——s,
10——t,
11—— .
12——c,
13——\n,

例2:

#include<stdio.h>
#include<string.h>
int main()
{
	printf("%d\n",strlen("c:\\code\\test.c\\n"));
	//这样能打印出\了,但是字符的个数比前面多了3个——总共16个字符
	printf("c:\\code\\test.c\\n");
	return 0;
}

效果:
在这里插入图片描述
例3:

#include<stdio.h>
int main()
{
	printf("\"");//这里\是改变"的意思,而能被打印出来
	return 0;
}

说明:"会自动与最近的”进行匹配

三.回车与换行

1.回车

符号:\r
说明:指的是回到当前行的首元素

2.换行

符号:\n
说明:准确的是回到当前行的下一行的相同位置
注意:一般编译器实现的换行是:回车+换行(上面提及的换行)

一个有意思的旋转光标的实现:

#include<stdio.h>
#include<Windows.h>
int main()
{
	while (1)
	{
		printf("\\\r");
		Sleep(100);
		
		printf("|\r");
		Sleep(100);

		printf("-\r");
		Sleep(100);

		printf("/\r");
		Sleep(100);
	}
	return 0;
}

四.逻辑操作符

逻辑与:&&
说明:一假即为假,全真才为真(串联)
逻辑或: ||
说明: 一真即为真,全假才为假(并联)
运算顺序:从左向右

#include<stdio.h>
int my_print()
{
	printf("hello\n");
	return 1;
}
int main()
{
	int judge = 0;
	scanf("%d", &judge);
	judge && my_print();
	//输入0时,不执行my_print
	//输入1时,执行my_print
	//judge || my_print();
	//输入1时,不执行
	//输入0时,执行
	return 0;
}

五.位操作符和移位操作符

位运算符是对内存的数直接进行运算的(补码)
按位与:&
说明:同1才为1,其余都为0
按位或:|
说明:同0才为0,其余为1
按位异或:^
说明:相同为0,相异为1
按位取反: ~
说明:1变0,0变1,包括符号位。

简单运用:

int main()
{
	printf("%d\n", 1 & 2);//0
	//  01(二进制)
	//& 10
	//  00
	//答案是:0
	printf("%d\n", 1 | 2);//3
	//  01
	//& 10
	//  11
	//答案:3
	printf("%d\n", 1 ^ 2);//3
	//  01
	//^ 10
	//  11
	//答案:3
	printf("%d\n", ~-1);//0
	//  11111111 11111111 11111111 11111111
	//~
	//  00000000 00000000 00000000 00000000
	//答案:0
	return 0;
}

移位操作符
1.移位操作符运算后不会影响操作数本身
2.移位操作符运算的范围为整数

  1. 左移操作符
    符号:<<(双箭头向左)
    功能:将补码整体左移n位舍去,右边补0。
int a =1;
int b = a<<1;//这是将a的补码向左移动一位,

a的补码:00000000000000000000000000000001
b的补码:00000000000000000000000000000010
在这里插入图片描述
2. 右移操作符
符号:>>(双箭头向右)

1.算数右移
功能:将补码整体向右移n位,最左边补符号位
例子:

int a =-1;
int b = a>>1:

在这里插入图片描述
a的补码:11111111111111111111111111111111
b的补码:11111111111111111111111111111111
1.逻辑右移
功能:将补码整体向右移n位,最左边补0
在这里插入图片描述

一般右移都是算数右移(补符号位

关于sizeof的整形提升问题:

#include<stdio.h>
int main()
{

	char a = 0;
	printf("%d\n", sizeof(~a));//4
	printf("%d\n", sizeof(!a));//1
	printf("%d\n", sizeof(a&a));//4
	printf("%d\n", sizeof(a|a));//4
	printf("%d\n", sizeof(a^a));//4
	printf("%d\n", sizeof(a >>1));
	printf("%d\n", sizeof(a <<1));
	return 0;
}

说明:位运算符合移位操作符,都是在整形的大小进行计算的。
注意:!a在VS下是1,在Linux下是4,这里我们推荐当做4进行理解。

经典运用:
1.用异或和按位与实现加法

说明:CPU也是通过异或和按位与进行加法运算的。

#include<stdio.h>
int main()
{
	int begin = 0;
	int process = 0;
	int end = 0;
	scanf("%d%d", &begin, &end);
	process = end;
	while (process)//当没有进位信息,就停止循环
	{
		//先进行异或不保留进位信息
		end = begin ^ process;
		//获取进位信息,左移之后是进位
		process = (begin & process) << 1;
		//更新下一轮的加数信息
		begin = end;
	}
	printf("%d\n", end);
	return 0;
}

2.用异或实现两个数交换

#include<stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	printf("a==%d,b==%d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	// b =a^(b^b)=a^0=a
	a = a ^ b;
	//a = b^(a^a)=b^0=b
	printf("a==%d,b==%d\n", a, b);
	return 0;
}

说明:
1.异或支持交换律和结合律
2.0与任何数异或等于本身
3.两个相同的数异或为0

3.用按位与将二进制序列输出

void ShowBites(int x)
{
	for (int i = 31; i >= 0; i--)
	{
		if (((x>>i) & 1)== 1)
		{
			printf("1");
		}
		else
		{
			printf("0");
		}
	}
}

4.用异或将指定的数变为1

#include<stdio.h>
#define SPECIALBIT(x,y) ((x)|=(1<<(y-1))) 
int main()
{
	int a = 0;
	SPECIALBIT(a, 5);
	ShowBites(a);
	return 0;
}

5.用按位与将指定位置变为0

#include<stdio.h>
#define SPECIALBITS(x,y) ((x)^=(1<<(y-1)))
int main()
{
	int a = 0xFFFFFFFF;
	SPECIALBITS(a, 5);
	ShowBites(a);
	return 0;
}

六.前置++与后置++

我们一般说前置++是先自增一,再使用,后置++是先使用,然后再加1,真的是这样吗?
答案:应该说大多数情况下是这样的,这样只是为了方便我们记忆,这种情况并不是绝对的。
满足情况的例子:

int main()
{
	int a = 0;
	int b = 1;
	b = a++;
	return 0;
}

b=a++的反汇编代码

在这里插入图片描述

int main()
{
	int a = 0;
	int b = 1;
	b = ++a;
	return 0;
}

在这里插入图片描述
不满足情况的例子:

int main()
{
	int a = 0;
	++a;
	a++;
	return 0;
}

在这里插入图片描述
一个典型的问题表达式:

所谓的问题表达式,并不是说表达式的语法有问题,而是说表达式的计算路径具有二义性,也就是有多种计算路径。

#include<stdio.h>
int main()
{
	int a = 1;
	a = (++a) + (++a) + (++a);
	printf("%d\n", a);
	return 0;
}

说明:这里是++与+的计算顺序与优先级的问题
有两种可能:
1.先计算全部的++,也就是把a的值先自增三次,再把自增过后的a相加,答案为12,这是VS下运行的结果
2.先计算前两个++,也就是先把a自增两次,再把自增过后的前两个a相加,最后再对a自增一,再把前两次相加的结果再相加此时a自增的结果,也就是3+3+4=10
这是Linux下的运行结果。

七.字符与字符串

1.字符串
说明:C语言并没有字符串类型,但是有字符类型

字符串在C语言中主要以两种形式存在:
1.数组
2.字符指针
但是字符串应用的场景很多。

int main()
{
	char* p ="abcdef";//p是字符串首字符的地址
	//说明:这里的字符串是不能进行修改的。
	char arr[]="abcdef";//字符串被放在数组中,字符串里面的字符是能修改的
	char c = "0123456"[1];//这是字符指针的形式。
	printf("%d\n",sizeof("abcdef");//这是以数组形式存在的,其大小是
	//字符串的字符个数
	printf("%d\n", sizeof(""));//里面有一个字符\0,所以是1
	return 0;
}

2.字符
说明:字符常量是以整形存在的,字符常量被放在字符变量中是要发生截断的。
注意:
1.一个字符里面最多包含4个字符(‘abcd’),对应4个字节
2.一个字符里面不能为空

int main()
{
	printf("%d\n", sizeof('c'));//这是4个字节
	char c = 'c';
	printf("%d\n", sizeof(c));//这是1个字节
	printf("%d\n",sizeof(+c));//整形提升,4个字节
	//CPU运算是以整形大小的
	return 0;
}

为什么存在ASCII码表?

因为代码是外国人发明的,外国的字符由26个英文字符组成,这也就照应了ASCII码表里面,为啥有26个大小写字符,那与计算机怎么交互信息呢?自然是由ASCII码表翻译出的字符啦!

八./和%

1.四种取整方式

1.向0取整
在这里插入图片描述

函数:trunc()
参数:double
返回值:double

#include<stdio.h>
#include<math.h>
int main()
{
	printf("%f\n", trunc(5.4));//5.0
	return 0;
}

2.向负无穷取整
在这里插入图片描述

#include<stdio.h>
#include<math.h>
int main()
{
	printf("%f\n", floor(5.4));//5.0
	return 0;
}

3.向正无穷取整
在这里插入图片描述

函数:ceil()
参数:double
返回值:double

#include<math.h>
int main()
{
	printf("%f\n", ceil(5.4));//6.0
	return 0;
}

4.四舍五入取整

函数:round()
参数:double
返回值:double

#include<math.h>
int main()
{
	printf("%f\n", round(5.4));//5.0
	return 0;
}

2.取模与取余的区别和联系

数学中余数的定义为:

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

计算机中余数的定义

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = qd + r其中,q被称为商,r 被称为余数。
注意:这里的余数是可以小于0的,商的结果是向0取整
比如:5/-2=-2.5,向0取整为-2,这里的 /准确的来说是取余
余数的求法:r=a-q
d=5-(-2)*(-2)=5-4=1,也就是用公式求。

C语言的 / 就是取余

计算机中取模的定义

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = qd + r其中,q被称为商,r 被称为余数。
说明:a/d=q余r,这里的/准确的来说是取模
注意:这里的余数是可以小于0的,商的结果是向负无穷取整
比如:5/-2=-2.5,向负无穷取整为-3
余数的求法:用公式求,r=a-q
d=5-(-3)*(-2)=5-6=-1.

Python的 / 就是取模

3./两边异号的情况

1.左正右负

这里的r=a-qd,a是被除数,q是商,d是除数,
也就是a>0,d<0,q<0,q * d > 0,所以可以这样写r=|a|-|q*d|,
1.当为取模时,商实际上会比较小(负数),绝对值比较大,所以|q*d|>|a|,因此r是小于0的
2.当为取余时,商实际上会比较大(负数),绝对值比较小,所以|q
d|<|a|,r是大于0的。

2.左负右正

这里的r=a-qd,a是被除数,q是商,d是除数,
也就是a<0,d>0,q<0,q*d<0,所以可以这样写r=|q*d|-|a|
1.当为取模时,商实际上会比较小(负数),绝对值比较大,所以|q*d|>|a|,因此r是大于0的
2.当为取余时,商实际上会比较大(负数),绝对值比较小,所以|q
d|<|a|,r是小于0的。

九.运算符的优先级

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sentinel

SentinelSentinel介绍什么是Sentinel?为什么需要流量控制&#xff1f;为什么需要熔断降级&#xff1f;一些普遍的使用场景本文介绍参考&#xff1a;Sentinel官网《Spring Cloud Alibaba 从入门到实战.pdf》Sentinel下载/安装项目演示构建项目控制台概览演示之前需先明确&#…

【webrtc】ICE 到VCMPacket的视频内存分配

ice的数据会在DataPacket 构造是进行内存分配和拷贝而后DataPacket 会传递给rtc模块处理rtc模块使用DataPacket 构造rtp包最终会给到OnReceivedPayloadData 进行rtp组帧。吊炸天的是DataPacket 竟然没有声明析构方法。RtpVideoStreamReceiver::OnReceivedPayloadData 的内存是外…

3.网络爬虫——Requests模块get请求与实战

Requests模块get请求与实战requests简介&#xff1a;检查数据请求数据保存数据前言&#xff1a; 前两章我们介绍了爬虫和HTML的组成&#xff0c;方便我们后续爬虫学习&#xff0c;今天就教大家怎么去爬取一个网站的源代码&#xff08;后面学习中就能从源码中找到我们想要的数据…

普通Java工程师 VS 优秀架构师

1 核心能力 1.1 要成为一名优秀的Java架构师 只懂技术还远远不够&#xff0c;懂技术/懂业务/懂管理的综合型人才&#xff0c;才是技术团队中的绝对核心。 不仅仅是架构师&#xff0c;所有的技术高端岗位&#xff0c;对人才的综合能力都有较高的标准。 架构路线的总设计师 规…

安卓渐变的背景框实现

安卓渐变的背景框实现1.背景实现方法1.利用PorterDuffXfermode进行图层的混合&#xff0c;这是最推荐的方法&#xff0c;也是最有效的。2.利用canvas裁剪实现&#xff0c;这个方法有个缺陷&#xff0c;就是圆角会出现毛边&#xff0c;也就是锯齿。3.利用layer绘制边框1.背景 万…

多线程案例——阻塞队列

目录 一、阻塞队列 1. 生产者消费者模型 &#xff08;1&#xff09;解耦合 &#xff08;2&#xff09;“削峰填谷” 2. 标准库中的阻塞队列 3. 自己实现一个阻塞队列&#xff08;代码&#xff09; 4. 自己实现生产者消费者模型&#xff08;代码&#xff09; 一、阻塞队列…

【Pytorch】 理解张量Tensor

本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 这是目录张量Tensor是什么&#xff1f;张量的创建为什么要用张量Tensor呢&#xff1f;总结张量Tensor是什么&#xff1f; 在深度学习中&#xff0c;我们经常会遇到一个概念&#xff…

更改Hive元数据发生的生产事故

今天同事想在hive里用中文做为分区字段。如果用中文做分区字段的话&#xff0c;就需要更改Hive元 数据库。结果发生了生产事故。导致无法删除表和删除分区。记一下。 修改hive元数据库的编码方式为utf后可以支持中文&#xff0c;执行以下语句&#xff1a; alter table PARTITI…

Vue初入,了解Vue的发展与优缺点

作者简介&#xff1a;一名计算机萌新、前来进行学习VUE,让我们一起进步吧。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;我叫于豆豆吖的主页 前言 从本章开始进行Vue前端的学习&#xff0c;了解Vue的发展&#xff0c;以及背后的故事。 一.vue介…

ASEMI代理瑞萨TW9992AT-NA1-GE汽车芯片

编辑-Z TW9992AT-NA1-GE是一款低功耗NTSC/PAL模拟视频解码器&#xff0c;专为汽车应用而设计。它支持单端、差分和伪差分复合视频输入。集成了对电池短路和对地短路检测&#xff0c;先进的图像增强功能&#xff0c;如可编程的自动对比度调整&#xff08;ACA&#xff09;和MIPI…

【Linux】网络编程套接字(下)

&#x1f387;Linux&#xff1a; 博客主页&#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 看似不起波澜的日复一日&#xff0c;一定会在某一天让你看见坚持…

ASEMI代理MIMXRT1064CVJ5B原装现货NXP车规级MIMXRT1064CVJ5B

编辑&#xff1a;ll ASEMI代理MIMXRT1064CVJ5B原装现货NXP车规级MIMXRT1064CVJ5B 型号&#xff1a;MIMXRT1064CVJ5B 品牌&#xff1a;NXP /恩智浦 封装&#xff1a;LFGBA-196 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;196 类型&#…

【Hadoop-yarn-01】大白话讲讲资源调度器YARN,原来这么好理解

YARN作为Hadoop集群的御用调度器&#xff0c;在整个集群的资源管理上立下了汗马功劳。今天我们用大白话聊聊YARN存在意义。 有了机器就有了资源&#xff0c;有了资源就有了调度。举2个很鲜活的场景&#xff1a; 在单台机器上&#xff0c;你开了3个程序&#xff0c;分别是A、B…

Redis知识点汇总

前言 梳理知识 说一下项目中的Redis的应用场景 首先知道Redis的5大value类型: string,list,hash, set ,zset 2.基本上是缓存 3.为的是服务无状态, 4.无锁化 Redis是单线程还是多线程 1.无论什么版本,工作线程就一个 2.6.x高版本出现IO多线程

三天吃透操作系统面试八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

基于python的超市历年数据可视化分析

人生苦短 我用python Python其他实用资料:点击此处跳转文末名片获取 数据可视化分析目录人生苦短 我用python一、数据描述1、数据概览二、数据预处理0、导入包和数据1、列名重命名2、提取数据中时间&#xff0c;方便后续分析绘图三、数据可视化1、美国各个地区销售额的分布&…

进阶C语言——指针(二)【题目练习】

文章目录1.指针和数组概念的理解2.指针和数组笔试题解析一维数组字符数组二维数组1.指针和数组概念的理解 指针和数组 数组&#xff1a;能够存放一组相同类型的元素&#xff0c;数组的大小取决于数组的元素个数和元素类型指针&#xff1a;也是地址或指针变量&#xff0c;大小是…

Spring Cloud -- GateWay

为什么需要网关在微服务架构中&#xff0c;一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢&#xff1f;如果没有网关的存在&#xff0c;我们只能在客户端记录每个微服务的地址&#xff0c;然后分别去调用。这样的话会产生很多问题&#xff0c;例…

重构·改善既有代码的设计.04之重构手法(下)完结

1. 前言 本文是代码重构系列的最后一篇啦。前面三篇《重构改善既有代码的设计.01之入门基础》、《重构改善既有代码的设计.02之代码的“坏味道”》、《重构改善既有代码的设计.03之重构手法&#xff08;上&#xff09;》介绍了基础入门&#xff0c;代码异味&#xff0c;还有部…

【Java】你真的懂封装吗?一文读懂封装-----建议收藏

博主简介&#xff1a;努力学习的预备程序媛一枚~博主主页&#xff1a; 是瑶瑶子啦所属专栏: Java岛冒险记【从小白到大佬之路】 前言 write in the front: 如何理解封装&#xff1f; 试想&#xff1a;我们使用微波炉的时候&#xff0c;只用设置好时间&#xff0c;按下“开始”…
最新文章