Function printf() to print backspace problem - c

There are two programs and they get different results, but I don't understand why.
Here is the first:
int main()
{
printf("12345");
fflush(stdout);
printf("\b\b");
fflush(stdout);
return 0;
}
The result is: 123.
Then the second:
int main()
{
printf("12345");
fflush(stdout);
sleep(1);
printf("\b\b");
fflush(stdout);
return 0;
}
but the result is: 12345.
Why does the sleep call make the second result different when I expect a "123" result?
The code was running in the CLion.
and My OS is macOS, if it matters.

Depending on the Terminal, '\b' might "erase" a character or only move the cursor to the left. To have a foolproof solution, use:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
printf("12345");
fflush(stdout);
sleep(1);
printf("\b\b \b\b");
fflush(stdout);
}

Your code first displays "12345" and then displays "123". Without the sleep, the "12345" is displayed for too little time to be visible. With the sleep, you can see the "12345" for about a second before the "4" and "5" are erased.

With the original code (called bs97, compiled from bs97.c), and with my command line prompt Osiris JL:, I get the output:
Osiris JL: bs97
123Osiris JL:
Note that the new prompt has overwritten the 45. You can see that if you add putchar('\n'); after the second fflush(). (I added void to int main(void) to avoid compilation warnings (errors) with my default compilation options.)
Osiris JL: make bs97 && bs97
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes bs97.c -o bs97
12345
Osiris JL:
This time, the 4 and the 5 are still visible.
Simply using backspace does not erase the content that was previously there; it positions the write position on screen back one place, that's all. If you want to erase what was there, you need to output printf("\b \b\b \b") to go back, output a space, and go back again — repeated twice. Or you could use printf("\b\b "), but that would leave the write position after the two spaces; or you could use printf("\b\b \b\b") to leave the write position after the 3. And there are other variations on this theme.
With the second program with the sleep, I get similar behaviour, except that the 12345 is on display while the program sleeps.
I'm testing on a Mac running macOS 10.14 Mojave, using a home-built GCC 8.2.0 or the clang compiler from XCode 10.0.

Related

Sleep function in C (POSIX) breaks my program

This is my program code:
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
void function() {
srand(time(NULL));
while(1) {
int n = rand();
printf("%d ", n);
//sleep(1);
}
}
int main() {
pid_t pid;
pid = fork();
if (pid == 0) {
function();
}
}
With the sleep line commented out (as in the code above) the program works fine (i.e. it prints a bunch of random numbers too fast to even see if they are actually random), but if I remove the comment the program doesn't print anything and exits (not even the first time, before it gets to the sleep), even though it compiles without warnings or errors with or without the comment.
but if I remove the comment the program doesn't print anything and exits
It does not print, but it does not really exit either. It will still be running a process in the background. And that process runs your infinite while loop.
Using your code in p.c:
$ gcc p.c
$ ./a.out
$ ps -A | grep a.out
267282 pts/0 00:00:00 a.out
$ killall a.out
$ killall a.out
a.out: no process found
The problem is that printf does not really print. It only sends data to the output buffer. In order to force the output buffer to be printed, invoke fflush(stdout)
If you're not flushing, then you just rely on the behavior of the terminal you're using. It's very common for terminals to flush when you write a newline character to the output stream. That's one reason why it's preferable to use printf("data\n") instead of printf("\ndata"). See this question for more info: https://softwareengineering.stackexchange.com/q/381711/283695
I'd suspect that if you just leave your program running, it will eventually print. It makes sense that it has a finite buffer and that it flushes when it gets full. But that's just an (educated) guess, and it depends on your terminal.
it prints a bunch of random numbers too fast to even see if they are actually random
How do you see if a sequence of numbers is random? (Playing the devils advocate)
I believe you need to call fflush(3) from time to time. See also setvbuf(3) and stdio(3) and sysconf(3).
I guess that if you coded:
while(1) {
int n = rand();
printf("%d ", n);
if (n % 4 == 0)
fflush(NULL);
sleep(1);
}
The behavior of your program might be more user friendly. The buffer of stdout might have several dozens of kilobytes at least.
BTW, I could be wrong. Check by reading a recent C draft standard (perhaps n2176).
At the very least, see this C reference website then syscalls(2), fork(2) and sleep(3).
You need to call waitpid(2) or a similar function for every successful fork(2).
If on Linux, read also Advanced Linux Programming and use both strace(1) and gdb(1) to understand the behavior of your program. With GCC don't forget to compile it as gcc -Wall -Wextra -g to get all warnings and debug info.
Consider also using the Clang static analyzer.

Why the charater "%" is printed after performing a printf without "\n"?

Here is my simple c code. Can anyone tell me why it gives me this output?
I am coding on an arch linux 4.15.1-2-ARCH machine with the gcc compiler (version: 7.3.0)
I compile with: gcc --std=c99 -Wall --pedantic client.c -o client
I have the following code:
#include <stdio.h>
int main(void) {
printf("Test.");
return 0;
}
But it get the following Output:
Test.%
I don't know where the % is comming from. Would be great if someone can give me a hint.
Your printf string doesn't contain a newline character. As a result, whatever string your shell normally prints as a prompt will appear immediately after what your program prints.
Running on my machine:
$ ./x1
Test.$
My prompt is "$", so that's what appears after the string
Adding \n, which is the escape sequence for a newline, to your string will make your prompt appear on the following line:
printf("Test.\n");
Output:
$ ./x1
Test.
$
Try:
printf("Test.\n");
The word Test. printed by your program probably joined with the first character of your terminal prompt. Adding a \n will print a new line character, so your terminal prompt will be written on the next line when your program exits.

ncurses.h, wprintw doesn't work, even after refresh

