Как очистить экран консоли в C?

Есть ли «правильный» способ очистить окно консоли в C, помимо использования system("cls")?


person devurs    schedule 27.02.2010    source источник
comment
cplusplus.com/forum/articles/10515 содержит некоторые коды. Хотя он не переносим как для систем Windows, так и для POSIX, он может быть полезен всем, кто будет читать этот вопрос в будущем.   -  person Aseem Bansal    schedule 22.06.2013
comment
Также здесь cplusplus.com/articles/4z18T05o   -  person Marcello Romani    schedule 27.06.2013


Ответы (13)


Ну, C не понимает концепцию экрана. Таким образом, любой код не будет переносимым. Можете взглянуть на conio.h или curses, в соответствии с вашими потребностями?

Переносимость является проблемой, независимо от того, какая библиотека используется.

person Tom    schedule 27.02.2010
comment
Я поставил вам +1, прежде чем прочитать вашу строку о conio.h. Обратите внимание, что это тоже очень непереносимо. - person Derrick Turk; 27.02.2010
comment
Я не уверен насчет conio.h, но похоже, что curses заботится о графическом интерфейсе более комплексно, чем я себе представлял. Я должен изучить это. Спасибо за предложение! - person devurs; 01.03.2010

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

Эта функция будет работать на терминалах ANSI, требует POSIX. Я предполагаю, что есть версия, которая также может работать на консоли окна, поскольку она также поддерживает escape-последовательности 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} .

