I'm learning data structures in C and I need to take input from the user. I learned from searching other stackoverflow questions that I need to use fflush after I print something.
The issue I'm having is when I type add it doesn't print anything until I break the while loop by entering quit twice. Can someone explain how to fix this and why it happens please?
Here's the code:
#include "stdio.h"
typedef struct S_RacingCar {
char name[8];
int speed;
} RacingCar;
const int MaxCars = 4;
void PrintList() {
printf("List Print...\n");
}
int AddCar(RacingCar *car) {
printf("Enter Name And Speed:\n\n");
char input[16];
fgets( input, 15, stdin);
int ok = 0;
int result = sscanf(input, "%s %d", car->name, car->speed);
if (result == 2) {
ok = 1;
printf("Added:%s Speed:%d\n\n", car->name, car->speed);
fflush(stdout);
} else {
printf("Sorry, error parsing input\n\n");
}
return ok;
}
int main() {
RacingCar allCars[MaxCars];
int numCars = 0;
char command[16];
char input[16];
while( fgets(input, 15, stdin) ){
sscanf(input,"%s",command);
if ( strncmp(command, "quit", 4) == 0){
printf("\n\nBreaking...\n");
break;
} else if ( strncmp(command, "print", 5) == 0){
PrintList();
fflush(stdout);
} else if ( strncmp(command, "add", 3) == 0){
if (numCars < MaxCars) {
numCars += AddCar( &allCars[numCars] );
fflush(stdout);
} else {
printf("Sorry List is Full!!\n\n");
}
}
fflush(stdout);
}
return 0;
}
The output I get after I type print, and then add is:
print
List Print...
add
The cursor is left blinking under add. If I enter quit I get:
print
List Print...
add
quit
Enter Name And Speed:
Sorry, error parsing input
So the program hasn't ended and I'm wondering why. Could someone explain?
To end the program I have to enter quit again:
print
List Print...
add
quit
Enter Name And Speed:
Sorry, error parsing input
quit
Breaking...
<<< Process finished. (Exit code 0)
================ READY ================
The reason that your program behaves weirdly is because it exhibits UB.
Change
int result = sscanf(input, "%s %d", car->name, car->speed);
To
int result = sscanf(input, "%s %d", car->name, &(car->speed));
This is done because sscanf expects an int* but you give it an int.
Also, you can add
setvbuf(stdout, NULL, _IONBF, 0);
at the start of main and remove all the fflush() in your program. The above line flushes the stdout whenever it is written to.
In addition to the other answer, change:
int AddCar(RacingCar *car) {
printf("Enter Name And Speed:\n\n");
to:
int AddCar(RacingCar *car) {
fflush(stdout);
printf("Enter Name And Speed:\n\n");
Related
What I'm exactly trying to achieve is: You enter your name, get a response like 'your name is', and if you enter a number you get a response like 'invalid input' which loops you back to the 'Enter your name' part
#include <stdio.h>
char i[20];
int result;
int main()
{
void findi(); // im trying to loop it back here if a number is entered instead of a character
printf("Enter your name\n");
result = scanf("%s", &i);
while(getchar() != '\n'){ //dont know how to make it work without the '!'
if(result = '%s'){
printf("Your name is: %s", &i);
return 0;
}
else{
printf("Invalid input"); //doesnt work
findi();
}
}
}
//program just ends after a character is entered instead of continuing
Using &i (char(*)[20]) for %s (expects char*) invokes undefined behavior.
The condition result = '%s' (assign implementation-defined value to result without checking its value) looks weird.
Calling findi() (not disclosed here) from main() need not mean a loop.
Try this:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char i[20];
printf("Enter your name\n");
/* an infinite loop (loop until return or break) */
for (;;) {
int number_exists = 0, j;
/* limit length to read and check the result*/
if (scanf("%19s", i) != 1) {
printf("read error\n");
return 1;
}
/* check if a number is entered */
for(j = 0; i[j] != '\0'; j++) {
if (isdigit((unsigned char)i[j])) {
number_exists = 1;
break;
}
}
/* see the result */
if (number_exists) {
/* one or more number is entered */
printf("Invalid input\n");
} else {
/* no number is entered : exit from the loop */
printf("Your name is: %s\n", i);
break;
}
}
return 0;
}
printf("Enter number of patients:");
int numberOfInputs = scanf("%d", &patients);
if (numberOfInputs != 1) {
printf("ERROR: Wrong number of arguments. Please enter one argument d.\n");
}
I am asking the user to input one number as an argument, but would like to print out a statement if the user does not input anything or puts in more than one input. For example, once prompted with "Enter number of patients:", if the user hits enter without entering anything, I would like to print out a statement. The code above is what I have been specifically tinkering around with it for the past couple hours as a few previous posts on this site have suggested but when I run it in terminal, it does not work. Any suggestions? Thank you in advance, and all advice is greatly appreciated!
If I understand your question right, you want to print an error when the input is anything other than an integer and this includes newline as well. You can do that using a char array and the %[] specifier.
Example:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int patients;
char str[10];
printf("Enter number of patients:");
int numberOfInputs = scanf("%[0-9]", str);
if (numberOfInputs != 1) {
printf("ERROR: Wrong number of arguments. Please enter one argument.\n");
}
patients = atoi(str); //This is needed to convert the `str` back to an integer
}
This will print the error when the user just hits ENTER as well.
This looks super over-complicated, but it basically splits the input, checks it to be exactly one and than checks it to be an integer (and converts it). It works fine in loop as well and handles empty input.
I'm sure there are more elegant solutions to this problem, it's just a suggestion.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
int getNumberOfInput(char* str);
bool isNumber(char* str);
int main()
{
char str[512];
while(1)
{
printf("Enter text: ");
fgets(str, 512, stdin);
int numberOfInput = getNumberOfInput(str);
if ( numberOfInput == 0 )
printf("You must give an input\n");
else if ( numberOfInput > 1 )
printf("You have to give exactly one input\n");
else
{
if (!isNumber(str))
printf("The input is not an integer\n");
else
{
int input = atoi(str);
printf("input: %d\n", input);
}
}
}
return 0;
}
int getNumberOfInput(char* str)
{
char* word = strtok(str, " \t\n\v\f\r");
int counter = 0;
while(word != NULL)
{
++counter;
word = strtok(NULL, " \t\n\v\f\r");
}
return counter;
}
bool isNumber(char* str)
{
int i, len = strlen(str);
for (i=0; i<len; ++i)
if (!isdigit(str[i]))
return false;
return true;
}
I'm trying to create a program that asks to type something and check if it is an integer. If it is an integer, then print "the integer is ...". Else, print "try again" and waits for another input. However, the program prints an infinite number of "try again" if you type in a character. Here's the source code:
#include <stdio.h>
#include <stdbool.h>
int main()
{
int inp;
bool t = 1;
printf("type an integer\n");
while (t) {
if (scanf("%i", &inp) == 1) {
printf("The integer is %i", inp);
t = 0;
} else {
printf("try again");
scanf("%i", &inp);
}
}
}
OP's code fail to consume the offending non-numeric input. It remains in stdin, for the next input function. As it is unfortunately just another scanf("%i", &inp) which fails the same way - infinite loop.
After attempting to read an int, read the rest of the line.
#include <stdio.h>
#include <stdbool.h>
int main() {
int inp;
int scan_count;
printf("Type an integer\n");
do {
scan_count = scanf("%i", &inp); // 1, 0, or EOF
// consume rest of line
int ch;
while ((ch == fgetchar()) != '\n' && ch != EOF) {
;
}
} while (scan_count == 0);
if (scan_count == 1) {
printf("The integer is %i\n", inp);
} else {
puts("End of file or error");
}
}
An even better approach would read the line of user input with fgets(). Example
When you entered a char, the variable inp in scanf("%d", &inp) would get null, since the input that doesn't match the format string. And the character you input would remain in the buffer, so that's the reason both your scanf would not stop.
A simplest way to fix this is modify your second scanf("%i", &inp); to scanf("%c", &c); (don't forget to declare a char c in your main function).
check here while(t) its in an infinite loop because you have to set a condition for t something like while(t==1) or while(t>1) or (t<1) something like that. saying while(t) means that t can be anything and it will continue to run.
There is nothing in to break the while loop.
consider getting rid of the boolean, and simply using a while (1) loop with a break. Also you should be using "%d" to indicate an integer in scanf/printf. And there is no need for the scanf call in the else, since your program would loop back and call scanf again anyway.
#include <stdio.h>
int main() {
int inp = 0;
printf("type an integer\n");
while (1) {
if (scanf("%d", &inp) == 1) {
printf("The integer is %d", inp);
break;
}
else {
printf("try again");
}
}
return 0;
}
I hope this helped.
I was working on this sample exercise, and everything works as I would like it to, but there is one behavior I don't understand.
When providing input: if I make consecutive invalid entries everything seems to work great. But if I enter a number different from 1,2,3 in the case of the first question, or 1,2 in the case of the second question, the program just sits there until a new input is given. If another invalid entry is made, it goes back to the error "invalid entry" message, and if an appropriate number is entered, everything moves along fine.
I do not understand why it stops to wait for a second input...anyone?
Thanks guys.
#include <stdio.h>
static int getInt(const char *prompt)
{
int value;
printf("%s",prompt);
while (scanf("%d", &value) !=1)
{
printf("Your entry is invalid.\nGive it another try: %s", prompt);
getchar();
scanf("%d", &value);
}
return value;
}
int main() {
int wood_type, table_size, table_price;
printf("Please enter " );
wood_type = getInt("1 for Pine, 2 for Oak, and 3 for Mahogany: ");
printf("Please enter ");
table_size = getInt("1 for large, 2 for small: ");
printf("\n");
switch (wood_type) {
case 1:
table_price = (table_size == 1)? 135:100;
printf("The cost of for your new table is: $%i", table_price);
break;
case 2:
table_price = (table_size == 1)? 260:225;
printf("The cost of for your new table is: $%i", table_price);
break;
case 3:
table_price = (table_size == 1)? 345:310;
printf("The cost of for your new table is: $%i", table_price);
break;
default:
table_price = 0;
printf("The cost of for your new table is: $%i", table_price);
break;
}
}
You most likely need to flush your input buffer (especially with multiple scanf calls in a function). After scanf, a newline '\n' remains in the input buffer. fflush does NOT do this, so you need to do it manually. A simple do...while loop works. Give it a try:
edit:
static int getInt(const char *prompt)
{
int value;
int c;
while (printf (prompt) && scanf("%d", &value) != 1)
{
do { c = getchar(); } while ( c != '\n' && c != EOF ); // flush input
printf ("Invalid Entry, Try Again...");
}
return value;
}
The blank line you get if you enter nothing is the normal behavior of scanf. It is waiting for input (some input). If you want your routine to immediately prompt again in the case the [Enter] key is pressed, then you need to use another routine to read stdin like (getline or fgets). getline is preferred as it returns the number of characters read (which you can test). You can then use atoi (in <stdlib.h>) to convert the string value to an integer. This will give you the flexibility you need.
example:
int newgetInt (char *prompt)
{
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0; /* number of characters read */
size_t n = 0; /* numer of chars to read, 0 no limit */
static int num = 0; /* number result */
while (printf ("\n %s ", prompt) && (read = getline (&line, &n, stdin)) != -1)
{
if ((num = atoi (line)))
break;
else
printf ("Invalid Input, Try Again...\n");
}
return num;
}
If some invalid input is entered, it stays in the input buffer.
The invalid input must be extracted before the scanf function is completed.
A better method is to get the whole line of input then work on that line.
First, put that input line into a temporary array using fgets(),
then use sscanf() (safer than scanf because it guards against overflow).
#include <stdio.h>
int main(int argc, const char * argv[]) {
char tempbuff[50];
int result, d , value;
do
{
printf("Give me a number: ");
fgets( tempbuff, sizeof(tempbuff), stdin ); //gets string, puts it into tempbuff via stdin
result = sscanf(tempbuff, "%d", &value); //result of taking buffer scanning it into value
if (result < 1){ //scanf can return 0, # of matched conversions,
//(1 in this case), or EOF.
printf("You didn't type a number!\n");
}
}while (result < 1);
//some code
return 0;
}
Knowledge from: http://www.giannistsakiris.com/2008/02/07/scanf-and-why-you-should-avoid-using-it/
I posted a few days ago already about a problem with my array-program. Well, it is basically a program which lets the user generate an array, safe a specific number in a specific slot, read the array or read a specific slots value. Now I am figuring out, how to let the user save the current array as a file.
this is what I got
void safeFile(){
FILE *f = fopen("list.txt", "a+");
putc(f , list);
fclose(f);
printf("File saved");
start();
}
where's the problem?
My Program crashes everytime I call the function safeFile() .
I played around, came with fputs instead of putc, program won't crash anymore, the file gets created but it's still blank
void safeFile(){
FILE *f = fopen("list.txt", "r+");
fputs(f , list);
fclose(f);
printf("File saved");
start();
}
here is my current full code
would be grateful for advices, im a newb
#include <stdio.h>
#include <stdlib.h>
int list[30];
int x = 0;
int i = 0; // variable used by for-Loop in setList
int j = 0; // variable used by for-Loop in getList
int input;
int option; //start Value
int gvinput; //getValue input
void start();
void getList();
int main()
{
start();
return 0;
}
void setList(int sizeOfList)
{
for (i = x; i <= sizeOfList; i++)
{
list[i] = i;
}
}
void getList(){
for(j = x; j < i ; j++ )
{
printf("At %d we got the value %d \n",j,list[j]);
}
}
void startList()
{
fflush(stdin);
printf("Please enter number between 0 and 30\n ");
scanf("%d",&input);
if(input > 30 || input == 0)
{
printf("The Number is not between 0 and 30\n");
startList();
}
setList(input);
getList();
fflush(stdin);
start();
}
void setValues(int l[])
{
fflush(stdin);
int v;
int loc;
printf("please enter what value you want to safe\n");
scanf("%d",&v);
fflush(stdin);
printf("Where do you want to save it?\n");
scanf("%d",&loc);
l[loc] = v;
printf("we got at slot %d the value %d\n\n",loc,l[loc]);
start();
}
void getValues(int getArray[]){
fflush(stdin);
printf("which slot do you want to read?\n");
scanf("%d",&gvinput);
fflush(stdin);
printf("The value is: %d \n\n",getArray[gvinput]);
start();
}
void safeFile(){
FILE *f = fopen("list.txt", "r+");
fputs(f , list);
fclose(f);
printf("File saved");
start();
}
void start(){
fflush(stdin);
printf("\n");
printf("[L] = generate Slots\n");
printf("[S] = set a Value at specific slot\n");
printf("[G] = get a Value from a specific slot\n");
printf("[F] = safe File");
printf("[X] = exit\n");
option=getchar();
if(option == 'L' || option == 'l'){
startList();
}
if(option == 'S' ||option == 's'){
setValues(list);
}
if (option =='G' ||option == 'g'){
getValues(list);
}
if (option == 'X' || option == 'x'){
printf("Thank you");
}
if (option == 'f' || option == 'F'){
safeFile();
}
int putc( int ch, std::FILE* stream );
putc writes a single char, and you pass an array of ints to it. The same is true for fputs, which writes a null-terminated string. You'll really have to write some code that serializes your data structure to a sequence of bytes to be written to the file.
In your case, since you want to save a list of ints, you can do this with a loop, for example, that is, loop over your array and write each item to the file. You'll also need a function that writes an int (putc isn't good here, since it writes a char). Have a look at printf, if you'd like to stick with C-style IO, otherwise use streams.
If your using putc(), you should be passing char by char.
for(i=0;i<strlen(list);i++)
{
putc(f,list[i]);
}
The list is an array, if you pass the address it means whole array so putc won't work here.
int fputs(const char *s, FILE *stream);
The second argument to the fputs is the stream. Since u use int [10]. u can use fprintf to print to the file.
Also, fflush(stdin); is undefined behaviour
you need to use the loop, but it is not working because the parameters in the putc function are not in the correct order. Try this:
for(i=0;i<strlen(list);i++)
{
putc(list[i],f); //<---------- NOT putc(f,list[i]);
}
first the char and second the stream.
int putc ( int character, FILE * stream );