How do i remove NULL input in C? - c

My teacher has asked me to "Fool proof" my code from any sort of misuse, So I have come up with an
program that can remove any empty values (by disallowing them entirely)
Here is the Un-foolproofed code
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
printf("Type something: ");
fgets(text,16, stdin);
printf("You typed: %s",text);
getch();
}
I have made some simple adjustments to ensure there is no error, however, i cannot get the if filter to work properly, as it still allows the NULL input
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
int loop;
do
{
printf("Type something: ");
fgets(text,16, stdin);
if( text[0] == '\0')
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}
}
while(loop > 0);
printf("You typed: %s",text);
getch();
}
I've tried google and i cannot get a solid answer, this probably is some very simple line of code, but sadly i have no idea what it is.
Edit: it's fixed, the if statement should be:
if (text[0] == '\n')

Using the return value from fgets() is the best first step to fool-proofing user I/O.
char text[16];
printf("Type something: ");
if (fgets(text, sizeof text, stdin) == NULL) {
if (feof(stdin)) Handle_stdin_is_closed(); // no more input
if (ferror(stdin) Handle_IOerror(): // very rare event, more common with files
}
// Test is input is is only a '\n'
if (text[0] == '\n')
printf("Try again");
// Look for long line.
size_t len = strlen(text);
if (len + 1 == sizeof text && text[len - 2] != '\n') HandleLongLine();
The next step is to look for scan errors. Let's assume code is to read a long.
errno = 0;
char *endptr;
long = strtol(text, &endptr, 10);
if (errno) Handle_NumericOverflow();
if (text == endptr) Handle_InputIsNotNumeric();
while (isspace((unsigned char) *endptr)) endptr++;
if (*endptr != '\0') Handle_ExtraTextAfterNumber();
Although this is a lot of code, robust handling of hostle user input is best spun off to a helper function where lots of tests can be had.
char * prompt = "Type something: ";
long number;
int stat = GetLong(stdin, prompt, &number); // put all tests in here.
if (stat > 0) Handle_SomeFailure();
if (stat < 0) Handle_EOF();
printf("%ld\n", number);

fgets reads a whole line including the newline into the buffer and 0-terminates it.
If it reads something and then the stream ends, the read line will not have a newline.
If the line does not fit, it won't contain a newline.
If an error occurs before it successfully reads the first character, it returns NULL.
Please read the man-page for fgets: http://man7.org/linux/man-pages/man3/fgets.3.html

According to the fgets() man page
char *fgets(char *s, int size, FILE *stream);
//fgets() returns s on success, and NULL on error or when end of file
//occurs while no characters have been read.
so, you can check the return value of fgets()
n = fgets(text,16, stdin);
if that value is NULL, then nothing have been read.
you can do this by checking the value of n in a for loop,
if( n == NULL)
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}

Related

Is there an elegant way to handle the '\n' that gets read by input functions (getchar(), fgets(), scanf()) in C?

