【深度解刨C语言】符号篇(全)
文章目录
- 一.注释
- 二.续行符与转义符
- 1.续行符
- 2.转义符
- 三.回车与换行
- 四.逻辑操作符
- 五.位操作符和移位操作符
- 六.前置++与后置++
- 七.字符与字符串
- 八./和%
- 1.四种取整方式
- 2.取模与取余的区别和联系
- 3./两边异号的情况
- 1.左正右负
- 2.左负右正
- 九.运算符的优先级
一.注释
注释的两种符号:
- // +内容
- /*+内容 */
- 说明:/*只会与最近的 */进行匹配。
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后置减减再减去bprintf("%d\n", c);//答案是-1a = 1;b = 2;c = a - --b;//是b前置--,然后a再减去bprintf("%d\n", c);//答案:0return 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是13return 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//答案是:0printf("%d\n", 1 | 2);//3// 01//& 10// 11//答案:3printf("%d\n", 1 ^ 2);//3// 01//^ 10// 11//答案:3printf("%d\n", ~-1);//0// 11111111 11111111 11111111 11111111//~// 00000000 00000000 00000000 00000000//答案:0return 0;
}
移位操作符
1.移位操作符运算后不会影响操作数本身
2.移位操作符运算的范围为整数
- 左移操作符
符号:<<(双箭头向左)
功能:将补码整体左移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));//4printf("%d\n", sizeof(!a));//1printf("%d\n", sizeof(a&a));//4printf("%d\n", sizeof(a|a));//4printf("%d\n", sizeof(a^a));//4printf("%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=aa = a ^ b;//a = b^(a^a)=b^0=bprintf("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,所以是1return 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.0return 0;
}
2.向负无穷取整
#include<stdio.h>
#include<math.h>
int main()
{printf("%f\n", floor(5.4));//5.0return 0;
}
3.向正无穷取整
函数:ceil()
参数:double
返回值:double
#include<math.h>
int main()
{printf("%f\n", ceil(5.4));//6.0return 0;
}
4.四舍五入取整
函数:round()
参数:double
返回值:double
#include<math.h>
int main()
{printf("%f\n", round(5.4));//5.0return 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-qd=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-qd=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.当为取余时,商实际上会比较大(负数),绝对值比较小,所以|qd|<|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.当为取余时,商实际上会比较大(负数),绝对值比较小,所以|qd|<|a|,r是小于0的。
九.运算符的优先级
相关文章:

【深度解刨C语言】符号篇(全)
文章目录一.注释二.续行符与转义符1.续行符2.转义符三.回车与换行四.逻辑操作符五.位操作符和移位操作符六.前置与后置七.字符与字符串八./和%1.四种取整方式2.取模与取余的区别和联系3./两边异号的情况1.左正右负2.左负右正九.运算符的优先级一.注释 注释的两种符号ÿ…...

VS Code 将推出更多 AI 功能给 Java 开发者
大家好,欢迎来到我们的二月更新!我们将为您带来与 JUnit 5 并行测试相关的新功能以及用于 Spring Boot Dashboard 的过滤功能。另外,OpenAI 和 ChatGPT 是最近的热点,所以在 GitHub Copilot 方面也有一些令人激动的消息࿰…...

关于利用FFT分析时域信号幅相的思考与验证
引言 利用FFT分析/估计时域信号的幅度和相位,属于传统估计的范畴。估计的准确程度受频率分辨率的影响较大。如果被估计的目标频率等于频率分辨率的整数倍,信号的幅相估计都是最准确的。一旦目标频率不等于频率分辨率的整数倍,幅度估计值将会…...

基于java中的Springboot框架实现餐厅点餐系统展示
基于java中的Springboot框架实现餐厅点餐系统开发语言和工具 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 21世纪的今天,随着社会的不断发展与进步,人们对…...

案例07-在线人员列表逻辑混乱
一、背景介绍 在线人员列表涉及到的问题: 类中写了公共变量最后导致数据混乱现象 保存数据没有考虑业务的隔夜覆盖导致的逻辑漏洞 涉及到继承,对于this,如果父类有同样的成员最终使用哪一个? 参数不一致导致后续维护混乱 mysql由…...
Java集合框架
Java集合框架是Java编程语言所提供的一种便捷的数据结构的实现。Java集合框架提供了一种统一的接口和机制来访问和操作集合中的元素,这些元素可以是对象、基本数据类型或其他集合。Java集合框架是Java应用程序中最常用的特性之一,它为开发人员提供了许多…...

奇异值分解(SVD)原理与在降维中的应用
奇异值分解(SVD)原理与在降维中的应用 奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域。是很多机器学习算…...
GDB调试程序
1.GDB 调试程序 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。在UNIX平台下做软件,GDB这个调试工具有比VC的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。 一般来说,GDB主要帮忙你完成下面四个方面的功能…...

五种IO模型
用户空间与内核空间 操作系统把内存空间划分成了两个部分:内核空间和用户空间。 为了保护内核空间的安全,操作系统一般都限制用户进程直接操作内核。 所以,当我们使用TCP发送数据的时候,需要先将数据从用户空间拷贝到内核空间&a…...
5 全面认识java的控制流程
全面认识java控制流程1.块作用域2.条件语句3.迭代语句3.1while语句3.2do-while语句3.3for语句3.4 for-in语法4.中断控制流程的语句4.1 return4.2 break和continue4.2.1 不带标签的break语句4.2.2 带标签的break语句4.2.3 continue语句4.3 goto()5.多重选择:switch语句1.块作用域…...
第二章 测验【嵌入式系统】
第二章 测验【嵌入式系统】前言推荐第二章 测验【嵌入式系统】最后前言 以下内容源自《嵌入式系统》 仅供学习交流使用 推荐 第一章 测验【嵌入式系统】 第二章 测验【嵌入式系统】 1单选题 32bit宽的数据0x12345678 在小端模式(Little-endian)模式…...

排序算法之插入排序
要考数据结构了,赶紧来复习一波排序算法 文章目录一、直接插入排序二、希尔排序一、直接插入排序 直接上主题 插排,揪出一个数,插入到原本已经有序的数组里面,如数组有n个数据,从0~n下标依次排列,先从左往…...

Kaggle实战入门:泰坦尼克号生生还预测
Kaggle实战入门:泰坦尼克号生生还预测1. 加载数据2. 特征工程3. 模型训练4. 模型部署泰坦尼克号(Titanic),又称铁达尼号,是当时世界上体积最庞大、内部设施最豪华的客运轮船,有“永不沉没”的美誉ÿ…...
【大汇总】11个Python开发经典错误(1)
“但是太阳,他每时每刻都是夕阳也都是旭日。当他熄灭着走下山去收尽苍凉残照之际,正是他在另一面燃烧着爬上山巅散烈烈朝晖之时。” --------史铁生《我与地坛》 🎯作者主页:追光者♂🔥 🌸个人简介:计算机专业硕士研究生💖、2022年CSDN博客之星人工智能领…...

Java中的异常
程序错误一般分为三种:编译错误: 编写程序时没有遵循语法规则,编译程序能够自己发现错误并提示位置和原因。运行错误:程序在执行的时候运行环境发现了不能执行的操作。比如,JVM出错了,内存溢出等。逻辑错误…...
L2-022 重排链表 L2-002 链表去重
给定一个单链表 L1 →L2→⋯→L n−1 →L n ,请编写程序将链表重新排列为 L n →L 1 →L n−1 →L 2 →⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。 输入格式: 每个输入包含1个测试用例。每个测试用例第1行…...

【手撕八大排序】——插入排序
文章目录插入排序概念插入排序分为2种一 .直接插入排序直接插入排序时间复杂度二.希尔排序希尔排序时间复杂度效率比较插入排序概念 直接插入排序是从一个有序的序列中选择一个合适的位置进行插入,这个合适的位置取决于是要升序排序还是降序排序。 每一次进行排序…...

flink多流操作(connect cogroup union broadcast)
flink多流操作1 分流操作2 connect连接操作2.1 connect 连接(DataStream,DataStream→ConnectedStreams)2.2 coMap(ConnectedStreams → DataStream)2.3 coFlatMap(ConnectedStreams → DataStream)3 union操作3.1 uni…...

漫画:什么是快速排序算法?
这篇文章,以对话的方式,详细着讲解了快速排序以及排序排序的一些优化。 一禅:归并排序是一种基于分治思想的排序,处理的时候可以采取递归的方式来处理子问题。我弄个例子吧,好理解点。例如对于这个数组arr[] { 4&…...

vue 3.0组件(下)
文章目录前言:一,透传属性和事件1. 如何“透传属性和事件”2.如何禁止“透传属性和事件”3.多根元素的“透传属性和事件”4. 访问“透传属性和事件”二,插槽1. 什么是插槽2. 具名插槽3. 作用域插槽三,单文件组件CSS功能1. 组件作用…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...