How to Build a Real-Time Linux Progress Bar in C Using \r and Buffer Flushing
This tutorial explains the difference between \r and \n, line buffering, and how to use fflush and usleep to create a live updating progress bar and countdown timer in a Linux C program, complete with multi‑file implementation and sample code.
Understanding \r and \n
In C, characters are divided into printable characters and control characters. \r is a carriage return that moves the cursor to the beginning of the current line, while \n is a newline that starts a new line. Together they produce the typical line break.
When output is line‑buffered, the buffer is flushed automatically only when a newline is encountered.
Line Buffering and Flushing
Output is first stored in a buffer. If the buffer is not flushed, the text remains invisible until the program terminates or fflush is called. In line‑buffered mode, encountering \n triggers an automatic flush.
Example Programs
#include <stdio.h>
int main(){
printf("hello xxx");
sleep(3);
return 0;
}Result: the cursor stays at the line start and the string is not shown until the program exits.
#include <stdio.h>
int main(){
printf("hello xxx
");
sleep(3);
return 0;
}Result: the string appears immediately because the newline flushes the buffer.
#include <stdio.h>
int main(){
printf("hello xxx\r");
sleep(3);
return 0;
}Result: nothing is displayed; the cursor stays at the start of the line and the shell prompt overwrites the text after the program ends.
Answers to Common Questions
Code 1 does not execute sleep before printf; the functions run in order, but the output is buffered until program termination.
Adding \n in Code 2 forces a line‑buffer flush, so the text appears immediately.
In Code 3, \r returns the cursor to the line start; without a flush the text never becomes visible, and the shell prompt overwrites it.
Using fflush for Real‑Time Updates
Calling fflush(stdout) forces the buffer to be written to the terminal. This allows immediate display of text even when only \r is used.
Countdown Example
#include <stdio.h>
#include <unistd.h>
int main(){
int i = 10;
for(; i >= 0; i--){
printf("%2d\r", i);
fflush(stdout);
sleep(1);
}
printf("
");
return 0;
}This prints numbers from 10 down to 0 on the same line, updating each second.
Progress Bar Design
The bar consists of two brackets, an expanding = sequence, a > pointer, a percentage display, and a rotating cursor (| / - \). The bar updates in place using \r and fflush.
Multi‑File Implementation
proc.h: declares
void process(); proc.c: contains the progress‑bar logic. test.c (or main.c): calls
process(); Makefile: builds the program from the three source files.
proc.h
#pragma once
#include <stdio.h>
extern void process();proc.c
#include "proc.h"
#include <string.h>
#include <unistd.h>
#define SIZE 102
#define STYLE '='
#define FLAG '>'
void process(){
const char* str = "|/-\\";
char bar[SIZE];
memset(bar, '\0', sizeof(bar));
int i = 0;
while(i <= 100){
printf("[%-100s][%d%%][%c]\r", bar, i, str[i % 4]);
fflush(stdout);
bar[i++] = STYLE;
if(i != 100) bar[i] = FLAG;
usleep(100000);
}
printf("
");
}test.c
#include "proc.h"
int main(){
process();
return 0;
}Compiling and running the program displays a live updating progress bar with percentage and rotating cursor, demonstrating the use of \r, fflush, and line buffering for real‑time terminal output.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