I am trying a simple exercise from K&R to append string2 at the end of string1 using pointers. In case of overflow i.e. buffer of string1 can't contain all of string2 I want to prompt the user to re-enter string2 or exit.
I have written the following code:
#include<stdio.h>
#include<string.h>
#define MAXLINE 1000
int get_input(char *s);
int str_cat(char *s, char *t);
void main()
{
char input1[MAXLINE], input2[MAXLINE], c;
get_input(input1);
check:
get_input(input2);
if((strlen(input1) + strlen(input2) + 2) <= MAXLINE)
{
str_cat(input1, input2);
printf("%s\n", input1);
}
else
{
input2[0] = '\0';
printf("String overflow\n Press: \n 1: Re-enter string. \n 2: Exit.\n");
scanf(" %d", &c);
if(c == 1){
input2[0] = '\0';
get_input(input2);
goto check;
}
}
}
int get_input(char *arr)
{
int c;
printf("Enter the string: \n");
while(fgets(arr, MAXLINE, stdin))
{
break;
}
}
int str_cat(char *s, char *t)
{
while(*s != '\0')
{
s++;
}
while((*s++ = *t++) != '\0')
{
;
}
*s = '\0';
}
Initially, I was using the standard getchar() function mentioned in the book to read the input in get_input() which looked like this:
int get_input(char *arr)
{
int c;
printf("Enter the string: \n");
while((c = getchar()) != '\n' && c != EOF)
{
*arr++ = c;
}
*arr = '\0';
}
I am new and I read this and understood my mistake. I understand that one isn't supposed to use different input functions to read stdin and the '\n' is left in the input stream which is picked by the getchar() causing my condition to fail.
So, I decided to use fgets() to read the input and modified the scanf("%d", &c) as mentioned in the thread with scanf(" %d", c). This does work (kinda) but gives rise to behaviors that I do not want.
So, I have a few questions:
What's a better way to fgets() from reading the input on encountering '\n' than the one I have used?
while(fgets(arr, MAXLINE, stdin))
{
break;
}
fgets() stops reading the line and stores it as an input once it either encounters a '\n' or EOF. But, it ends up storing the '\n' at the end of the string. Is there a way to prevent this or do I have to over-write the '\n' manually?
Even though I used the modified version of scanf(" %d", &c), my output looks like
this: (https://imgur.com/a/RaC2Kc6). Despite that I get Enter the string: twice when prompted to re-enter the second string in case of an overflow situation. Is the modified scanf() messing with my input? And how do I correct it?
In general, do not mix fgets with scanf. Although it may be a bit bloaty, you will avoid many problems by being consistent with reading input with fgets and then parse it with sscanf. (Note the extra s)
A good way to remove the newline is buffer[strcspn(buffer, "\n")] = 0
Example:
// Read line and handle error if it occurs
if(!fgets(buffer, buffersize, stdin)) {
// Handle error
}
// Remove newline (if you want, not necessarily something you need)
buffer[strcspn(buffer, "\n")] = 0;
// Parse and handle error
int val;
if(sscanf(buffer, "%d", &val) != 1) {
// Handle error
}
// Now you can use the variable val
There is one thing here that might be dangerous in certain situations, and that is if buffer is not big enough to hold a complete line. fgets will not read more than buffersize characters. If the line is longer, the remaining part will be left in stdin.

How to take input until enter is pressed twice?

I want to break this loop when the user press enters twice. Meaning, if the user does not enter a character the second time, but only presses enter again, the loop must break.
char ch;
while(1) {
scanf("%c",&ch);
if(ch=='') { // I don't know what needs to be in this condition
break;
}
}
It is not possible to detect keypresses directly in C, as the standard I/O functions are meant for use in a terminal, instead of responding to the keyboard directly. Instead, you may use a library such as ncurses.
However, sticking to plain C, we can detect newline characters. If we keep track of the last two read characters, we can achieve similar behavior which may be good enough for your use-case:
#include <stdio.h>
int main(void)
{
int currentChar;
int previousChar = '\0';
while ((currentChar = getchar()) != EOF)
{
if (previousChar == '\n' && currentChar == '\n')
{
printf("Two newlines. Exit.\n");
break;
}
if (currentChar != '\n')
printf("Current char: %c\n", currentChar);
previousChar = currentChar;
}
}
Edit: It appears that the goal is not so much to detect two enters, but to have the user:
enter a value followed by a return, or
enter return without entering a value, after which the program should exit.
A more general solution, which can also e.g. read integers, can be constructed as follows:
#include <stdio.h>
#define BUFFER_SIZE 64U
int main(void)
{
char lineBuffer[BUFFER_SIZE];
while (fgets(lineBuffer, BUFFER_SIZE, stdin) != NULL)
{
if (lineBuffer[0] == '\n')
{
printf("Exit.\n");
break;
}
int n;
if (sscanf(lineBuffer, "%d", &n) == 1)
printf("Read integer: %d\n", n);
else
printf("Did not read an integer\n");
}
}
Note that there is now a maximum line length. This is OK for reading a single integer, but may not work for parsing longer input.
Credits: chux - Reinstate Monica for suggesting the use of int types and checking for EOF in the first code snippet.
You can store the previous character and compare it with the current character and enter, like this:
char ch = 'a', prevch = '\n';
while(1){
scanf("%c",&ch);
if((ch=='\n') && (ch == prevch)){// don't know what needs to be in this condition
break;
}
prevch = c;
}
Note that the previous character by default is enter, because we want the program to stop if the user hits enter at the very start as well.
Working like charm now
char ch[10];
while(1){
fgets(ch, sizeof ch, stdin);
if(ch[0]=='\n'){
break;
}
}

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.

C: Clearing STDIN

basically in codeblocks for windows before each printf I have "fflush(stdin);" which works. When I copied my code to Linux, it doesn't work, nor does any of the alternatives for "fflush(stdin);" that I've found. No matter which way I seem to do it, the input doesn't seem to be clearing in the buffer or something in my code is incorrect.
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>
int main()
{
char pbuffer[10], qbuffer[10], kbuffer[10];
int p=0, q=0, k=0;
int r, i, Q, count, sum;
char a[3];
a[0]='y';
while(a[0]=='y' || a[0]=='Y')
{
printf("Enter a p value: \n");
fgets(pbuffer, sizeof(pbuffer), stdin);
p = strtol(pbuffer, (char **)NULL, 10);
printf("Enter a q value: \n");
fgets(qbuffer, sizeof(qbuffer), stdin);
q = strtol(qbuffer, (char **)NULL, 10);
printf("Enter a k value: \n");
fgets(kbuffer, sizeof(kbuffer), stdin);
k = strtol(kbuffer, (char **)NULL, 10);
while(p<q+1)
{
Q=p;
sum=0;
count=0;
while(Q>0)
{
count++;
r = Q%10;
sum = sum + pow(r,k);
Q = Q/10;
}
if ( p == sum && i>1 && count==k )
{
printf("%d\n",p);
}
p++;
a[0]='z';
}
while((a[0]!='y') && (a[0]='Y') && (a[0]!='n') && (a[0]!='N'))
{
printf("Would you like to run again? (y/n) ");
fgets(a, sizeof(a), stdin);
}
}
return 0;
}
Calling fflush(stdin) is not standard, so the behavior is undefined (see this answer for more information).
Rather than calling fflush on stdin, you could call scanf, passing a format string instructing the function to read everything up to and including the newline '\n' character, like this:
scanf("%*[^\n]%1*[\n]");
The asterisk tells scanf to ignore the result.
Another problem is calling scanf to read a character into variable a with the format specifier of " %s": when the user enters a non-empty string, null terminator creates buffer overrun, causing undefined behavior (char a is a buffer of one character; string "y" has two characters - {'y', '\0'}, with the second character written past the end of the buffer). You should change a to a buffer that has several characters, and pass that limit to scanf:
char a[2];
do {
printf("Would you like to run again? (y/n) \n")
scanf("%1s", a);
} while(a[0] !='y' && a[0] !='Y' && a[0]!='n' && a[0]!='N' );
}
I think what you are trying to do is more difficult than it seems.
My interpretation of what you are trying to do is disable type ahead so that if the user types some characters while your program is processing other stuff, they don't appear at the prompt. This is actually quite difficult to do because it is an OS level function.
You could do a non blocking read on the device before printing the prompt until you get EWOULDBLOCK in errno. Or the tcsetattr function family might help. It looks like there is a way to drain input for a file descriptor in there, but it might interact badly with fgets/fscanf
A better idea is not to worry about it at all. Unix users are used to having type ahead and what you want would be unexpected behaviour for them.
Drop the need for flushing the input buffer.
OP is on the right track using fgets() rather than scanf() for input, OP should continue that approach with:
char a;
while(a !='y' && a !='Y' && a!='n' && a!='N' ) {
printf("Would you like to run again? (y/n) \n");
if (fgets(kbuffer, sizeof(kbuffer), stdin) == NULL)
Handle_EOForIOerror();
int cnt = sscanf(kbuffer, " %c", &a); // Use %c, not %s
if (cnt == 0)
continue; // Only white-space entered
}
Best to not use scanf() as it tries to handle user IO and parsing in one shot and does neither that well.
Certain present OP's woes stem from fgets() after scanf(" %s", &a); (which is UB as it should be scanf(" %c", &a);. Mixing scanf() with fgets() typically has the problem that the scanf(" %c", &a); leaves the Enter or '\n' in the input buffer obliging the code to want to flsuh the input buffer before the next fgets(). Else that fgets() gets the stale '\n' and not a new line of info.
By only using fgets() for user IO, there need for flushing is negated.
Sample fgets() wrapper
char *prompt_fgets(const char *prompt, char dest, long size) {
fputs(prompt, stdout);
char *retval = fgets(dest, size, stdin);
if (retval != NULL) {
size_t len = strlen(dest);
if (len > 1 && dest[len-1] == '\n') { // Consume trailing \n
dest[--len] = '\0';
}
else if (len + 1 == dest) { // Consume extra char
int ch;
do {
ch == fgetc(stdin);
} while (ch != '\n' && ch != EOF);
}
return retval;
}

How to prevent the user from entering more data than the maximum limit?

This code asks the user for data and subsequently a number:
$ cat read.c
#include<stdio.h>
#include<stdlib.h>
#define MAX 10
int main() {
char* c = (char*) malloc(MAX * sizeof(char));
int num;
printf("Enter data (max: %d chars):\n", MAX);
fgets(c, MAX, stdin);
// how do I discard all that is there on STDIN here?
printf("Enter num:\n");
scanf("%d", &num);
printf("data: %s", c);
printf("num: %d\n", num);
}
$
The problem is that apart from the instruction that states the maximum number of chars, there is nothing that stops the user from entering more, which is subsequently read into num as junk:
$ ./read
Enter data (max 10 chars):
lazer
Enter num:
5
data: lazer
num: 5
$ ./read
Enter data (max 10 chars):
lazerprofile
Enter num:
data: lazerprofnum: 134514043
$
Is there a way to discard all that is there on STDIN after the fgets call?
The scanf() function is terrible for user input, and it's not that great for file input unless you somehow know your input data is correct (don't be that trusting!) Plus, you should always check the return value for fgets() since NULL indicates EOF or some other exception. Keep in mind that you get the user's newline character at the end of your fgets() data unless the maximum is reached first. I might do it this way as a first pass:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10
void eat_extra(void) {
int ch;
// Eat characters until we get the newline
while ((ch = getchar()) != '\n') {
if (ch < 0)
exit(EXIT_FAILURE); // EOF!
}
}
int main() {
char c[MAX+1]; // The +1 is for the null terminator
char n[16]; // Arbitrary maximum number length is 15 plus null terminator
int num;
printf("Enter data (max: %d chars):\n", MAX);
if (fgets(c, MAX, stdin)) { // Only proceed if we actually got input
// Did we get the newline?
if (NULL == strchr(c, '\n'))
eat_extra(); // You could just exit with "Too much data!" here too
printf("Enter num:\n");
if (fgets(n, sizeof(n) - 1, stdin)) {
num = atoi(n); // You could also use sscanf() here
printf("data: %s", c);
printf("num: %d\n", num);
}
}
return 0;
}
To my knowledge, the only portable solution is to exhaust the buffer yourself:
while (getchar() != EOF);
Note that fflush(stdin); is not the answer.
EDIT: If you only want to discard characters until the next newline, you can do:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
What "can happen" to fgets?
it returns NULL when there is an error in input
it returns NULL when it finds an EOF before any "real" characters
it returns the pointer to the buffer
the buffer wasn't completely filled
the buffer was completely filled but there is no more data in input
the buffer was completely filled and there is more data in input
How can you distinguish between 1 and 2?
with feof
How can you distinguish between 3.1., 3.2. and 3.3.
By determining where the terminating null byte and line break were written:
If the output buffer has a '\n' then there is no more data (the buffer may have been completely filled)
If there is no '\n' AND the '\0' is at the last position of the buffer, then you know there is more data waiting; if the '\0' is before the last position of the buffer, you've hit EOF in a stream that doesn't end with a line break.
like this
/* fgets fun */
/*
char buf[SOMEVALUE_LARGERTHAN_1];
size_t buflen;
*/
if (fgets(buf, sizeof buf, stdin)) {
buflen = strlen(buf);
if (buflen) {
if (buf[buflen - 1] == '\n') {
puts("no more data (3.1. or 3.2.)"); /* normal situation */
} else {
if (buflen + 1 == sizeof buf) {
puts("more data waiting (3.3.)"); /* long input line */
} else {
puts("EOF reached before line break (3.1.)"); /* shouldn't happen */
}
}
} else {
puts("EOF reached before line break (3.1.)"); /* shouldn't happen */
}
} else {
if (feof(stdin)) {
puts("EOF reached (2.)"); /* normal situation */
} else {
puts("error in input (1.)");
}
}
The usual, incomplete tests, are buf[buflen - 1] == '\n' and checking fgets return value ...
while (fgets(buf, sizeof buf, stdin)) {
if (buf[strlen(buf) - 1] != '\n') /* deal with extra input */;
}
I would read the data and then check it for user error:
bool var = true;
while var {
printf("Enter data (max: %d chars):\n", MAX);
fgets(c, MAX, stdin);
// how do I discard all that is there on STDIN here?
if(strlen(c) <= 10)
var = false;
else
printf("Too long, try again! ");
}
On the other hand, if you don't want to do this, just read num twice and discard the first one.

Resources