一、转义字符是什么
顾名思义就是转变原来意思的字符。
举例:'n'本来就是单纯的字符n,但是‘\n’就和字符n没有任何关系,但它可以实现换行的功能。
#include <stdio.h> int main() { printf("abcndef"); return 0; }#include <stdio.h> int main() { printf("abc\ndef"); return 0; }二、转义字符有哪些(速览)
\? 在书写连续多个问号时使用,防止被编译器解析成三字母词;
\' 用于表示字符常量 ' ;
\'' 用于表示一个字符串内部的双引号;
\\ 用于表示一个反斜杠,防止它被解释为转义序列符;
\a 警报,使得终端发出警报声或出来闪烁,或者两者同时发生;
\b 退格键,光标回退一个字符,但不删除字符;
\f 换页符,光标移到下一页。现在基本不用,本文不做详细讲解;
\n 换行符;
\r 回车符,光标移到同一行的开头;
\t 水平制表符,光标移动到下一个水平制表位,通常是4或8的倍数;
\v 垂直分隔符,光标移动到下一个垂直制表位。现在基本不用,本文不做详细讲解;
\ddd d d d表示1~3个八进制的数字。 可以理解为字符的八进制表示形式。如:\130 表示字符X;
\xdd d d表示2个十六进制数字。可以理解为字符的十六进制表示形式。如:\x30 表示字符0;
三、给转义字符分类
分类依据:根据各自的实际用途以及在ASCII码表中的排列
1.控制转义字符(ASCII 7~13)
我们知道,ASCII码从0到31总共32个是不可打印字符,全部是不可见硬件指令。我们上面聊到的转义字符产生的效果中有共有7个来自这里:
| 转义字符 | 名称 | ASCII |
|---|---|---|
\a | 响铃 Alert | 7 |
\b | 退格 Backspace | 8 |
\t | 水平制表 Tab | 9 |
\n | 换行 Newline | 10 |
\v | 垂直制表 Vertical Tab | 11 |
\f | 换页 Form feed | 12 |
\r | 回车 Return | 13 |
以下是个人的思考,可以选择性阅读:
我曾经一直纳闷的一个问题是:为什么不直接把转义字符本来的样子如“\a” "\b"等直接放到ASCII码表的“ch”栏,而是要用“BEL(响铃)” “BS(退格)”等这样的方式表示?
后来查阅资料,终于明白了:ASCII码表诞生早于C语言。在创造ASCII码的时候,人们就知道这类指令确实没有图案,但总不能画一个空白框吧?所以人们给每个控制字符起英文名字,用缩写代表它的功能含义。这些英文缩写才是标准名称,给工程师、硬件手册、协议文档使用。C语言是后来单独设计的源代码语法,\a \b这种转义字符只是方便程序员书写看不见的控制字符。
2.符号转义字符
| 转义字符 | 作用 | ASCII |
|---|---|---|
\' | 输出单引号' | 39 |
\" | 输出双引号" | 34 |
\\ | 输出反斜杠\ | 92 |
\? | 输出问号? | 63 |
这4个转义字符的最终效果都是可输出各自的原始字符,而原始字符在ASCII表中属于可见字符。
到这里,会不会有小伙伴有这样的问题:那ASCII码值中的 单引号 ' 双引号 '' 斜杠 \ 问号? 到底带不带斜杠呢?
其实,ASCII码表里面的这些符号只有纯字符,这一套带斜杠的写法,只是C语言源代码的语法标记而已,和ASCII码没有任何关系!
如果还是迷糊,也不要紧,下文将会举很多例子帮助理解。
3.通用数值转义
上述两类每一种转义字符只能固定代表唯一1个字符,但 \ddd 和 \xhh 却可以通过修改数字,表达ASCII码中任意单个字符。
四、逐个详解(按照ASCII码表的顺序)
1. \a
警报,使得终端发出警报声或出来闪烁,或者两者同时发生。
#include <stdio.h> int main() { printf("\a"); return 0; }在笔者使用的设备上,这段代码运行的效果是警报声,也没有办法在此呈现,读者可在自己的电脑上感受效果,至于闪烁效果,则和终端模拟器程序有关,这里不做详解,读者可以自行查阅资料学习。
2. \b
退格键,光标回退一个字符,但不删除字符。
我们先来看没有 \ 的效果
#include <stdio.h> int main() { printf("climb"); return 0; }加上 \ 后呢
#include <stdio.h> int main() { printf("clim\b"); return 0; }这个结果看起来是不是有些矛盾呢?明明是光标回退一个字符且不删除字符,但这个结果看上去删除了一个字符,why?
先不着急回答这个问题,来看一下 F10逐过程调试(VS2026)的结果(逐过程调试可以理解为一句一句地执行代码,这样做可以让我们更加明白代码是如何一步一步被执行的)
看来确实只是光标退回一格,并没有删除字符。只是VS的终端渲染特性导致最终程序运行的视觉效果是少了一个m。(这里就不过度深究了,不然偏离主题了~)
我们换一个平台,用Dev C++
Dev C++就没有出现这样的情况
当然,如果非要在VS上让最后的m显现出来也是可以的,用一个换行符 \n
#include <stdio.h> int main() { printf("clim\b\n"); return 0; }如果 \b 真的在退格的同时删除了m字符,那么就不会呈现这样的效果啦。
可能有些小伙伴会想为什么m不会去下一行,不是换行了吗?因为换行符 \n 只是移动光标到下一行,并不会把字符也搬下去。
上面的代码是将\b放在最后,如果有\b后面还有内容会怎么样呢?我们来试试
#include <stdio.h> int main() { printf("clim\b\bab"); return 0; }也就是说如果\b后面有其他字符,那么\b前面的字符将会被覆盖。
3. \t
水平制表符,光标移动到下一个水平制表位,通常是4或8的倍数。
\t一般是用来做数据的对齐的。我们先来试试效果
#include <stdio.h> int main() { printf("a\tbc\tdef\tghij\tklmno\tw"); return 0; }从最终的运行结果中,我们可以看出,只要出现 \t ,控制台就会预留出一定的位置,使得空出来的位置和前面字符所占的位置加起来总共是8个字符的位置(VS默认是这样的)。
那如果\t前面的字符超过8个会怎么样呢?
#include <stdio.h> int main() { printf("abcdefghij\tklmno\tw"); return 0; }那就会从第9个开始算。那如果更多呢?道理是一样的。快去动手验证一下自己的想法吧!
4. \n
换行符。
这可是老朋友了!这里就只放一段代码给大家呈现一下效果
#include <stdio.h> int main() { printf("abc\ndef"); return 0; }这个符号用的太多了,所以笔者这里不再做过多赘述。主要是和下一个回车符 \r 做区分。
5. \r
回车符,光标移到同一行的开头。
\n是真的换到了下一行,而\r则是移到同一行的开头。来看效果
#include <stdio.h> int main() { printf("abcdef\r"); return 0; }上面第二张图是程序运行的最终效果,为什么会少了字母a,还是和VS的终端渲染特性有关。因此,放了第三张逐过程调试的图,可以看到光标确实是回到了同一行的开头。
那如果\r后面还有其他字符呢?我们来试试(这次直接放逐过程调试的图了)
#include <stdio.h> int main() { printf("abcdef\rghi"); return 0; }到此,控制转义字符就讲解完了,下面是符号转义字符,主要研究他们分别在什么场景下使用。
6. \"
用于表示一个字符串内部的双引号。
如果我们想在字符串中打印 " ,比如,打印 abc"def,如果直接打印,会发生什么,我们试试
#include <stdio.h> int main() { printf("%s\n", "abc"def"); return 0; }直接发生了编译错误
为什么呢?因为编译器在编译这段代码时会把我们需要打印到屏幕上的那个 " 看作是字符串结束的那个双引号,也就是要打印的那个双引号和前面的双引号组成了一对,编译器看不懂了。
因此,C语言有了相关的语法规定,在字符串中出现的 " 必须变成 \" ,加了斜杠的双引号,就失去了和别的双引号成对的可能,使得其就是一个普普通通的双引号。
我们再试试
#include <stdio.h> int main() { printf("%s\n", "abc\"def"); return 0; }这样就没问题了。
再举一个例子,就只打印一个 "
注意:\"的应用场景只是在字符串当中,如果是要打印字符" ,那当然是没问题的
7. \'
用于表示字符常量 ' 。
道理和 \" 是一模一样的,这里就不过多赘述了,只不过是在打印单个字符的情景中出现,来看看这段代码
#include <stdio.h> int main() { printf("%c\n", '''); return 0; }在大家的预料之中,编译失败了,那加上斜杠之后呢?
#include <stdio.h> int main() { printf("%c\n", '\''); return 0; }这样就可以正常打印了,你学会了吗?
8. \?
在书写连续多个问号时使用,防止被编译器解析成三字母词。
这里没有办法给大家验证展示了。因为只有老式的编译器才会将连续多个问号解析成三字母词,现在的编译器基本都比较新的,自然就没有办法给大家展示了。
但我们依旧可以用文字进行说明,比如,你想在屏幕上打印(what are you 弄啥嘞??),如果不使用转义字符,老式的编译器就会将??)解析成],打印出来(what are you 弄啥嘞]。
如果在?前加上\,就等于告诉编译器:我这个?就是单独的问号,不会和别的符号进行组合变成一个转义字符
9. \\
用于表示一个反斜杠,防止它被解释为转义序列符。
不知道大家有没有这样的疑问,\加上一个其他字符就可以发挥一些不一样的作用,那如果想打印\本身,那这个\会不会被误解呢?
实践出真知,这里我们举2个例子。
首先是打印字符 \
如果只打1个\
看来编译器是把 \ 和它后面的 ' 读成 \' 了。那怎么办呢?正所谓解铃还须系铃人,前面再加1个 \ 试试
所以 \\ 就表示一个真正的斜杠,也许可以理解为:前一个 \ 不让后一个 \ 和别的字符组合。
再试试打印字符串
如果单个 \ 后面遇到了可以组合的字符,那么就会形成转义字符。
那如果 \ 后面是不能组合的字符呢?
我们会发现,就算 \ 后面没有字符可以与之组合,\ 也不会被打印出来,这是因为MSVC(VS编译器)的规则是:遇到未知转义序列,就直接丢弃 \ ,只保留后面的字符
那好吧,只能老老实实再打上一个 \ 了
10.\ddd
可以理解为字符的八进制表示形式。
比如:\130
130是八进制数字,换算成十进制数是88(进制转换不作详细讲解),ASCII码值是88的字符是大写的X,\130代表的就是'X'(字符X)
真的是这样吗?
#include <stdio.h> int main() { printf("%c\n", '\130'); return 0; }到这里,细心的朋友可能会发现,从开始到现在,好像还没有提到过 \0 ,就是那个字符串的结束标志。没错,因为 \0 是 \ddd 的一种,代表ASCII码值为0的字符,也就是null字符
11.\xdd
可以理解为字符的十六进制表示形式。
比如:\x30
x代表十六进制,30是十六进制数字,换算成十进制数是48,ASCII码值是88的字符是数字0,\x30代表的就是'0'(字符0)
再来验证一下
#include <stdio.h> int main() { printf("%c\n", '\x30'); return 0; }如果还是不太相信,可以自己再换一个字符去尝试哦~
五、小试牛刀
#include <stdio.h> #include <string.h> int main() { int len1 = strlen("c:\test\16\test.c"); int len2 = strlen("c:\test\\16\test.c"); //strlen函数统计的是字符串中\0之前的字符个数,不包含\0 printf("len1=%d,len2=%d", len1, len2); return 0; }上面这段代码中len1,len2分别等于多少?
答案公布在评论区,感谢观看!
完!