person Avinash Katiyar    schedule 05.10.2011
comment
Просто чтобы вы знали, FWIW, эта последовательность не работала для меня в консоли Windows cmd.exe. - person dodgy_coder; 09.04.2013
comment
@anon: Это если для UNIX. Вы делаете ответ для DOS? - person user2284570; 23.03.2015
comment
Как это требует POSIX? Я не верю, что эти управляющие последовательности указаны в стандарте POSIX. - person Keith Thompson; 01.06.2015
comment
Это не работает для меня. Что работает для меня, так это старая добрая "\e[2J". Я знаю, что прошло около четырех лет, но... Не хочешь объяснить разницу? Или что должен делать "\e[1;1H"? - person Braden Best; 19.09.2015
comment
Этот код отлично работает в CMD Windows, по крайней мере, в Win10. - person Fund Monica's Lawsuit; 13.05.2016
comment
Используя это, я не получил ошибок совместимости с ISO: \033[2J\033[1;1H - person Geremia; 21.01.2017
comment
Командная строка Windows (от Windows 98 до Windows 7) не поддерживает escape-символы ANSI. Похоже, что они работают в Windows 10 и, предположительно, в Windows 8, как отмечает QPaysTaxes. - person MD XF; 27.09.2017
comment
Нит: Не используйте printf(string);, вместо этого используйте puts(string);. У первого может быть UB, если string содержит знак процента (хотя здесь это не так, я рекомендую сделать это привычкой). - person Arne Vogel; 20.06.2018
comment
Почему это регулярное выражение работает? Может кто-нибудь опубликовать ссылку, которая объясняет это? - person Pranav Chaudhary; 10.08.2019
comment
\033[x;yH переместит курсор в строку x столбца y. Если x равно 1, его можно опустить: \033[;yH. en.wikipedia.org/wiki/ - person Dosisod; 03.06.2020

Для переносимости попробуйте следующее:

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

Затем просто позвоните clrscr(). В Windows он будет использовать код clrscr() conio.h, а в Linux — управляющие коды ANSI.

Если вы действительно хотите сделать это "правильно", вы можете устранить посредников (conio, printf и т. д.) и сделать это только с помощью низкоуровневых системных инструментов (подготовьтесь к массивному дампу кода). ):

#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
person MD XF    schedule 28.02.2017
comment
На самом деле это очень приятно. +1 за указание переносимого пути с использованием экранов ANSI с ужасным, но полезным clrscr() из conio.h. - person Manoel Vilela; 30.08.2017
comment
Просто для того, чтобы сказать: clrscr() недоступен в реализации conio.h компилятора mingw - person Manoel Vilela; 21.09.2017

Обходной путь, протестированный в Windows (cmd.exe), Linux (Bash и zsh) и OS X (zsh):

#include <stdlib.h>

void clrscr()
{
    system("@cls||clear");
}
person Jamesits    schedule 31.10.2015
comment
1- это чудовищно; 2- ОП прямо попросил не использовать его; 3- OP запрашивает команду языка C, а system вызывает команды для других языков (саид, bash, zsh, пакет и т. д.). Еще +1, чтобы попытаться сделать его переносимым. (Я тестировал на debian/linux и win7, даже инвертируя аргументы. @ также не нужен, потому что команда не будет отображаться на экране после запуска) - person DrBeco; 30.11.2015

Используя макросы, вы можете проверить, используете ли вы Windows, Linux, Mac или Unix, и вызвать соответствующую функцию в зависимости от текущей платформы. Что-то вроде следующего:

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

    #if defined(_WIN32) || defined(_WIN64)
        system("cls");
    #endif
}
person nbro    schedule 27.03.2016

Поскольку вы упоминаете cls, похоже, вы имеете в виду окна. Если это так, то в этом элементе базы знаний есть код, который это сделает. Я только что попробовал, и это сработало, когда я вызвал его со следующим кодом:

cls( GetStdHandle( STD_OUTPUT_HANDLE ));
person Mark Wilkins    schedule 27.02.2010
comment
+1 хотя я не спрашивал, но это может быть весьма полезно. И что можно сделать в unix, чтобы «очистить»? - person N 1.1; 27.02.2010
comment
@nvl: у меня дома есть только машины с Windows, и для входа на рабочие машины отсюда требуется около 15 имен пользователей и паролей, поэтому я не могу проверить это прямо сейчас. Но я считаю, что ncurses — это путь для этого (linux.die.net/man/3/ncurses< /а>). - person Mark Wilkins; 27.02.2010
comment
На самом деле я думал о системах на основе Unix, но это помогает для Windows. Спасибо! - person devurs; 01.03.2010
comment
Я получаю non-ISO-standard escape sequence, '\e' при использовании этого с C11. - person Geremia; 21.01.2017

#include <conio.h>

и использовать

clrscr()
person Vivek Sharma    schedule 27.02.2010
comment
Обратите внимание, что это не портативно. - person Billy ONeal; 27.02.2010
comment
И это не в стандарте c. Обратите внимание, что ОП упомянул. Есть ли правильный способ - person Muthu Ganapathy Nathan; 30.08.2011

Для этого нет переносимого C-способа. Хотя различные библиотеки управления курсором, такие как curses, относительно переносимы. conio.h можно переносить между OS/2 DOS и Windows, но не в *nix варианты.

Вся концепция консоли — это концепция, выходящая за рамки стандарта C.

Если вы ищете чистое решение API Win32, в API консоли Windows нет единого вызова для этого. Одним из способов является FillConsoleOutputCharacter достаточно большого количество символов. Или WriteConsoleOutput. Вы можете использовать GetConsoleScreenBufferInfo , чтобы узнать, сколько символов будет достаточно.

Вы также можете создать совершенно новый буфер экрана консоли и сделать его текущим.

person John Knoeller    schedule 28.02.2010

Окна:

system("cls");

Юникс:

system("clear");

Вместо этого вы можете вставлять символы новой строки до тех пор, пока все не будет прокручено. noreferrer">здесь.

При этом вы легко достигаете переносимости.

person gfe    schedule 27.02.2010
comment
ОП прямо сказал, что это НЕ то, что он искал. - person Billy ONeal; 27.02.2010
comment
\n сразу возникает следующая проблема: какое минимальное количество новых строк нужно написать, чтобы все прокручивалось из терминала? - person Premature Optimization; 10.09.2012
comment
@PrematureOptimization Forty quadvigiseptanovatriheptasexgesillion, который у нас не будет ЦП, способных обрабатывать, пока у нас не будет 2048-битного ЦП с библиотекой bitchin bignum. Извините, вам не повезло. Вам просто придется смириться с тем фактом, что люди, которые запускают свою систему, используя сторону Эмпайр-стейт-билдинг в качестве проекционного монитора с полноэкранным терминалом, использующим шрифт 1pt, получат уродливо выглядящий четкий эффект. Это редкий пограничный случай. В противном случае ~ 100 строк должны помочь. (Xterm, использующий шрифт по умолчанию в полноэкранном режиме на мониторе 1080p, имеет высоту всего 74 строки) - person Braden Best; 19.09.2015
comment
@Wilhelm Возможно, это было не то, что искал ОП, но это было ИМЕННО то, что я искал. Спасибо. - person Bryson S.; 23.02.2016


В Windows я сделал ошибку, используя

system("clear")

но это на самом деле для Linux

Тип Windows

system("cls")

без #include conio.h

person Ezekiel Adewale    schedule 20.11.2020

Правильный способ сделать это — использовать функции tput или terminfo для получения свойств терминала, а затем вставлять новые строки в соответствии с размерами.

person Jack    schedule 27.02.2010
comment
Хм?! Предполагая, что вызов terminfo был успешным, а тип терминала является умным (не «немым» или «tty»), тогда вы могли бы также использовать инструкцию очистки экрана terminfo (или termcap) (clear / cl), а не нажимать несколько новых строк , что может быть медленным на больших терминалах X-Window, особенно в сетях. - person mctylr; 28.02.2010

Это должно работать. Затем просто вызовите cls(); всякий раз, когда вы хотите очистить экран.

(используя метод, предложенный ранее.)

#include <stdio.h>
void cls()
{
    int x;
    for ( x = 0; x < 10; x++ ) 
    {
        printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
    }
}
person JD3    schedule 15.10.2013
comment
Для такого решения конструкция цикла (while или for) была бы немного более элегантной. См., например: cprogramming.com/faq/cgi- корзина/ - person lurker; 15.10.2013
comment
Да, я мог бы, я думаю. Но зачем использовать цикл, когда я могу скопировать и вставить для того же эффекта? Потому что копирование и вставка нарушает одно из самых важных правил хорошего программирования: СУХОЕ — не повторяйтесь. - person MofX; 09.02.2015
comment
Я сделал, как вы предложили, и добавил красивую петлю :) - person JD3; 02.03.2015
comment
Это печатает 160 новых строк и оставляет курсор внизу экрана. На самом деле возможно иметь окно выше 160 строк. - person Keith Thompson; 01.06.2015
comment
Поддерживая Кита Томпсона, я получаю уже 159 строк на старом вертикальном мониторе Full HD. В тот момент, когда я обновлюсь до 4k, будет более 160 строк... Общий вывод: Никогда не думайте, что этого будет достаточно во всех случаях. Потому что этого не будет. Всякий раз, когда вы предполагаете это, вы создаете ошибку, которая только и ждет, чтобы случиться. Всегда определяйте свою потребность или выбирайте методы, которые всегда работают правильно. (То же самое с длиной буфера, длиной строки и т. д.) - person cmaster - reinstate monica; 03.03.2020