Quantcast
Channel: User Peter - Reinstate Monica - Stack Overflow
Viewing all articles
Browse latest Browse all 223

Answer by Peter - Reinstate Monica for How can I delete the last digit of a line I printed with cout in c++?

$
0
0

Terminal control — how to position the cursor, change colors or fonts etc. — is not part of the C++ language (and was not part of C either). However, there are a few things which work virtually everywhere because they are literally a hundred years old when all typing and printing was performed on machines that were pimped typewriters: They had a carriage with a platen (the rubber roller) that held and transported the paper. A letter would always land at the same position relative to the machine; in order to have it land on different positions on the paper, the paper had to be moved. Horizontal movement was performed by the carriage which was able to move left and right far enough that the printing would occur anywhere between the left and right edge of the paper; and the platen would roll up (or, when desired, down) to move the printing position down (or, if desired, up).

This model of changing printing position — horizontally and vertically — has been preserved into modern times. On a manual typewriter, the two are typically performed at the same time: A line is finished, and in order to start a new line you must do both, advance the paper upwards and reposition the carriage to the right, which was done with one quick operation of a long lever. But if needed, the carriage could be moved separately, without rotating the platen and advancing to the next line. The platen could also be moved separately in order to advance to a new line, which always needed to be done to insert a new sheet of paper.

In teletypes, these two operations were triggered by control codes aptly named carriage return respectively line feed, or newline. In the 1960s, the codes for these operations were standardized as part of ASCII as 13 (carriage return) and 10 (newline).

In the second half of the 20th century, electronic terminals increasingly replaced paper-based teletypes; but many of them were able to understand ASCII, including the control characters, which is why a program using this smallest common denominator works on the vast majority of output devices.

The better terminals could perform much more elaborate cursor movements, but every company had their own way of controlling those, typically by sending proprietary "control sequences". In the 1970s, ANSI started to standardize control sequences for a subset of these capabilities which, again, are today supported by many terminals. I'll use two of those below. The following program has two parts which differ only in the cursor positioning: The first one uses ASCII carriage return, the second one uses ANSI sequences telling the terminal to memorize and subsequently restore the cursor position. Both methods work in a Windows Console and in msys2 in a mintty terminal, compiled with a x86_64-pc-msys gcc.

I hope the random and thread code is not a distraction; the output is what counts here.

#include <iostream>#include <iomanip> // setw()#include <random>#include <thread> // just so that we can wait and see something// Number of numbers, and if we want to see 10 outputs, we have the // following interval:enum { NUM_COUNT = 1'000'000, PRINT_INTERVAL = NUM_COUNT/10 };// Maximum number value, // Adjust the width with the max (could use log but overkill).enum { MAX_NUM = 100'000, PRINT_WIDTH = 6 };using namespace std;int main(){    // the random number code is from    // https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution    std::random_device rd;  // a seed source for the random number engine    std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd()    std::uniform_int_distribution<> distrib(1, MAX_NUM);    cout << "Carriage return method "<< "(works virtually everywhere, including teletypes) : \n";    cout << std::left; // number is left-aligned in "print box", looks nicer    for (int i = 0; i < NUM_COUNT; i++)    {        auto num = distrib(gen);        if (i % PRINT_INTERVAL == 0)        {            // '\r' moves the write position to the beginning of the line, but            // does not advance the position to the next line. Subsequent output            // will start to overwrite the current line, which is what you want.            // (Ideally, you would like to go back only             // to the end of "Printed numbers:",            // but that is not possible in a system independent manner.)            cout << "\r";            // setw() lets the next output operation            // print spaces if the number has fewer digits so that             // previous longer numbers are overwritten.            // flush to make sure the terminal sees it            cout << "Printed numbers: " << setw(PRINT_WIDTH) << num << flush;            this_thread::sleep_for(500ms); // so that we can see something        }    }    cout << endl; // only one linefeed at the end.    //-----------------------------------------------------------------------    // second method for Windows Console    cout << "ANSI terminal sequence method (works on most terminals):\n";    // print that only once!    cout << "Printed numbers: " << flush;   // flush: Make sure the terminal sees it.     // Let the terminal memorize the cursor position     // *after* "Printed numbers: ".    cout << '\033'<< "[s";          for (int i = 0; i < NUM_COUNT; i++)    {        auto num = distrib(gen);        if (i % PRINT_INTERVAL == 0)        {            // Tell the terminal to move the cursor to the             // memorized position. It is always the same.            cout << '\033'<< "[u" << flush;            cout << setw(PRINT_WIDTH) << num << flush;            this_thread::sleep_for(500ms);        }    }    cout << endl; // only one linefeed at the end.}

Viewing all articles
Browse latest Browse all 223

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>