I'm using the library ncurses, and when I try to call wprintw(), and then do a wrefresh on the right window, it doesn't print anything.
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
int main()
{
WINDOW *winTest; //The window
int rows, cols; //Rows and colums in the terminal
initscr(); //Starting NCurses
raw(); //Calling 'getch()' doesn't wait for '\n'
noecho(); //Doesn't print what's written by user
curs_set(0); //Doesn't display the cursor
getmaxyx(stdscr, rows, cols); //How many rows and colums in stdscr (the terminal)
winTest = newwin(10, 10, rows/2, cols/2); //Creates a square WINDOW at the center of the terminal
mvwprintw(winTest, 0, 0, "Test"); //Prints "Test" on the created window
wrefresh(winTest); //Refreshes so what's done is displayed
getch(); //Pause
delwin(winTest); //Free the memory for winTest
endwin(); //Ends NCurses
return 0;
}
When I execute this, nothing is displayed.
I'm on Ubuntu 14.04 LTS, I compile with gcc:
gcc -g -Wall -Werror -Wpedantic -Wextra -Wformat -o test.exe test.c -lncurses
and I execute in the gnome-terminal.
As explained here, you should replace:
getch();
by:
wgetch(winTest);
I replaced the second pause, getch() with my own pause function: scanf("%*s"); and then it displayed test in the middle like it was supposed to. I think what was happening is it went through both pauses in one go so that you never saw the "Test" because it was deleted as fast as it was created. – Tony Ruth
Thanks to Tony Ruth, who answered my question. Even if I still don't understand why getch() erases what's written, replacing it with scanf("%*s") works fine !
PS: Don't know how to tell this issue is solved :/
EDIT : You can also call 'wgetch(aWindow)' on whatever window, and every windows will be corectly displayed :) (Thank to Ruud, who told it)

How do I get GCC to work?

I am using Vim as my editor and GCC as my compiler, but it’s not working quite right. Let‘s say I am making a basic program to determine if a number is odd or even. Here is my code:
#include <stdio.h>
int main(int argc, char argv[])
{
int i;
printf("Enter a number: ");
scanf("%d\n", &i);
printf("%d\n", i);
if(i % 2 == 0)
{
printf("Your number is even.\n");
}
else if(i % 2 != 0)
{
printf("Your number is odd.\n");
}
else
{
printf("Invalid input.\n");
}
getchar();
return 0;
}
I'm not sure if I am programming this wrong, or gcc is just not a good compiler, or whatever. I am running linux, which I dual boot with windows. Now I press ctrl-d to stop the process, and only then does it print me back my number, and tell if it is odd or even. It isn't just this one, a lot of other programs with similar formats seem to do this to.
~ $ ./test
Enter a number: 45
45 //I press enter, nothing happends. Ctrl-d
Your number is even. //ctrl-d again
~ $
So what I'm asking is, is there a way to program it so that I don't have to quit the program in order for it to work, or is there another compiler that wouldn't have this problem? I am running on Ubuntu 14.04 dual booted with Windows 8.1.
\n in the format for scanf means "read until hit into non-whitespace character and then ignore them". Remove it and make the format for reading "%d".
to get gcc to work from vim,
goto the vim command prompt
shell gcc <and all needed parameters>
Or open another command window
set it to the same directory as the program being edited
gcc <and all needed parameters>
in general, try to make the compile step separate from the link step. I.E. to compile:
gcc -c <mySource.c> -Wall -Wextra -pedantic -std=c99 -o mySource.o
if any header files, other than those in the default 'include' path then add
-I<pathToHeaderFile>
which is often in the same directory so would be:
-I.
then link with:
gcc mySource.o -o mySource
You can add the -ggdb parameter to both lines if you plan on doing any debugging.
to add any library directories then on the link step append
-L<pathToLibrary>
to add any libraries then on the link step append, after any library parameters:
-l<shortLibName>
The initialization file for vim can contain the necessary info to invoke gcc by some keystroke combination, but I'm not totally familiar with the details.

printf doesn't work, even with newline and fflush()

I'm compiling the below C code with gcc. No errors are thrown during compilation or at runtime. I ran through the code with gdb, and the answer given in sum is correct at the end, yet the printf() does not display anything on the screen. I've tried all sorts of combinations of fprintf(), printf(), and fflush(), but nothing works.
What do I need to change so the program will print the result to stdout?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 9;
int i, sum; i = 1, sum = 0;
while (i < 2 * num) {
sum = sum + i * i;
++i;
}
printf("sum: %d\n", sum);
fflush(stdout);
return 0;
}
The code is correct, and should print sum: 1785 for any conforming implementation.
This is a guess (update: which turns out to be correct), but ...
You've named the source file test.c, and you compile it with:
$ gcc test.c -o test
(or something similar) and execute it with:
$ test
which produces no output.
The problem is that test is a standard Unix command (and also a built-in command in some shells). When you type a command name to the shell, it first looks for built-in commands, then for executables in directories specified in your $PATH environment variable.
To execute a command in the current directory, prepend ./ to the name:
$ ./test
sum: 1785
$
This applies to any command in the current directory. There are so many built-in commands that you can't reasonably avoid colliding with them. Cultivating the habit of running executables in the current directory by typing ./whatever means that name collisions don't matter.
(Don't be tempted to add . to the front of your $PATH; that's dangerous. Think about what could happen if you cd into a directory and type ls, if there happens to be a malicious ls command there.)
There is nothing wrong with your program. It has to work. Try running it with redirection:
./a.out > myout
..and see if you get any output. If not, I'd suspect there is a problem with some kind of standard library mismatch.
Another option to check would be to build using SUN C compiler as opposed to gcc and see if that works. If it does, gcc is the culprit.

Resources