0

I am making a loading type function so what I wanted to do was to halt my program for a few seconds and then resume the execution inside a loop to make it look like a loading process. Looking up on web I found that I can use std::this_thread::sleep_for() to achieve this (I am doing this on linux). The problem I am facing is that I am unable to make it work with \r or any other way to overwrite the last outputted percentage as the program freezes as soon as I do it, however it works perfectly with \n and it's all confusing to understand why it'd work with a newline sequence but not with \r.

I am posting the sample code below, can someone tell me what am I doing wrong?

#include<iostream>
#include<chrono>
#include<thread>

int main()
{
    for (int i = 0; i<= 100; i++)
    {
        std::cout << "\r" << i;
        std::this_thread::sleep_for(std::chrono::seconds(rand()%3));
    }
    return 0;
}

I am kinda new to this topic and after some digging I found out that I am messing with the threads. But still not sure why this behavior is happening.

Jiaar
  • 60
  • 6
  • 3
    Can you get away with just flushing the stream? cout is buffered. See https://stackoverflow.com/questions/22026751/c-force-stdcout-flush-print-to-screen – Captain Giraffe Jan 09 '22 at 17:16
  • 10
    The program is not frozen. If you set a breakpoint, you'll see that the `std::cout << "\r" << i;` does run every few seconds. The problem is that you're not flushing the output, so the results are still in the buffer waiting to be printed. It works with `\n` because there is an automatic flush when a `\n` is printed. But `\r` does not have this special property. – Raymond Chen Jan 09 '22 at 17:17
  • Thank you so much for the replies, adding std::flush did the job but now what i am unable to understand is why is it behaving like that? i mean the first time i am calling cout with `\r` it should still print something right? but it's not printing anything at all if i am not flushing the stream. Is it something to do with the `std::this_thread::sleep_for` or just the `cout` function? Am i missing something here? Maybe an execution chart or something similar would be useful or some further elaboration on the topic. and thanks again for figuring this out for me. :) – Jiaar Jan 09 '22 at 17:25
  • 3
    [What is meant by stream buffering?](https://stackoverflow.com/q/23298717/2752075) – HolyBlackCat Jan 09 '22 at 17:26
  • @RaymondChen Please move your comment to an answer. – Soleil Jan 09 '22 at 17:27

1 Answers1

1

This works fine on my machine (Windows 10):

#include <iostream>
#include <chrono>
#include <thread>
#include <cstdlib>
#include <ctime>


int main( )
{
    std::srand( std::time( 0 ) );

    for ( std::size_t i { }; i < 100; ++i )
    {
        std::cout << '\r' << i;
        std::this_thread::sleep_for( std::chrono::seconds( std::rand( ) % 3 ) );
    }
}

I suggest that you write '\r' instead of "\r" cause here you only want to print \r character and "\r" actually prints two characters (\r and \0).
Also, it's better to seed rand using srand before calling it.

However, it may not work as expected in some environments so you may need to flush the output sequence like below:

std::cout << '\r' << i << std::flush;

or like this:

std::cout << '\r' << i;
std::cout.flush( );

These are equivalent.

For more info about flush see here.

digito_evo
  • 3,216
  • 2
  • 14
  • 42
  • Even this one is not working without flushing the `cout`. I even tried it just now on some online compilers as well as on linux g++. As soon as I add the `std::flush` it works fine otherwise it stops. The execution flow of the program is confusing me now. Also what you said about seeding using `srand` I'll surely try it out :) It's a good advice. – Jiaar Jan 09 '22 at 17:41
  • @Jiaar Which line did you add `std::flush` to? – digito_evo Jan 09 '22 at 17:46
  • Instead of `std::cout << '\r' << i;` in for loop, I used `std::cout << '\r' << i << std::flush;` and it started working as expected. I figured that'd be the right place to add it as Its the same `cout` in which I was using `\n` i.e. I was using `std::cout << '\n' << i;` and it was all working fine but I was getting new line and that was not intended for me. – Jiaar Jan 09 '22 at 17:50
  • @Jiaar See the updated answer. – digito_evo Jan 09 '22 at 18:22
  • 2
    `"\r" actually prints two characters (\r and \0)` is false. `std::cout << '\r'` and `std::cout << "\r"` do exactly the same thing. – n. m. could be an AI Jan 09 '22 at 18:23
  • @n. 1.8e9-where's-my-share m. "\r" is a buffer that contains two characters. I may be wrong on the printing side of it though. – digito_evo Jan 09 '22 at 18:25
  • 1
    *"\r" is a buffer that contains two characters* Indeed, it is. *I may be wrong on the printing side of it though* Indeed, you are. – n. m. could be an AI Jan 09 '22 at 18:30