如何在C语言中清空控制台屏幕?

72

除了使用 system("cls"),C语言中是否有“正确”的清除控制台窗口的方法?


http://www.cplusplus.com/forum/articles/10515/ 包含一些代码。虽然它不适用于Windows和POSIX系统,但对未来阅读此问题的任何人都可能有用。 - Aseem Bansal
1
也可以在这里查看:http://www.cplusplus.com/articles/4z18T05o/ - Marcello Romani
没有人提到标准ASCII控制字符FF(换页符),它可以在打印机或打印终端(如vt100)上弹出一页。 - stark
15个回答

44
printf("\e[1;1H\e[2J");

这个函数可以在ANSI终端上工作,需要POSIX。我假设也有一个版本可以在Windows控制台上工作,因为它也支持ANSI转义序列。

#include <unistd.h>

void clearScreen()
{
  const char *CLEAR_SCREEN_ANSI = "\e[1;1H\e[2J";
  write(STDOUT_FILENO, CLEAR_SCREEN_ANSI, 12);
}

还有一些其他选择,其中一些不会将光标移动到 {1,1}。


1
只是让你知道,就此而言,在Windows的cmd.exe控制台中,这个序列并不能正常工作。 - dodgy_coder
1
它如何要求POSIX?我不相信那些转义序列是由POSIX标准指定的。 - Keith Thompson
那对我不起作用。但是,对我有用的是简单的旧式 "\e[2J"。我知道已经过去了四年,但是...能解释一下区别吗?或者 "\e[1;1H" 应该做什么? - Braden Best
使用这个,我没有收到ISO兼容性错误: \ 033 [2J \ 033 [1; 1H - Geremia
Windows的命令提示符(从Windows 98到Windows 7)不支持ANSI转义。据QPaysTaxes指出,似乎在Windows 10中和预计在Windows 8中也支持。 - MD XF
显示剩余5条评论

31

嗯,C语言无法理解屏幕的概念。因此,任何代码都会失去可移植性。也许可以根据您的需求看看 conio.hcurses

无论使用哪个库,可移植性都是一个问题。


3
在读到关于conio.h的那行之前,我已经点赞了你。请注意,这也是高度不可移植的。 - Derrick Turk
我不确定conio.h,但看起来curses以比我最初想象的更全面的方式处理GUI。我得研究一下这个。谢谢你的建议! - devurs

27

为了移植性,请尝试以下方法:

#ifdef _WIN32
#include <conio.h>
#else
#include <stdio.h>
#define clrscr() printf("\e[1;1H\e[2J")
#endif

然后只需调用clrscr()。在Windows上,它将使用conio.hclrscr()函数,在Linux上,它将使用ANSI转义码。

如果你真的想要“正确地”做到这一点,你可以消除中间人(conioprintf等),仅使用低级系统工具进行操作(准备大量代码倾泻):

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void ClearScreen()
{
  HANDLE                     hStdOut;
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  DWORD                      count;
  DWORD                      cellCount;
  COORD                      homeCoords = { 0, 0 };

  hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
  if (hStdOut == INVALID_HANDLE_VALUE) return;

  /* Get the number of cells in the current buffer */
  if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
  cellCount = csbi.dwSize.X *csbi.dwSize.Y;

  /* Fill the entire buffer with spaces */
  if (!FillConsoleOutputCharacter(
    hStdOut,
    (TCHAR) ' ',
    cellCount,
    homeCoords,
    &count
    )) return;

  /* Fill the entire buffer with the current colors and attributes */
  if (!FillConsoleOutputAttribute(
    hStdOut,
    csbi.wAttributes,
    cellCount,
    homeCoords,
    &count
    )) return;

  /* Move the cursor home */
  SetConsoleCursorPosition( hStdOut, homeCoords );
}

#else // !_WIN32
#include <unistd.h>
#include <term.h>

void ClearScreen()
{
  if (!cur_term)
  {
     int result;
     setupterm( NULL, STDOUT_FILENO, &result );
     if (result <= 0) return;
  }

   putp( tigetstr( "clear" ) );
}
#endif

1
实际上这真的很好。+1 指出了使用 ANSI 转义序列和来自 conio.h 的可怕但有用的 clrscr() 的“便携”方式。 - Manoel Vilela
只是说一下:在mingw编译器的conio.h实现中,clrscr()不可用。 - Manoel Vilela

19

一个在Windows(cmd.exe)、Linux(Bash和zsh)以及OS X(zsh)上测试过的解决方法:

#include <stdlib.h>

void clrscr()
{
    system("@cls||clear");
}

8
1- Its monstrous; → 它很可怕; 2- The OP explicitly asked not to use it; → 楼主明确要求不要使用它; 3- OP is asking for C language command, and system calls commands for other languages (said, bash, zsh, batch, etc.). Still +1 to try to make it portable. (I've tested on debian/linux and win7, even inverting the arguments. No need the @ also, because the command will not be on the screen after run) → 楼主正在寻求C语言指令,而system调用的是其他语言的指令(如said、bash、zsh、batch等)。尽管如此,还是要尝试使其具有可移植性。(我已在debian / linux和win7上进行了测试,甚至翻转了参数。也不需要@,因为命令将在运行后不会显示在屏幕上)。 - DrBeco

13

使用宏可以检查当前操作系统是否为Windows、Linux、Mac或Unix,并根据当前平台调用相应的函数。示例代码如下:

void clear(){
    #if defined(__linux__) || defined(__unix__) || defined(__APPLE__)
        system("clear");
    #endif

    #if defined(_WIN32) || defined(_WIN64)
        system("cls");
    #endif
}

1
即使您为 64 位构建,Windows 上也将定义 _WIN32 - jdt

9
#include <conio.h>

并使用

clrscr()

9
请注意,这不是可携带的。 - Billy ONeal
3
不符合C语言标准。注意,OP提到了是否存在一种“正确”的方式。 - Muthu Ganapathy Nathan

9

由于你提到了cls,这似乎是与Windows相关的。如果是这样,那么这篇KB文章中有可以实现它的代码。我刚试过了,当我使用以下代码调用它时,它起作用了:

cls( GetStdHandle( STD_OUTPUT_HANDLE ));

1
+1 虽然我没有问,但这可能非常有用。在Unix上可以做什么来“清除”? - N 1.1
@nvl: 我家里只有 Windows 电脑,需要使用大约 15 个用户名和密码才能从这里登录到工作电脑,所以我现在无法测试。但我相信 ncurses 是解决这个问题的途径(http://linux.die.net/man/3/ncurses)。 - Mark Wilkins
我实际上是在考虑基于Unix的系统——但这有助于Windows。谢谢! - devurs
当我在C11中使用它时,会出现“非ISO标准转义序列'\ e'”的错误。 - Geremia

5

没有一种C语言的可移植方法来做到这一点。尽管各种光标操作库,如curses相对可移植。conio.h在OS/2 DOS和Windows之间可移植,但不能用于*nix变体。

"控制台"的整个概念是标准C范围之外的概念。

如果你正在寻找一个纯Win32 API解决方案,则Windows控制台API中没有单个调用可以完成此操作。一种方法是使用FillConsoleOutputCharacter足够大数量的字符。或者使用WriteConsoleOutput,你可以使用GetConsoleScreenBufferInfo找出需要多少个字符。

你还可以创建一个全新的控制台屏幕缓冲区并将其设置为当前缓冲区。


4

Windows:

system("cls");

在Windows系统中使用此命令可以清空控制台窗口。

Unix:

system("clear");

在Unix系统中使用此命令可以清空控制台窗口。

你也可以通过插入换行符来滚动屏幕,具体可以参考这里的内容。

通过这些方法,你可以轻松实现跨平台操作。


7
楼主明确表示这不是他所寻找的。 - Billy ONeal
立即采取的方法会立刻带来下一个问题:为了让终端滚动条滚动到底部,需要写入多少个换行符才足够? - Premature Optimization
2
@PrematureOptimization 四十个 quadvigiseptanovatriheptasexgesillion,我们在拥有一个带有强大的大数库的2048位CPU之前无法处理。抱歉,你没那么幸运。你只能接受这样一个事实,那些使用帝国大厦侧面作为投影监视器,并在全屏终端上运行1pt字体的人将获得一个丑陋的“清除”效果。这是一个罕见的边缘情况。否则,大约100行代码就可以解决问题。(在1080p显示器上以默认字体运行的Xterm仅有74行) - Braden Best
1
@Wilhelm 这可能不是原帖作者想要的,但这正是我所需要的。谢谢。 - Bryson S.

3

只需在 void main() 中键入 clrscr(); 函数。

例如:

void main()
{
clrscr();
printf("Hello m fresher in programming c.");
getch();
}

clrscr();

实现清屏的简单函数。


6
"void main"非常不好。这是一个问题的代码行,出现在C和C++编程语言中。它的正确版本应该是"int main"。 - Shravan
1
大多数编译器会自动纠正,所以它并不是非常糟糕。您正确,不应该使用它。 - 0-0
1
test.c:(.text+0x31): 对 'clrscr' 的引用未定义 collect2: 错误:ld 返回 1 退出状态。包含 stdio.h 和 stdlib.h,不可移植。 - Braden Best

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