problems utilitizing small pauses in c code using nanosleep - c

I am a C beginner and trying this and that.
I want to display a string letter by letter with tiny pauses in between. So my idea was a small pause using sleep or usleep after displaying each char but I read that using nanosleep in your own function makes more sense. So I put my little pauses in a function "msleep" to get microseconds pauses.
I output my string 3 times.
Once in the main(), then in a do-while-loop in a function (fancyOutput) char by char, and eventually in the same function with printf again to check, if it was handled over correctly.
My problem: I expected, that the middle output would work char by char and separated by 100/1000 seconds breaks, but what I experience is a long break before chowing any char and then a fast output if line two and three. It looks like the compiler "realized what I am planning to do and wants to modify the code to be more efficient." So all my pauses seemed to be combined in one long break.
Maybe you remeber the captions in the tv series "x files" - something like that I want to produce.
For sure there are better and more sophisticated ways to archieve what I am going to try but I want to learn and understand what is going on. Can someone help me with that?
I am using codeclocks on a debian-based distro with gcc.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int msleep(long tms);
void fancyOutput(char inputToOutput[]);
int msleep(long tms)
{
struct timespec ts;
int ret;
if (tms < 0)
{
return -1;
}
ts.tv_sec = tms / 1000;
ts.tv_nsec = (tms % 1000) * 1000000;
do
{
// printf("sleeping for %d", ret);
ret = nanosleep(&ts, &ts);
}
while (ret);
return ret;
}
void fancyOutput(char inputToOutput[])
{
int counter = 0;
do
{
printf("%c", inputToOutput[counter]);
msleep(100);
++counter;
}
while (!(inputToOutput[counter]=='\0'));
printf("\n");
printf("%s\n", inputToOutput); // only check, if string was properly handled over to function
}
char output[] = "This string shall appear char by char in the console.";
void main(void)
{
printf("%s\n", output); // only check, if string was properly set and initialized
fancyOutput(output); // here the function above is called to output the string char by cchar with tiny pauses between
}

You are getting problem with buffer.
When you use printf with no \n (new line) C is buffering the display in order to display information block by block (to optimize displaying speed).
Then you need to either add a \n to your printf or add a flush of the stdout.
An other solution will be to use stderr, which got no buffer, but stderr is meant for error not output :)
You can also check setvbuf in order to change the buffering.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int msleep(long tms);
void fancyOutput(char inputToOutput[]);
int msleep(long tms)
{
struct timespec ts;
int ret;
if (tms < 0)
{
return -1;
}
ts.tv_sec = tms / 1000;
ts.tv_nsec = (tms % 1000) * 1000000;
do
{
// printf("sleeping for %d", ret);
ret = nanosleep(&ts, &ts);
}
while (ret);
return ret;
}
void fancyOutput(char inputToOutput[])
{
int counter = 0;
do
{
printf("%c", inputToOutput[counter]);
flush(stdout);
msleep(100);
++counter;
}
while (!(inputToOutput[counter]=='\0'));
printf("\n");
printf("%s\n", inputToOutput); // only check, if string was properly handled over to function
}
char output[] = "This string shall appear char by char in the console.";
void main(void)
{
printf("%s\n", output); // only check, if string was properly set and initialized
fancyOutput(output); // here the function above is called to output the string char by cchar with tiny pauses between
}

So, I tried the solution to place fflush(stdout); directly after the char-output in the loop. It worked as intended.
Summarizing for those with similar problems (guess this also happens with usleep and similar self-made functions):
As I understaood, printf "collects" data in stdout until it "sees" \n, which indicates the end of a line. Then printf "releases" stdout. So in my initial post it "kept" each single char in stdout, made a pause after each char and finally released stdout in one fast output.
So fflush(stdout); after each char output via empties stdout char by char.
Hope it can help others.

Related

Ncurses flickers when using pipes or redirection

