Why is scanf altering the execution order? - c

I'm capturing some user input and saving it to both a struct and a file.
For each field, I first write a prompt using printf, and then capture data to the struct using scanf, and finally write to file using fprintf.
The program works fine, but only on one computer, one scanf executes before its corresponding printf.
Here's the core of the problem:
printf("\n color: ");
scanf("%s",&robot1.color);
fputs(robot1.color, f);
fputs("\n",f);
printf("\n energy: ");
scanf("%d",&robot1.energy);
fprintf(f,"%d",robot1.energy);
fputs("\n",f);
printf("\n height: ");
scanf("%f",&robot1.height);
fprintf(f,"%.2f",robot1.height);
fputs("\n",f);
printf("\n weight: ");
scanf("%f",&robot1.weight);
fprintf(f,"%.2f",robot1.weight);
fputs("\n",f);
I tested it on two Windows PCs using Dev-C++, and on a Mac using GCC. One of the Windows machines is the one causing all this mess.
The correct execution (user input included) is:
color: red
energy: 100
height: 30.5
weight: 500.0
But in the troublesome computer, after I input the energy value, it shows nothing, and to continue I have to input the height value.
After that, I see the height and weight prompts, and finish by capturing the weight:
color: red
energy: 100
30.5
height:
weight: 500.0
The file is written correctly in all cases so, why is only one computer having trouble with scanf and printf?
The struct definition is:
typedef struct roboto
{
char name[10];
char color[10];
int energy;
float height;
float weight;
}robot;

I am guessing its an issue with stdout not being flushed before the user is being prompted for input. To fix this you could try flushing stdout after each print statement using fflush(stdout);. For example:
printf("\n color: ");
fflush(stdout);
scanf("%s",&robot1.color);
fputs(robot1.color, f);
fputs("\n",f);

The standard output is buffered so you cannot be sure when it will be written.
Call fflush(stdout) to force the output to be written after calling printf, then you can be sure that the output will be written.

Maybe checking the return value from scanf would give you some clues. Ignoring that value is just asking for trouble.

Related

How to use printf() and scanf() in C without going to the next line?

I want to get date of birth in one line:
#include <stdio.h>
int main()
{
int BirthYear,BirthMonth,BirthDay;
printf("Please enter your birth date: ");
scanf("%d",&BirthYear);
printf("/");
scanf("%d",&BirthMonth);
printf("/");
scanf("%d",&BirthDay);
return 0;
}
This is my output:
Please enter your birth date: YYYY
/MM
/DD
But I want to get something like this:
Please enter your birth date: YYYY/MM/DD
In output, it goes to next line after each scanf() without using \n.
I use VS Code for IDM.
Here is a workaround using ansi control characters. I would not do like this, but just to show that it is possible:
#define PREVLINE "\033[F"
#define MSG "Please enter your birth date: "
int main(void) {
int BirthYear,BirthMonth,BirthDay;
printf(MSG);
scanf("%d",&BirthYear);
printf(PREVLINE MSG "%d/", BirthYear);
scanf("%d",&BirthMonth);
printf(PREVLINE MSG "%d/%d/", BirthYear, BirthMonth);
scanf("%d",&BirthDay);
printf("You entered: %d/%d/%d\n", BirthYear, BirthMonth, BirthDay);
}
Please note that this is not portable. The terminal needs to support this in order to work. AFAIK there's no 100% portable way to achieve this.
If you want to do this stuff for real, then I recommend taking a look at the ncurses library
Note:
Always check the return value for scanf to detect errors.
Note2:
It may be a good idea to add fflush(stdout); after each printf statement.
I actually wrote another answer today about ascii control characters. It might be interesting: https://stackoverflow.com/a/64549313/6699433
You can explicitly specify that the three input numbers should be separated by a '/' character by adding that character in the format specifier for the scanf function.
Then, you can ensure that the user gave valid input by checking the value returned by scanf (which will be the number of items successfully scanned and assigned); if that value is not 3, then you will (probably) need to clear any 'leftover' characters in the input buffer, using a getchar() loop until a newline (or end-of-file) is found:
#include <stdio.h>
int main()
{
int BirthYear, BirthMonth, BirthDay;
int nIns = 0, ch;
while (nIns != 3) {
printf("Enter D.O.B. (as YYYY/MM/DD): ");
nIns = scanf("%d/%d/%d", &BirthYear, &BirthMonth, &BirthDay);
while ((ch = getchar() != '\n') && (ch != EOF))
; // Clear remaining in-buffer on error
}
printf("Entered data were: %d %d %d!\n", BirthYear, BirthMonth, BirthDay);
return 0;
}
Expanding on my comment...
The problem you're running into is that you have to hit Enter for each input, which writes a newline to the terminal screen. You can't avoid that.
And unfortunately, you can't overwrite the newline on the screen with a '\b'; you can only backspace up to the beginning of the current line, not to a previous line.
You basically can't do what you want with vanilla C - the language only sees byte streams, it has no concept of a "screen".
There are some terminal control sequences you can play with to reposition the cursor after sending the newline; I don't know how well those will work for you.
Beyond that, you'll need to use a library like ncurses.
#include <stdio.h>
int main()
{
int BirthYear,BirthMonth,BirthDay;
printf("Please enter your birth date: ");
scanf("%d/%d/%d",&BirthYear,&BirthMonth,&BirthDay);
return 0;
}
You can take multiple values from scanf which are then separated by any text you like (in this case /s).
You could use fflush(3) (in particular before all calls to scanf(3)) like in
printf("Please enter your birth date: ");
fflush(NULL);
but you should read this C reference website, a good book about C programming such as Modern C, and the documentation of your C compiler (perhaps GCC) and debugger (perhaps GDB).
Consider enabling all warnings and debug info in your compiler. With gcc that means compiling with gcc -Wall -Wextra -g
Be aware that scanf(3) can fail.
Your code and problem is surely operating system specific.
On Linux consider using ncurses (for a terminal interface) or GTK (for a graphical interface). Read also the tty demystified, then Advanced Linux Programming and syscalls(2) and termios(3).
You might also consider using ANSI escape codes, but be aware that in 2020 UTF-8 should be used everywhere.

