在输入文本时,回车键一敲,就开始了新的一行,这个习惯性用法难免误导 C/C++ 的初学者们对 回车符(CR, Carriage Return)'\r' 和 换行符(LF, Linefeed)'\n' 的理解,这里这个问题我们暂且放下,后文再谈。先让我们来看看关于“回车”的有趣历史来源。
关于“回车键”的来历,要追朔到机械英文打字机的时代。在这种打字机上有个叫“字车”的部件,大概就是下面那个部分,会左右不停地跑的那东西。
当输满一行后,使用者就要把“字车”推到起始位置,这时打字机就会有两个动作,一是“字车”归位,二是滚筒上卷一行(相当于“字车”下移一行),这样就可以开始输入下一行了,这里推动“字车”的动作就称为“回车”。
上述打字机的“字符”归位的动作就相当于我们的 回车 '\r',只回到行首而仍在当前行,而滚筒上卷的动作就相当于 换行 '\n',移动到下一行。回车符 '\r' 对应 ASCII 码的16进制是 0x0d,10进制是 13,换行符 '\n' 对应16进制是 0x0a, 10进制是 10。
而不同的系统对回车的处理是不同的:在我们常用的 Windows 系统中用 "\r\n"两个字符来表示,如图,在第一行与第二行之间有两个字符位,分别是 0D 0A,即 ASCII 码对应的 '\r'和'\n'。这样的表示方法就和打字机的行为很相似了。
那么,同样的方法,在 Linux 上会是什么情况呢?请继续看。
在 Linux 上通过 vim 我们看到,在 a, ab, abc 之间只有一个字符位了,对应的是 0a,即 ASCII 码中的 '\n',这就说明在 Linux 上只用了一个换行字符来表示。
那么接下来让我们回到 C/C++ 中 '\r' 和 '\n' 的讨论中吧。在 C/C++ 中原风原味地保留了对换行符的这种理解,回车符 '\r' 仅表示回到行首,并没有包含换行的动作,换行是由 '\n' 来完成的,初学者一定要分清这两个符号的意义。
这里再提一个与 '\r' '\n' 类似的一个转义字符:退格(BS, Backspace)'\b',顾名思义,这个字符的意义是往前退一格,这里需要特别提醒的是:退格 '\b' 和回车 '\r' 都只是光标的移动,不会删除前面的文本!
现在让我们用一段简单的代码来验证 '\r' '\n' '\b' 的作用效果。
(1) C代码:
#include <stdio.h>
int main()
{
printf("abc\r\ncba\rrr\bz\n");
printf("abcd\b\b");
getchar();
return 0;
}
运行结果:
(2) C++ 代码:
#include <iostream>
int main()
{
using namespace std;
cout << "abc\r\ncba\rrr\bz\n";
cout << "abcd\b\b";
cin.get();
return 0;
}
运行结果:
(3) 分析:
首先我们看下输出的第一行 "abc\r\ncba\rrr\bz\n":
在输出 abc 后 \r 使回车符回到当前行即第一行的行首,但不删除字符,所以第一行最终显示 abc,然后 \n 使光标移到下一行,接着输出 cba,\r再次让光标回到行首,这次不换行,直接接着输出 rr,这样达到的效果是行首两个字符 cb 被替换为 rr,接着 \b 使光标向前一位,输出 z,这样第二个 r 就被换成了 z,然后换行,最终第二行显示结果就是 rza。
接着为了更直观地证明只有光标移动而不删除字符,我们看看第二行代码。"abcd\b\b",在两个 \b 过后,光标向前移动到 c 的下面(或者是 c 上的方块光标,亦或是在 c 前的 I 形光标),为了使光标停留以便观察,我们添加了 getchar() 和 cin.get()。
所以程序运行后的结果将是:
abc
rza
abcd
同时可以看到光标停留在上述位置,当然,这时如果你再输入字符,就会从光标的位置开始向后将 c 甚至 d 覆盖。
最后,附上一张转义字符的表格,供大家参考。
转义字符 | 意义 | ASCII码值(十进制) | ASCII码值(十六进制) |
\a | 响铃(BEL) | 007 | 0x07 |
\b | 退格(BS) ,将当前位置移到前一列 | 008 | 0x08 |
\f | 换页(FF),将当前位置移到下页开头 | 012 | 0x0C |
\n | 换行(LF) ,将当前位置移到下一行开头 | 010 | 0x0A |
\r | 回车(CR) ,将当前位置移到本行开头 | 013 | 0x0D |
\t | 水平制表(HT) (跳到下一个TAB位置) | 009 | 0x09 |
\v | 垂直制表(VT) | 011 | 0x0B |
\\ | 代表一个反斜线字符''\' | 092 | 0x5C |
\' | 代表一个单引号(撇号)字符 | 039 | 0x27 |
\" | 代表一个双引号字符 | 034 | 0x22 |
\? | 代表一个问号 | 063 | 0x3F |
\0 | 空字符(NULL) | 000 | 0x00 |
\ddd | 1到3位八进制数所代表的任意字符 | 三位八进制 | |
\xhh | 1到2位十六进制所代表的任意字符 | 二位十六进制 |