Ncurses flickers when using "unix pipes" and "redirection" for input. That is, it draws fine if I input myself but doesn't when using '|' or '<'.
I thought this might be due to getch() delay modes(no delay, half delay and infinite delay). So I explicitly tried setting nodelay(stdscr, FALSE); but as obvious, it didn't solve it.
This is the minimal working code :
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
/* Default assumptions */
#define BUFSIZE 100
#define SELINDICATOR ">>> "
#define MAXITEMS LINES /* Decides how many items are shown at a time. By default, it's (number of rows - 1) */
/* Declarations */
static void draw(char **data, short index, short selected);
static void handleInput(short *selected, short index);
int main(int argc, char *argv[]) {
char buf[BUFSIZE], **data;
short index = 0, selected = 1;
size_t curSize = 0;
/* Get the entries */
while(fgets(buf, BUFSIZE, stdin)) {
if(!(data = realloc(data, (curSize += sizeof(char *))))) {
fprintf(stderr, "error reallocating memory!\n");
exit(1);
}
if(!(data[index] = malloc(BUFSIZE))) {
fprintf(stderr, "error reallocating memory!\n");
exit(1);
}
strcpy(data[index], buf);
index++;
}
/* Start nCurses */
initscr();
noecho();
nodelay(stdscr, FALSE); // just tryin' it out if it works
while(1) {
draw(data, index, selected);
handleInput(&selected, index);
}
/* Quit nCurses */
endwin();
/* Free allocated memories */
for(short i = 0; i < index; i++)
free(data[i]);
free(data);
return 0;
}
void
draw(char **data, short index, short selected) {
static short posX = strlen(SELINDICATOR), posY; /* posY doesn't need to be static but it makes no difference and looks cleaner */
/* Clear old garbage */
clear();
posY = 0;
/* Draw line echoing inputs */
mvaddch(posY, 0, '>');
posY++;
/* Draw the entries */
for(short i = 0; posY < COLS && i < index; i++) {
if(posY == selected) {
mvprintw(posY, 0, SELINDICATOR);
}
mvprintw(posY, posX, "%s", data[i]);
refresh();
posY++;
}
/* Make the output visible */
refresh();
}
void
handleInput(short *selected, short numOfEntries) {
int input = getch();
/* A whole bunch of other stuff........ */
endwin();
exit(0);
}
Much thanks for your efforts!
Ncurses is designed and built as a tool for providing an interactive user interface. To the extent that it reads input from from the standard input (as opposed to directly from the terminal), it is possible for an ncurses-based program to have its input redirected from a file or pipe, but it's unclear why it would be important to actually display the UI in that case. If doing so causes unwanted visual effects then the easiest mitigation might be to disable the UI in that case.
In the program presented in the question, it appears that displaying the UI is cleanly separated from reading and processing input, and that reading input relies only minimally on ncurses. It should be very straightforward to modify such a program to enable it to switch between UI and no-UI modes, and my recommendation is that you do so. To that end, you may find the isatty() function useful for determining whether the standard input (and / or standard output) is a terminal.
The example is missing something, since this function
void
handleInput(short *selected, short numOfEntries) {
int input = getch();
/* A whole bunch of other stuff........ */
endwin();
exit(0);
}
will simply exit after running once. That leaves a lot of possibilities, the most likely being that you're running this program a lot of times, causing it to initialize the screen (and on a lot of terminals, switching to/from the alternate screen). That'll flicker every time...

c does not follow the program operation procedure