Format string attack, convert output to readable format in bash

I'm working on a ctf challenge. This is the relevant code section,
void details(){
char name[100];
printf("Please enter your name: ");
scanf("%100s", name);
printf("Hello %s!\n", name);
}
If I EOF scanf/stdin, printf will output arbitrary data, which I
hope to put to some use but it's indiscernable hex data in bash.
I tried piping the output to hexdump or od -t x1, redirect to a
file but whatever I'm trying the shell output doesn't match what
I'm seeing in gdb, e.g. 0xf7facce0 0xf7e7b6e3 etc etc.
output/bash
Any pointers?
Thanks.
Ok, I'll eloborate, bear with me the interface here is still somewhat of a challenge all by itself.
I was trying to keep my question generic to avoid running into any spoilers.
There's are other attack vectors I'm looking at, this is just one of the them.
And I know I can overflow the buffer but that will only get halfway where I
need to go.
void welcome(){
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}
int main(){
printf("Toddler's Secure Login System 1.0 beta.\n");
welcome();
login();
// something after login...
printf("Now I can safely trust you that you have credential :)\n");
return 0;
}
In gdb it looks something like this,
gdb
At the top you can see the printf output when I quit scanf with Ctrl-D, "Welcome &%%/%/&", obviously it's non readable in this format. In the disassembly the buffer is at $ebp-0x70, 0xffffd068 and following. As you can see there's a few words before the first 0 byte and I was hoping to be able to make these available
in bash. Now, if I pipe the program's output to od to convert to hex, all I get to see is printable ASCII codes in hex, where did the non-printable characters go?
pipe to od -t x1
The real function of interest in this challenge is login(). To give you a hint on this challenge without spoiling it for you: remember that even when the welcome() function ends and the stack is cleared, those values can still remain in those memory locations. Look at the scanf() function in login() instead.

My Visual Studio Code won't run my code properly

