C语言中的\r是什么?

19
#include <stdio.h>

int main()
{
  int countch=0;
  int countwd=1;

  printf("Enter your sentence in lowercase: ");
  char ch='a';
  while(ch!='\r')
  {
    ch=getche();
    if(ch==' ')
      countwd++;
    else
      countch++;
  }

  printf("\n Words =%d ",countwd);

  printf("Characters = %d",countch-1);

  getch();
}

这是我遇到 \r 的程序。它在这里的作用是什么?我是 C 的初学者,希望能得到一个清晰的解释。


1
+1 for "我已经谷歌搜索过了..."。这绝对是一个难以或无法通过谷歌搜索得到答案的问题。 - R.. GitHub STOP HELPING ICE
@R能否给我解释一下以下几行代码的含义? char ch='a'; while(ch!='\r') 这两行代码如何帮助读取整行数据? - GEEK max
7个回答

19

'\r' 是回车字符。主要的应用场景包括:

  1. 在二进制模式下阅读文本或者可能来自外部操作系统的文本时,由于Windows格式的文本文件使用CR/LF作为行尾标识符,因此您可能需要找到并且舍弃它。

  2. 当向交互式终端上的 stdout 或者 stderr 写入数据时,可以使用 '\r' 将光标移回到行的开头,以便覆盖它并显示新内容。这是一种不错的原始进度指示器。

您发布的示例代码绝对是使用 '\r' 的错误方法。它假设回车符将出现在输入行末尾的换行符之前,这种方法不具有可移植性,并且只适用于Windows。相反,代码应该查找 '\n'(换行符),并在换行符之前舍弃任何回车符。或者,可以使用文本模式并让C库处理转换(但文本模式不美观,可能不应该使用)。


@R,你能解释一下上面的while循环吗?它检查了什么(ch!='\r'),而ch被初始化为'a',这是什么意思? - GEEK max
这就像说使用MFC是错误的,因为它不可移植。人们构建特定于平台的应用程序有什么问题? - Luchian Grigore
MFC是什么意思?我是一个初学者,你能清楚地解释一下吗?当(ch!='\r')且ch被初始化为'a'时,这是什么意思? - GEEK max
@Luchian 这会与可重用性产生冲突。 - Kyss Tao
3
测试 (ch != '\r') 是 毫无必要 的不可移植的……如果您正在使用MFC,您将获得MFC提供的某些内容……但在这种情况下,您可以测试 '\n',它将保证在所有平台上都能正常工作。 - Barton Chittenden
3
这段代码显然是为了初学C语言的人准备的教材。而刚开始学习C语言的人应该学习如何正确使用C语言,而不是使用不可移植的技巧。当然,在某些特定平台上使用特定的库或假设是有时机和场合的,但这只适用于特定于该平台构建的小型隔离模块,而不是通用代码。初学C语言的人应该从一开始就正确掌握这一点,否则他们的代码质量将大大降低。 - R.. GitHub STOP HELPING ICE

13

我知道这是回车符,但你能解释一下它在上面的代码中的作用吗,以便我可以清楚地理解吗? - GEEK max
ch 不必初始化为 a。它可以是任何与 \r 不同的字符,因为在第一次迭代中就会读取它。 - Luchian Grigore
你的评论解决了我的问题,现在我明白了。谢谢。 - GEEK max
在上述问题中,Getchar和Getche有什么区别?如果我使用Getchar它不起作用。你能解释一下为什么吗? - GEEK max
1
@GEEKmax 这个应该很容易在谷歌上找到。http://www.daniweb.com/software-development/c/threads/37195 第一个链接。 - Luchian Grigore

12
从前,人们使用像打字机一样的终端设备(只有大写字母,但那是另一个故事)。搜索“Teletype”,你认为为什么tty被用作“终端设备”?
这些设备有两个独立的动作。回车将打印头移回到行的开头而不滚动纸张; 换行字符将纸张向上移动一行,而不将打印头移回到行的开头。因此,在这些设备上,需要两个控制字符才能使打印头返回到下一行的开头:回车和换行。由于这是机械的,所以在发送CR和LF字符后,在向终端发送更多字符之前必须暂停足够长的时间。 CR无LF的一个用途是通过覆盖线条上的字符来进行“加粗”。你会先把这行写出来,然后使用CR重新开始,并在需要加粗的字符上重复打印两次。当然,你还可以在需要部分隐藏的内容上键入X,或者通过审慎覆盖来创建非常密集的ASCII艺术图像。
在Unix上,所有这些东西的逻辑都隐藏在终端驱动程序中。您可以使用stty命令和底层函数(那时是ioctl()调用;它们在1988年被POSIX.1清理成termios接口)来调整终端行为的各种方式。
最终,你获得了“玻璃终端”,速度更快,有新的特殊情况需要处理——Hazeltine故障等等。这些被奉为神圣的termcap和后来的terminfo库,然后进一步封装在curses库中。
但是,其他一些(非Unix)系统没有隐藏好事情,您必须在文本文件中处理CRLF——不,这不只是Windows和DOS属于“ CRLF”阵营。无论如何,在某些系统中,C库必须处理包含CRLF换行符的文本文件,并将其呈现为仅在行末有换行符的形式呈现给你。但是,如果你选择将文本文件视为二进制文件,则会看到CR字符以及LF。
像旧版Mac OS(版本9或更早版本)这样的系统仅使用CR(也称为\r)作为行尾。像DOS和Windows(以及我认为的许多DEC系统,例如VMS和RSTS)这样的系统使用CRLF作为行尾。许多互联网标准(例如邮件)都规定了CRLF行尾。Unix始终只使用LF(也称为NL或newline,因此\n)作为其行尾。大多数人大多数时候都能忽略CR。
你的代码在寻找\r方面有些古怪。在遵循C标准的系统上,除非文件以二进制模式打开,否则CRLF或CR会被C运行时库映射为NL。

3
这并不总是正确的;它只在Windows中有效。对于在putty、Linux shell等终端交互中,它将用于将光标返回到行的开头。下图展示了其用法: 没有'\r': 数据以没有'\r'的形式传递到putty终端,只有'\n'。这意味着数据将在下一行打印。

enter image description here

“With '\r'”:

数据带有'\r',即字符串以'\r\n'结尾。因此,在Putty终端中,光标不仅会移到下一行,而且还会移到行的开头。

enter image description here


2
有几个字符可以表示新行。通常有以下两个: '\n' 或 '0x0A'(10进制中的10)-> 这个字符被称为“换行符”(LF)。 '\r' 或 '0x0D'(十进制中的13)-> 这个字符被称为“回车符”(CR)。
不同的操作系统以不同的方式处理换行。以下是最常见的几种:
DOS和Windows
它们期望换行符是两个字符的组合,即 '\r\n'(或13后跟10)。
Unix(因此也包括Linux)
Unix使用单个 '\n' 表示新行。
Mac
Mac使用单个 '\r'。

2
回车符仅在Mac OS版本9及更早版本中由Mac使用。Mac OS X使用常规的Unix换行符作为行终止符。 - Jonathan Leffler
你关于 Mac 的信息已经过时,与过去十年左右无关。 - R.. GitHub STOP HELPING ICE

1

\r 是转义序列字符或空字符。它用于将光标移动到行的开头(可能是同一行或新行),以便覆盖新内容(在 \r 之前写入的内容,例如:\rhello);

int main ()
{
  printf("Hello \rworld");
  return 0;
}

程序的输出将是world而不是Hello world,因为\r将光标放在行的开头,Helloworld覆盖了。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接