summary : system("clear"); isn't working well.
I'm using gcc, ubuntu 18.04 LTS version for c programming.
what I intended was "read each words and print from two text files. After finish read file, delay 3 seconds and erase terminal"
so I was make two text files, and using system("clear"); to erase terminal.
here is whole code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void printFiles(char *file1,char *file2,char *change1, char *change2){
FILE *f;
char *text = malloc(sizeof(char)*100);
f=fopen(file1,"r");
system("clear");
//while(!feof(f)){
while(EOF!=fscanf(f,"%s",text)){
//fscanf(f,"%s", text);
printf("%s ",text);
//usleep(20000);
}
//sleep(3);
fclose(f);
printf("\n");
//all comment problems are appear here. and if I give delay, such as usleep() or sleep, delay also appear here. Not appear each wrote part.
f=fopen(file2,"r");
//while(!feof(f)){
while(EOF!=fscanf(f,"%s",text)){
if(strcmp(text,"**,")==0){
strcpy(text,change1);
strcat(text,",");
}
else if(strcmp(text,"**")==0){
strcpy(text,change1);
}
else if(strcmp(text,"##.")==0){
strcpy(text,change2);
strcat(text,".");
}
else if(strcmp(text,"##,")==0){
strcpy(text,change2);
strcat(text,",");
}
printf("%s ",text);
//usleep(200000);
}
fclose(f);
free(text);
sleep(3); //here is problem. This part works in the above commented part "//all comment problems are appear here."
system("clear"); //here is problem. This part works in the above commented part "//all comment problems are appear here."
}
int main(){
char file1[100] = "./file1.txt";
char file2[100] = "./file2.txt";
char change1[100]="text1";
char change2[100]="text2";
printFiles(file1,file2,change1,change2);
return 0;
}
I'm very sorry, files and variables names are changed because of policy. Also, file contents also can not upload.
I can't find which part makes break Procedure-oriented programming. I think that was compiler error, because using one file read and system(clear); works well.
I also make two point variables, such as 'FILE *f1; FILE *f2; f1=fopen(file1); f2=fopen(file2)...`, but same result occur.
Is it compiler error? If it is, what should I do for fix these problem? Thanks.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void printFiles(char *file1,char *file2,char *change1, char *change2){
FILE *f;
char *text = malloc(sizeof(char)*100);
f=fopen(file1,"r");
system("clear");
//while(!feof(f)){
while(EOF!=fscanf(f,"%s",text)){
//fscanf(f,"%s", text);
printf("%s ",text);
fflush(stdout);
//usleep(20000);
}
//sleep(3);
fclose(f);
printf("\n");
//all comment problems are appear here. and if I give delay, such as usleep() or sleep, delay also appear here. Not appear each wrote part.
f=fopen(file2,"r");
//while(!feof(f)){
while(EOF!=fscanf(f,"%s",text)){
if(strcmp(text,"**,")==0){
strcpy(text,change1);
strcat(text,",");
}
else if(strcmp(text,"**")==0){
strcpy(text,change1);
}
else if(strcmp(text,"##.")==0){
strcpy(text,change2);
strcat(text,".");
}
else if(strcmp(text,"##,")==0){
strcpy(text,change2);
strcat(text,",");
}
printf("%s ",text);
fflush(stdout);// The answer.
//usleep(200000);
}
fclose(f);
free(text);
sleep(3); //here is problem. This part works in the above commented part "//all comment problems are appear here."
system("clear"); //here is problem. This part works in the above commented part "//all comment problems are appear here."
}
int main(){
char file1[100] = "./file1.txt";
char file2[100] = "./file2.txt";
char change1[100]="text1";
char change2[100]="text2";
printFiles(file1,file2,change1,change2);
return 0;
}
Hint for
That's probably just buffering. Do fflush(stdout); before you sleep. – melpomene
Thanks.
You can try this solution for delay.
#include <time.h>
#include <stdio.h>
void delay(double seconds)
{
const time_t start = time(NULL);
time_t current;
do
{
time(&current);
} while(difftime(current, start) < seconds);
}
int main(void)
{
printf("Just waiting...\n");
delay(3);
printf("...oh man, waiting for so long...\n");
return 0;
}
Following solution is pretty quite the same of previous one but with a clear terminal solution.
#include <time.h>
#include <stdio.h>
#ifdef _WIN32
#define CLEAR_SCREEN system ("cls");
#else
#define CLEAR_SCREEN puts("\x1b[H\x1b[2J");
#endif
void delay(double seconds)
{
const time_t start = time(NULL);
time_t current;
do
{
time(&current);
} while(difftime(current, start) < seconds);
}
int main(void)
{
printf("Just waiting...\n");
delay(2); //seconds
printf("...oh man, waiting for so long...\n");
delay(1);
CLEAR_SCREEN
return 0;
}