I can't properly run/debug my code in VS Code using the C language. I've installed C/C++ package on VSC, Mingw & applied the path for Mingw. All my files are running .c format as well.
Only the last part of my code keeps crashing in VSC, when I run this same code on website compilers, it works!
Here is my code:
#include <stdio.h>
int main(void) {
int num1;
int num2;
printf("Enter a number: ");
scanf("%d", &num1);
printf("Enter another number: ");
scanf("%d", &num2);
printf("Answer: %d ", num1 + num2);
return 0;
}
That last printf is where VSC just shuts down the output window, so I never get to see the end result of my code. Anyone have any solutions to fix this? It'd be greatly appreciated!
When you run your console program from Visual Studio, it opens a terminal window, runs the program and the terminal window closes automatically when the program exits. This is a classic problem with the Microsoft Windows platform that they do not seem to care about despite millions of newbie programmers like you experiencing the same problem.
If you open the terminal window yourself, by running the CMD command from the start menu, you will be able to run your program manually after changing the current directory to that of the program binary.
To prevent the terminal window from closing immediately when running directly from Visual Studio, you should add 2 getchar(); statements before returning from main() to wait for user input and get a chance to see the output. Just reading a single byte with getchar() will not suffice because it will just read the pending newline entered by the user in response to the second prompt.
Also note that it is preferable to output a trailing newline to ensure the output is properly flushed on some legacy systems:
printf("Answer: %d\n", num1 + num2);
Here is a modified program you can test:
#include <stdio.h>
int main(void) {
int num1 = 0, num2 = 0;
printf("Enter a number: ");
scanf("%d", &num1);
printf("Enter another number: ");
scanf("%d", &num2);
printf("Answer: %d\n", num1 + num2);
getchar(); // read the pending newline
getchar(); // read at least another byte from the user.
return 0;
}
run you program from the console:
In the search box type cmd
cd \path_to_your_executable
run your program.

Netbeans 8.1 scanf() function does not work properly

I'm running Netbeans 8.1 on a Windows 10 x86 64-bit computer, I have the project's Run>Console Type set to Standard Output because neither internal nor external terminal have worked for me with any other source I've made--for which standard output had. In any case, here is the code I'm attempting to run:
int main(void){
float original_amount, amount_with_tax;
printf("Enter an amount: ");
scanf("%f", &original_amount);
amount_with_tax = original_amount * 1.05f;
printf("With tax added: $%.2f\n", amount_with_tax);
exit(EXIT_SUCCESS);
}
and here is the output:
3
Enter an amount: With tax added: $3.15
RUN SUCCESSFUL (total time: 4s)
As you can see, the scan function is reading in the number before the program even prints "Enter an amount:". Also, after I commented out the scanf function, it printed both printf statements as expected. I have been wrestling with this problem for a while now and any help is appreciated, thanks!
ISO/IEC 9899:201x:
Files
… When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line
character is encountered. …
Your standard output stream seems to be line buffered, which is most often so.
try printf("Enter an amount: ");fflush(stdout); – BLUEPIXY
That worked! Is this only necessary because I'm using the standard output as my run console?
No, other streams opened by your program may even be fully buffered.
And if so, should I just put it at the beginning of any program that
will use a function accessing the buffer?
Putting fflush(stdout) at the beginning of a program won't do, since it outputs only once what is already in the stdout buffer. But you can use setbuf(stdout, NULL) there.

No way to input data when the program is running in NetBeans

I'm trying to execute a program from the book by K. N. King "C Programming, A Modern Approach, 2 Edition", in NetBeans 8.0.2, using MinGW compiler. The program looks like this:
#include <stdio.h>
int main(void) {
int height, length, width, volume, weight;
printf("Enter height of box: ");
scanf("%d", &height);
printf("Enter length of box: ");
scanf("%d", &length);
printf("Enter width of box: ");
scanf("%d", &width);
volume = height * length * width;
weight = (volume + 165) / 166;
printf("Volume (cubic inches): %d\n", volume);
printf("Dimensional weight (pounds): %d\n", weight);
return 0;
}
So, I press "Run Project", the program builds successfully without any errors, then it begins to run and nothing happens, no console or something like that appears to input data like height, length, etc.
In the output window, after the program builded, it begins to run and nothing is displayed in the window except for a thick cursor. When I press any button being in that window, the program ends and this is what is displayed:
Enter height of box: Enter length of box: Enter width of box: Volume (cubic inches): 0 Dimensional weight (pounds): 0
RUN SUCCESSFUL (total time: 6s)
I'm completely new to C, so I don't know, what should appear when the program runs. When launching programs written in Python the console appeared, and now I'm confused.
When I tried to debug, it builded successfully again and then the console appeared with the line: "Enter height of box: ", so it worked like I thought it should work, but I don't think this is the proper way to run programs.
stdio streams are buffered. You need to fflush() stdout before using stdin, if you want the output to be displayed before the program blocks waiting on input. Alternatively, you can end all output lines with '\n', as newline implicitly flushes the output.
Edit: If you're entering data that scanf() cannot match using %d, such as alphabetic characters, scanf() will fail. You can check for this failure by comparing the return value of scanf() with the number of matches you expected (one in this case). As it stands, you don't check for this, and the characters stay in the input buffer, where the next scanf() will again try and fail to match them.

Resources