• 特殊的转义字符—— \b 退格字符 ASCII 08


    引入

    我们在写 C 语言题目时,经常会碰见类似于 数字 分隔符 数字 分隔符 数字 分隔符 这样的输出。比如下面这段代码:

    1=1
    1+2=3
    1+2+3=6
    1+2+3+4=10
    
    • 1
    • 2
    • 3
    • 4

    如果用循环的话,这个加号是个大问题。直接用 printf("%d+"),最后面会多一个加号;用 printf("+%d") 则最前面会多一个加号。
    想要解决,则必须判断当前输出的是否为第一个或者最后一个数字,然后做特殊处理。

    新思路

    有人就发现了,转义字符里有一个\b,这是个退格字符,能不能用它把多余的加号给删了呢?
    那就试试呗,先输出个从 1 加到 5 试试

    #include 
    #include 
    
    int main(void)
    {
    	int sum = 0;
    	for (int i = 1; i <= 5; i++)
    	{
    		printf("%d+", i);
    		sum += i;
    	}
    	printf("\b");
    	printf("=%d\n", sum);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    好像没什么毛病,对吧?
    在这里插入图片描述
    让我们再提交到判题平台上试试
    在这里插入图片描述
    加号居然没删掉,而且还多了个点出来!

    真实含义

    我们把上面的代码稍稍改动一下

    #include 
    #include 
    
    int main(void)
    {
    	int sum = 0;
    	for (int i = 1; i <= 5; i++)
    	{
    		printf("%d+", i);
    		sum += i;
    	}
    	printf("\b");
    	//printf("=%d\n", sum); //<---- 注释这一行
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行效果:
    在这里插入图片描述
    这段代码和上面的一模一样,只是把等号后面的输出给删掉了而已。
    但是,最后的加号居然神奇地又出现了! 这是为什么呢?

    我们先来看一下“退格”究竟为何含义。
    \b 字符的确是退格字符,但此退格非“删除”。“退格”就是字面含义上的退格,即“往前退一格”,相当于你在 Word 里按一下左方向键。

    也就是说,\b 并不能删除上一个字符,它只是把光标往前移了一下而已

    那开头的代码为什么能正常输出呢?
    很简单,因为后面输出的字符覆盖掉了前面的字符,因此看起来好像是把上一个字符给删了。
    为了更清晰的表示这个过程,我做了一个动图。(偷一下懒,图里只制作了三个数字求和,但原理是一样的。)
    在这里插入图片描述
    事实上退格键在早期打印机上的作用就是“往前退一格”,后来退格键的含义变了,变成了“往前退一格 + 删除一个字符”。

    实际输出与显示

    问题还没有完全解决:为什么在本地可以,但是上传到判题平台就不行了呢?
    因为“显示的内容 ≠ 输出的内容”

    请看以下代码:

    #include 
    #include 
    
    int main()
    {
    	printf("123\n");
    	printf("123\b\n");
    	printf("123\b4\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果
    在这里插入图片描述

    然而,我们把它编译,然后把程序的输出结果重定向到文件里,得到的结果是这样的:

    123
    123
    1234
    
    
    • 1
    • 2
    • 3
    • 4

    这段输出在不同的地方显示的内容可能不相同
    Windows 记事本:一个框

    Visual Studio 2015:啥也没有
    在这里插入图片描述
    Visual Studio 2019:一个带空心圈的实心框
    ![[Pasted image 20221125225938.png]]
    Sublime:
    ![[Pasted image 20221125230132.png]]
    可以看到我们的 \b 字符,也就是 ASCII 码为 0x08 的字符被原样输出了出来, 在文本编辑器里并没有实现退格的效果。
    判题平台上使用的就是类似的方法,把程序的输出直接导出,传到网站上显示,但浏览器可不认 \b,于是就显示为了一个红点。

    实际应用

    利用这个退格字符,我们可以做一个进度条出来
    第一种:

    #include 
    #include 
    #include 
    
    int main()
    {
    	int index = 0;
    	char ch[] = {'|', '\\', '-', '/'};
    	while (1)
    	{
    		putchar(ch[index]);
    
    		index++;
    		if (index >= 4)
    			index = 0;
    
    		Sleep(200); // Sleep(200) 的作用是延时 200 毫秒(0.2 秒)再继续执行下面的代码
    		putchar('\b');
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    演示
    在这里插入图片描述

    第二种:

    #include 
    #include 
    #include 
    
    int main()
    {
    	//假设要做一个耗时较长的操作
    	//为了更好的用户体验,我们需要一个进度条
    	
    	double progress = 0.1; //当前进度
    	int length = 15; //进度条字符长度
    
    	for (progress = 0.1; progress <= 1; progress += 0.05)
    	{
    		//先输出 length 个 \b,把光标倒到开头去
    		//也可以直接用一个 \r
    		for (int j = 0; j < length + 2; j++)
    			putchar('\b');
    
    		putchar('[');
    		//已经完成部分的进度条
    		int count = (int)(length * progress); 
    		for (int j = 0; j < count; j++)
    			putchar('#');
    		//未完成部分的进度条
    		for (int j = 0; j < length - count; j++)
    			putchar(' ');
    		putchar(']');
    		
    		Sleep(100);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    演示
    在这里插入图片描述

  • 相关阅读:
    Qt 数据库的注册和登录功能
    Linux 系统服务
    AspNetCore&云效Flow持续集成
    HELP.md
    腾讯云CVM S5服务器性能测评和租用价格1年和五年
    【uniapp】将微信小程序代码转换为 uniapp 小程序
    信钰证券:首板第二天买入技巧?
    【1++的刷题系列】之双指针
    Ubuntu查看端口开放情况
    vue动画
  • 原文地址:https://blog.csdn.net/XcantloadX/article/details/128054164