Clearing the buffer not working as expected? - c

I have the following code.
int x1, x2;
char check[3];
do{
//input should be (x1,x2)
successfully_inputed = scanf("(%d,%d%2s", &x1, &x2, check);
if(successfully_inputed == EOF)
break;
if(check[1] || successfully_inputed != 3 || check[0] != ')'){
fprintf(stderr, "Invalid line");
char ch;
while((ch = getchar()) != EOF && ch != '\n');
continue;
}
getchar(); // remove the new line character from buffer
}while(1);
It does work for every input i give other than a particular one. When i give anything and then followed by the EOF, for example "asdEOF" then it consumes "asd" and when it reaches EOF it asks me for input, not the scanf() but the getchar(). Why is this happening and how can i solve it?

When the input is "asd<ctr-d>" scanf() fails so you need to swap the order of conditions to you check it first:
if(successfully_inputed != 3 || check[1] || check[0] != ')'){
In either case we are correctly getting an "Invalid line". Then we try to flush the input stream (ensuring ch is int):
int ch;
while((ch = getchar()) != EOF && ch != '\n');
This result in getchar() reading the 'a' and 's' and 'd' then hanging waiting for input. This is because, on Linux, the ctrl-d only cause the terminal buffer to be flushed, and you need a 2nd ctrl-d on an empty stream to close it. This will then trigger EOF being returned by getchar().
Even if you switch to reading input with fgets() it will not return till you press ctrl-d twice on non-empty input buffer:
#include <stdio.h>
#define LINE_LEN 100
#define CHECK_LEN 3
int main() {
for(;;) {
char line[LINE_LEN];
if(!fgets(line, LINE_LEN, stdin)) {
if(feof(stdin)) break;
// handle error
return 1;
}
int x1;
int x2;
char check[CHECK_LEN];
int rv = sscanf(line, "(%d,%d%2s", &x1, &x2, check);
if(rv != 3 || check[1] || check[0] != ')') {
fprintf(stderr, "\nInvalid line\n");
}
}
}
and example session:
$ ./a.out
asd<ctrl-d><ctrl-d>
Invalid line
$
$ ./a.out
<ctrl-d>
$

Related

In C, why do I only need getchar() to remove characters sometimes?

I am trying to use getchar() to remove characters from the input buffer. In the following code, the user is asked to input a choice to select, and then depending on the choice, another input is required, either type int or type char (string).
In the int case, getcar() is not needed and scanf takes in input correctly. But in the char case, scanf fails to get input without using getchar() beforehand. Is there a reason why that is?
printf("Available Ciphers:\n1) Caesar Cipher\n2) Vigenere Cipher\nSelected Cipher: ");
if(scanf("%d", &choice) != 1){
printf("Error: Bad selection!\n");
exit(EXIT_SUCCESS);
} else if (choice != 1 && choice != 2){
printf("Error: Bad Selection!\n");
exit(EXIT_SUCCESS);
//If the choice entered is correct, then run the following.
} else {
if(choice == 1){
printf("Input key as nuumber: ");
if(scanf("%d", &caesarkey) != 1){ //Why is getchar() not needed here?
printf("Error: Bad Key!\n");
exit(EXIT_SUCCESS);
}
//morecode here
} else if (choice == 2){
printf("Input key as string: ");
while(getchar() != '\n'); //Why is this needed here?
/*Uses scanf and not fgets, since we do not want the
key to contain the newline character '\n'. This is
due to the fact that the newline character is not
considered in the function that encrypts and decrypts
plaintext and ciphertext.*/
if(scanf("%[^\n]s", vigencipherkey) != 1){
printf("Error, Cannot read inputted key!\n");
exit(EXIT_SUCCESS);
}
//More code here..
}
}
It seems that you are scanning for a string rather than an int, and as such, you are passing in an int rather than the address of an int.
Change this line
if(scanf("%[^\n]s", vigencipherkey) != 1){
To
if (scanf("%d", &vigencipherkey) != 1) {
In order to read the remainder of the line input by the user, you can use this function:
int flush_line(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
Notes:
c must be defined as int to accommodate for all values of the type unsigned char and the special negative value EOF.
you should test for '\n' and EOF otherwise you will have an endless loop on premature end of file without a trailing newline, such as would occur if you redirect the input of your program from an empty file.
you can test for end of file by comparing the return value of flush_line() with EOF.

Halt while loop if the condition is not met

I'm trying to add a while loop inside the program. After it executes it's supposed to ask you if you want to continue and type in "y" if you do and "n" if you don't. If they do it's supposed to start over again, if not then it stops.
The thing is I wanted to make a message pop up if someone types in something other then "y" or "n" to require them to do that. The problem is the while loop will go on whatever they write in.
char cnd[100];
while(cnd[0] != 'n') {
printf("Program executing\n");
printf("Would you like to launch the program again? If not then type in 'n', if you do then type in 'y': ");
scanf("%s", &cnd);
while(cnd[0] != 'n' || cnd[0] != 'y') {
printf("You have to type in either 'y' or 'n':");
scanf("%s", &cnd);
}
}
return 0;
I tried to even test this by printing the user input before and after the statement. It does seem to be correct, so I don't know why the while loop won't work.
Let's translate your loop condition to plain English:
cnd[0] != 'n' || cnd[0] != 'y'
Basically, you're saying:
If the first character in cnd is something other than n, or the first character in cnd is something other than y, enter the loop.
This is unfalsifiable since cnd[0] will always be either not n or not y - it can't be both at the same time.
You should instead be asking:
If the first character in cnd is something other than n, and the first character in cnd is something other than y, enter the loop.
your while loop checks if it isn't y or isn't n one of those is always true try this instead
while(cnd[0] != 'n' && cnd[0] != 'y') {
The condition cnd[0] != 'n' || cnd[0] != 'y' is always true. You meant to use && (logical and).
You also need to drop & from &cnd (in both scanf calls) as that'd result in format specifier mismatch.
Also in the very first iteration cnd is uninitialized. You're better off using a do ..while loop or start cnd with "y" such as: char cnd[100] = "y";
Note the problems with scanf too.
read what you wrote (as code, not as english)
while(cnd[0] != 'n' || cnd[0] != 'y') {
if cnd[0] = 'n' then it doesnt = 'y' and vice versa.
you mean
while(cnd[0] != 'n' && cnd[0] != 'y') {
ie give the error is its not n and its not y
First and foremost: Why do you read a string when you want a single character? Use getchar(). Then check if there is other garbage after that character in the stream and act accordingly: Error message, clearing stdin:
#include <stdbool.h>
#include <ctype.h>
#include <stdio.h>
void clear(FILE *stream)
{
int ch;
// eat everything until a newline or EOF is encountered:
while ((ch = fgetc(stream)) != EOF && ch != '\n');
}
bool only_whitespace(FILE *stream)
{
int ch;
// eat all whitespace until a newline or EOF is encountered:
while ((ch = fgetc(stream)) != EOF && isspace((char unsigned)ch) && ch != '\n');
// ^^^^^^^^^^^^^^ don't pass signed values
// to the functions from <ctype.h>
if (ch == '\n') { // when the last character read was a newline
ungetc(ch, stream); // put it back into the stream
return true; // and tell the caller that all we encountered
} // was whitespace
return false;
}
int main(void)
{
int again;
do {
puts("Program executing\n");
while (printf("Would you like to launch the program again? If not then type in 'n', if you do then type in 'y': "),
(again = getchar()) != EOF && again != 'y' && again != 'n' || !only_whitespace(stdin))
{
fputs("Input error!\n\n", stderr);
if (again != '\n') // when the character read was not a newline
clear(stdin); // there could be other garbage left in the stream
}
clear(stdin);
} while (again == 'y');
// return 0; // Since C99 (i think) the effect of execution reching the end of main() without
// encountering a return-statement is the same as return 0; (same in C++)
}

C - While-Loop Duplicating Print Statements

When the while-loop runs after the first time, it prints my "Create new node" prompt twice before getting user input from stdin. Why is this? See linked image.
Code:
int main()
{
char userInput[2];
while(1)
{
printf("\nCreate new node? (y/n)\n");
printf(">>> ");
fgets(userInput, 2, stdin);
if(strcmp(userInput, "y") == 0)
{
printf("Yes\n");
}
else if(strcmp(userInput, "n") == 0)
{
printf("No\n");
exit(0);
}
}
}
Terminal Output:
fgets read string plus '\0' plus '\n'. Since userInput is of only 2 bytes, '\n' will not be read by fgets and will be there in the input buffer. On next iteration fgets will read '\n' left by the previous call of fgets.
Increase the buffer size and you will have no problem
char userInput[3];
or you can put
int ch;
while((ch = getchar()) != '\n' && ch != EOF);
just after fgets statement.

Using scanf for char array in while loop

I am new to C programming.
I was curious as to see how much I have learnt C.
Therefore I thought of creating a program in which I could simply create a file and write in it.
The name of the file, I thought, should be less that 100 chars. But it doesn't matter if it is a string or one word or a letter.
I couldn't complete because I was stuck on fact that how to input a string for a file name(eg, Project work, New Doc1, etc)
So I wrote this;
int main()
{
int a = 0;
while(a != 5)
{
puts("Put a number: ");
scanf("%i", &a);
if(a == 1)
{
char name[30];
printf("Put a name: ->>");
for(int i = 0;i < 31 && name[i] != '\n';i++)
{
name[i] = getchar();
}
char ex[50] = ".txt";
strcat(name,ex);
printf("%s",name);
}
}
return 0;
}
The problem is while inputting the name, it doesn't stop at the next (when I press enter) and some how it is not printing the right file name either.
There's a lot of problems with you approach.
It's not good to mix scanf with another input primitives, you must flush stdin from any remaining characters.
Any string must end in '\0' in order to mark that string as complete. So you must reserve space to this character.
When you concat you must obey the limit of the string.
If you use printf, the string will be only displayed after flushing the stdout (when you put '\n' in the end of the string, flush is done)
Try this:
#include <stdio.h>
#include <string.h>
int main()
{
int a = 0;
while(a != 5)
{
int ch;
puts("Put a number: ");
scanf("%d", &a);
/* flush any remaining characters */
while ((ch=getchar()) != EOF && ch != '\n'); /* issue 1 */
if(a == 1)
{
int i = 0;
char name[30];
printf("Put a name: ->>");
fflush(stdout); /* issue 4 */
while ((ch=getchar()) != EOF && ch != '\n' && i < 25) /* issue 3 */
name[i++] = ch;
name[i] = '\0'; /* issue 2 */
/* flush any remaining characters [if input > 25 chars] */
if (ch != EOF && ch != '\n') while ((ch=getchar()) != EOF && ch != '\n');
char ex[50] = ".txt";
strcat(name,ex); /* issue 3 */
printf("%s\n",name);
}
}
return 0;
}
Also, consider use getline and atoi instead of getchar and scanf
#include<stdio.h>
main()
{
static char stop_char='y';
char input=0;
do{
printf("please input a character\n");
scanf("\n%c",&input);
}while(input!=stop_char);
}

fgets and readRestOfLine errors

I got errors while creating a menu using fgets and readrestofline function. I don't know where is the error coming from. Am I missing something? After compiling, errors shows at "fgets", "readrestofline" and "stdin".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int printMenu(void)
{
int option;
char input[3];
while((option != 3)||(option < 4)||(option > 0))
{
printf("Welcome\n");
printf("---------------------\n");
printf("1.Play \n2.Display Scores\n3.Quit\n");
printf("Please enter your choice: ");
fgets(input, 3, stdin);
if (input[strlen(input) - 1] != '\n')
{
printf("Input was too long.\n");
readRestOfLine();
}
else
{
input[strlen(input) - 1] = '\0';
}
switch (option)
{
case 1:
printf("Loading ...\n");
break;
case 2:
printf("Loading ...\n");
break;
case 3:
printf("Quitting...\n");
exit(0);
break;
default:
printf("Invalid ! Please choose again.\n");
break;
}
}
}
void readRestOfLine()
{
int c;
/*read until the end of the line or end-of-file*/
while ((c = fgets(stdin)) != '\n' && c != EOF);
/*clear the error and end-of-file flags*/
clearerr(stdin);
}
errors while creating a menu using fgets...
Regarding your code line:
while ((c = fgets(stdin)) != '\n' && c != EOF);
fgets, prototype is:
char *fgets (char Line_Buffer[], int Number_of_Chars, FILE *Stream);
Reads characters from the specified input stream into a lineBuffer until end-of-file is encountered, a newline character is read, or (number_ofChars - 1) characters are read. The newline character is retained. An ASCII NUL byte is appended to the end of the string. If successful, the function returns a pointer to lineBuffer.
you have only provided 1 of the 3 necessary arguments.
Example usage:
char buf[80];//line buffer with space for 80 char
int c;
while(fgets(buf, 80, stdin))
{
//do something with buf
}
Also, instead of using the line(s): (undefined behavior)
if (input[strlen(input) - 1] != '\n') //used twice in your code example
Consider testing the contents of the string(s) like this:
if(strstr(input, "\n"))//change the second argument to search for other values
{
//do something
}
Note that your first usage of fgets in the posted code is syntactically correct.

Resources