How to make console output fixed in place

My LAME (v3.99.5) outputs progress in console by moving up x lines in the console and overwriting the previous lines. It's pretty cool.
I've read in a different post that such behavior for a single line can be achieved with a mere "\r" instead of "\n" - although the post was for Ruby, it seems to be the same for C on my system at least:
#include <stdio.h>
#include <time.h>
int main() {
time_t t;
time_t t2;
time(&t);
t2 = t;
printf("%u\r", (unsigned int)t);
fflush(stdout);
while (1) {
if (t2 - t > 0) {
time(&t);
printf("%u\r", (unsigned int)t);
fflush(stdout);
}
time(&t2);
}
return 0;
}
The post further suggests a curses library can be used to make the same behavior multi-line.
What would be a boilerplate example of such code in C?
According to http://falsinsoft.blogspot.com/2014/05/set-console-cursor-position-in-windows.html
Windows:
void SetCursorPos(int XPos, int YPos)
{
COORD Coord;
Coord.X = XPos;
Coord.Y = YPos;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Coord);
}
Linux:
void SetCursorPos(int XPos, int YPos)
{
printf("\033[%d;%dH", YPos+1, XPos+1);
}
You can use something like this:
/!\ Warning: If you stop your curses program without call endwin() before, the terminal used to launch the program will have a very strange behavior.
include <curses.h>
int main(int argc, char *argv[])
{
// init curses
Xinitscr(argc, argv);
// init time
time_t t = 0, t2;
time(&t2);
// main loop
while (1) {
if (t2 - t > 0)
{
time(&t);
clear();
mvprintw(1,1, "%u", (unsigned int)t);
refresh();
}
time(&t2);
}
// end curses mode
// warning: if you do not call this at the end of your program,
// your terminal won't be usable.
endwin();
return 0;
}
The example shown by #purplepsycho has some issues, addressed in this revision (works with "any" X/Open Curses implementation):
#include <curses.h>
int main(int argc, char *argv[])
{
filter();
initscr();
// init time
time_t t = 0, t2;
time(&t2);
// main loop
while (1) {
if (t2 - t > 0)
{
time(&t);
erase();
mvprintw(1,1, "%u", (unsigned int)t);
refresh();
}
time(&t2);
}
endwin();
return 0;
}
That is:
use initscr for initializing curses (PDCurses provides a non-standard function Xinitscr which is not what OP had in mind: it certainly is not often used).
use erase rather than clear (to avoid screen-flicker):
The clear and wclear routines are like erase and werase,
but they also call clearok, so that the screen is cleared
completely on the next call to wrefresh for that window
and repainted from scratch.
use filter to keep the output on a single line. If your terminal switches to the alternate screen, the screen will appear to be cleared. There is a workaround available with ncurses (see filter.c in ncurses-examples).
Better than erase() would be wclrtoeol(), called after the mvprintw.

C sleep method obstructs output to console

I have a C program, where I just wanted to test if I could reproduce a console spinner used in npm install while it installs a module. This particular spinner simply spins in this order:
|
/
-
\
on the same space, so I use the following program:
#include <stdio.h>
int main() {
char sequence[4] = "|/-\\";
while(1) {
for(int i = 0; i < 4; i++) {
// \b is to make the character print to the same space
printf("\b%c", sequence[i]);
// now I want to delay here ~0.25s
}
}
}
So I found a way to make it rest for that long from <time.h> documentation and made this program:
#include <stdio.h>
#include <time.h>
void sleep(double seconds) {
clock_t then;
then = clock();
while(((double)(clock() - then) / CLOCKS_PER_SEC) < seconds); //do nothing
}
int main() {
char sequence[4] = "|/-\\";
while(1) {
for(int i = 0; i < 4; i++) {
printf("\b%c", sequence[i]);
sleep(0.25);
}
}
}
But now nothing prints to the console. Does anyone know how I can go about producing the behavior I want?
EDIT According to what appears to be popular opinion, I've updated my code above to be the following:
#include <stdio.h>
#include <unistd.h>
int main() {
char sequence[4] = "|/-\\";
while(1) {
for(int i = 0; i < 4; i++) {
printf("\b%c", sequence[i]);
/* fflush(stdout); */
// commented out to show same behavior as program above
usleep(250000); // 250000 microseconds = 0.25 seconds
}
}
}
You will need to flush after you wrote to the console. Otherwise, the program will buffer your output:
fflush(stdout);
Things do get printed to console, it's just does not get flushed. Add fflush(stdout) to see the results, or set the console in an unbuffered mode by calling setbuf:
setbuf(stdout, NULL);
A bigger problem with your code is that your sleep method runs a busy loop, which burns CPU cycles for no good reason. A better alternative would be to call usleep, which takes the number of microseconds:
usleep(25000);
The sleep function isn't really your problem. The issue is that the output is buffered. The simplest thing to do will be to research ncurses.
For now:
fflush(stdout);

Why isn't my write method initialised?

I have been trying to write words that are given by the user in the command shell,but for some reason my program instantly quits after the read() function,so the text in main() :"in main2\n" is never even written. I have been trying to locate my problem for about an hour now and can't seem to find it.
# include <stdio.h>
void write_zin(const char* zin,int length_zin){
const char * runner =zin;
printf("out of loop\n");
while(runner!=(runner+length_zin)){
printf("%c",*runner);
runner++;
}
}
void read(char* zin,int NUMBER_LETTERS,int NUMBER_WORDS){
int i ;
char woord[NUMBER_LETTERS+1];
zin[0]='\0';
for(i =0;i<NUMBER_WORDS;i++){
printf("Give a word with %i letters\n",NUMBER_LETTERS);
scanf("%s",woord);
strcat(zin,woord);
strcat(zin,'\0');
}
strcat(zin,'\0');
}
int main(){
const int NUMBER_LETTERS = 5;
const int NUMBER_WORDS = 2;
char zin[(NUMBER_LETTERS+1)*NUMBER_WORDS];
printf("in main 1\n");
read(zin,NUMBER_LETTERS,NUMBER_WORDS);
printf("in main 2\n");
write_zin(zin,(NUMBER_LETTERS+1)*NUMBER_WORDS);
printf("in main3\n");
return 0;
}
There are a couple errors in your code:
Function void read(char* zin,int NUMBER_LETTERS,int NUMBER_WORDS)
If you concatenate words separated by '\0' you will end having just one string, because every string function will stop at the first '\0' and will not process further characters. So you cannot use strcat(zin,'\0');
If you want to mark the separation between strings use another special character as '\n' The final function will be:
void read(char* zin,int NUMBER_LETTERS,int NUMBER_WORDS){
int i ;
char woord[NUMBER_LETTERS+1];
for(i =0;i<NUMBER_WORDS;i++){
printf("Give a word with %i letters\n",NUMBER_LETTERS);
scanf("%s",woord);
strcat(zin,woord);
}
}
2. Function void write_zin(const char* zin,int length_zin)
You cannot ever change the condition of a loop inside a loop. That is what you are doing, because runner is always changing inside the loop, and in addition it is part of your condition.
while(runner!=(runner+length_zin)){
printf("%c",*runner);
runner++;
}
The final function is:
void write_zin(const char* zin,int length_zin){
const char * runner =zin;
printf("out of loop");
while(*runner){
printf("'%c'",*runner);
runner++;
}
}

Resources