How to check if user enters blank line in scanf in c - c

I need the program to exit the while loop if the user presses enter without entering any float value. Thanks!
printf("Enter scores\n”);
float scores[10];
int n=0;
while (n<10){
scanf("%f", &scores[n]);
n++;
if (THE USER PRESSES ENTER WITHOUT ENTERING ANYTHING){break;}
}

You can use fgets() to read a line of input through the newline character into a buffer, and then use sscanf() to parse the contents of the buffer. The problem with using scanf() for this is that most conversion specifiers, and in particular the %f conversion specifier, skip leading whitespace, including newlines. So, if you try to give an empty line to scanf(), the function will continue to wait for input until you enter a non-white-space character.
The code below adapts this technique to your code. The variable n has been changed to a size_t type variable, as this is an unsigned type guaranteed to be able to hold any array index. Furthermore, note that both fgets() and sscanf() return values that should be checked. The fgets() function returns a null pointer if there is an error, and the code below prints an error message and exits if this occurs. The sscanf() function returns the number of successful conversions made, and this value can be used to make sure that the input is as expected. When the user enters a blank line, or a line with no leading floating point value (leading white-space is OK), zero is returned, and the input loop is escaped.
I added some code to display the values entered into the array.
#include <stdio.h>
#include <stdlib.h> // for exit()
int main(void)
{
float scores[10];
char buffer[100];
size_t n = 0;
printf("Enter scores\n");
while (n < 10){
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
exit(EXIT_FAILURE);
}
if (sscanf(buffer, "%f", &scores[n]) == 1) {
++n;
} else {
break;
}
}
for (size_t i = 0; i < n; i++) {
printf("scores[%zu] = %f\n", i, scores[i]);
}
return 0;
}
Sample interaction:
Enter scores
3.8
3.6
2.9
3.4
scores[0] = 3.800000
scores[1] = 3.600000
scores[2] = 2.900000
scores[3] = 3.400000

Separate input of user text from parsing.
Read the line of user input as a string;
char buffer[80];
if (fgets(buffer, sizeof buffer, stdin) == NULL) Handle_EOF();
Now, parse the string using sscanf(), strtod(), etc.
if (sscanf(buffer, "%f", &scores[n]) == 1) Handle_Successful_Float_Input(scores[n]);
else if (buffer[0] == '\n') Handle_Empty_Line();
else Handle_Everything_Else(buffer);

fgets is the better route but if scanf must be used, newline can be detected by scanning a character. If the character is not a newline, replace it in the input with ungetc and then scan the float.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 10
int main ( void) {
char i = '\0';
int n = 0;
int result = 0;
float scores[SIZE] = { 0.0f};
printf ( "enter scores\n");
while ( n < SIZE && ( scanf("%c",&i) == 1)) {//scan a character
if ( i == '\n') {
break;//newline so leave loop
}
else {
ungetc ( i, stdin);//replace the character in input stream
}
if ( ( result = scanf ( "%f", &scores[n])) == 1) {//scan a float
printf ( " score[%d] entered as %f\n", n, scores[n]);
n++;
}
if ( result == 0) {
printf ( "please enter a number\n");//could not scan the input as a float
}
while ( ( result = getchar ( )) != '\n') {//clean the input stream
if ( result == EOF) {
fprintf ( stderr, "problem EOF\n");
return 1;
}
}
printf ( "enter score[%d]\n", n);
}
return 0;
}

I thought . you want to check that if an integer is assigned a value or not ?
Actually you have to initialize the variable otherwise it will contain whatever happen at that memory location unless it is declared as global. If you are not getting then check
this might help you with your question

We know that scanf returns a negative value if nothing of the defined type is fetched from the input.
So:
printf("Enter scores\n”);
float scores[10];
int n=0;
while (n<10){
if(scanf("%f\n", &scores[n]) < 0) printf("Error! Error!");
n++;
}
See http://www.cplusplus.com/reference/cstdio/scanf/

Related

How to check if scanf("%s", &var) is a number, and thus turn it into an integer

I have this code and I need help converting the comments to c code
// if the input of scanf() is "q"
{
break;
}
else
{
// convert to int
}
Firstly, how do I check if an input is a certain character. Secondly, how do I turn a string into an integer. Example: "123" -> 123
Things I've tried, that didn't work: (it is possible that I implemented these solutions incorrectly)
how does scanf() check if the input is an integer or character?
Convert char to int in C and C++
I am not using any standard libraries except for stdio.h to print some logging information on the window
you have to know also that any string is terminated by null character which is '\0' to indicate the termination of the string , also you have to check is the user entered characters not numbers and so on (that's not implemented in this code).
I also handled if negative numbers are entered.
but you have to handle if the user entered decimals numbers , to sum up . there are so many cases to handle.
and here the edited code :
#include <stdio.h>
int main(){
char inputString[100];
printf("enter the input:\n");
scanf("%s", &inputString);
if(inputString[0] == 'q' && inputString[1] == '\0' )
{
printf("quiting\n");
//break;
}
else {
int i = 0;
int isNegative = 0;
int number = 0;
// check if the number is negative
if (inputString[0] == '-') {
isNegative = 1;
i = 1;
}
// convert to int
for ( ;inputString[i] != '\0' ; i++) {
number *= 10;
number += (inputString[i] - '0');
}
if(isNegative == 1)
number *= -1;
printf("you entered %d\n", number);
}
return 0;
}
The fundamental question here is, Do you want to use scanf?
scanf is everyone's favorite library function for easily reading in values. scanf has an input specifier, %d, for reading in integers.
And it has a different input specifier, %s, for reading in arbitrary strings.
But scanf does not have any single input specifier that means, "Read in an integer as an integer if the user types a valid integer, but if the user types something like "q", have a way so I can get my hands on that string instead."
Unless you want to move mountains and implement your own general-purpose input library from scratch, I think you have basically three options:
Use scanf with %d to read integers as integers, but check scanf's return value, and if scanf fails to read an integer, use that failure to terminate input.
Use scanf with %s to read the user's input as a string, so you can then explicitly test if it's a "q" or not. If not, convert it to an integer by hand. (More on this below.)
Don't use scanf at all. Use fgets to read the user's input as a whole line of text. Then see if it's a "q" or not. If not, convert it to an integer by hand.
Number 1 looks something like this:
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(scanf("%d", &i) != 1) {
/* end of input detected */
break;
}
do something with i value just read;
}
The only problem with this solution is that it won't just stop if the user types "q", as your original problem statement stipulated. It will also stop if the user types "x", or "hello", or control-D, or anything else that's not a valid integer. But that's also a good thing, in that your loop won't get confused if the user types something unexpected, that's neither "q" nor a valid integer.
My point is that explicitly checking scanf's return value like this is an excellent idea, in any program that uses scanf. You should always check to see that scanf succeeded, and do something different if it fails.
Number 2 would look something like this:
char tmpstr[20];
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(scanf("%19s", tmpstr) != 1) {
printf("input error\n");
exit(1);
}
if(strcmp(tmpstr, "q") == 0) {
/* end of input detected */
break;
}
i = atoi(tmpstr); /* convert string to integer */
do something with i value just read;
}
This will work well enough, although since it uses atoi it will have certain problems if the user types something other than "q" or a valid integer. (More on this below.)
Number 3 might look like this:
char tmpstr[20];
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(fgets(tmpstr, 20, stdin) == NULL) {
printf("input error\n");
exit(1);
}
if(strcmp(tmpstr, "q\n") == 0) {
/* end of input detected */
break;
}
i = atoi(tmpstr); /* convert string to integer */
do something with i value just read;
}
One thing to note here is that fgets includes the newline that the user typed in the string it returns, so if the user types "q" followed by the Enter key, you'll get a string back of "q\n", not just "q". You can take care of that either by explicitly looking for the string "q\n", which is kind of lame (although it's what I've done here), or by stripping the newline back off.
Finally, for both #2 and #3, there's the question of, what's the right way to convert the user's string to an integer, and what if it wasn't a valid integer? The easiest way to make the conversion is to call atoi, as my examples so far have shown, but it has the problem that its behavior on invalid input is undefined. In practice, it will usually (a) ignore trailing nonnumeric input and (b) if there's no numeric input at all, return 0. (That is, it will read "123x" as 123, and "xyz" as 0.) But this behavior is not guaranteed, so these days, most experts recommend not using atoi.
The recommended alternative is strtol, which looks like this:
char *endp;
i = strtol(tmpstr, &endp, 10); /* convert string to integer */
Unlike atoi, strtol has guaranteed behavior on invalid input. Among other things, after it returns, it leaves your auxiliary pointer endp pointing at the first character in the string it didn't use, which is one way you can determine whether the input was fully valid or not. Unfortunately, properly dealing with all of the ways the input might be invalid (including trailing garbage, leading garbage, and numbers too big to convert) is a surprisingly complicated challenge, which I am not going to belabor this answer with.
Here are some guidelines:
scanf("%s", &var) is incorrect: you should pass the maximum number of characters to store into the array var and pass the array without the & as it will automatically convert to a pointer to its first element when passed as an argument:
char var[100];
if (scanf("%99s", var) != 1) {
printf("premature end of file\n");
return 1;
}
to compare the string read to "q", you can use strcmp() declared in <string.h>:
if (strcmp(var, "q") == 0) {
printf("quitting\n");
return 0;
}
to convert the string to the number it represents, use strtol() declared in <stdlib.h>:
char *p;
long value = strtol(var, &p, 0);
testing for a proper conversion is tricky: strtol() updated p to point to the character after the number and set errno in case of range error:
errno = 0;
char *p;
long value = strtol(var, &p, 0);
if (p == var) {
printf("not a number: %s\n", p);
return 1;
}
if (*p != '\0') {
printf("extra characters: %s\n", p);
return 1;
}
if (errno) {
printf("conversion error: %s\n", strerror(errno));
return 1;
}
printf("the number entered is: %ld\n", value);
return 0;
Here is a complete program:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char var[100];
char *p;
long value;
printf("Enter a number: ");
if (scanf("%99s", var) != 1) {
printf("premature end of file\n");
return 1;
}
if (strcmp(var, "q") == 0) {
printf("quitting\n");
return 0;
}
errno = 0;
value = strtol(var, &p, 0);
if (p == var) {
printf("not a number: %s\n", p);
return 1;
}
if (*p != '\0') {
printf("extra characters: %s\n", p);
return 1;
}
if (errno) {
printf("conversion error: %s\n", strerror(errno));
return 1;
}
printf("the number entered is: %ld\n", value);
return 0;
}
You can try this: (Assuming only positive integers needs to convert)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// Write C code here
char var[100];
int numb_flag=1, i=0,number=0;
scanf("%s",var);
while(var[i]!='\0') { // Checking if the input is number
if(var[i]>=48 && var[i]<=57)
i++;
else {
numb_flag = 0;
break;
}
}
if(numb_flag==1) {
number = atoi(var);
printf("\nNumber: %d",number);
} else {
printf("\nNot A Number");
}
return 0;
}
//Mind that in order to be more precise you could also use atof().
//The function works the same way as atoi() but is able to convert float
// (returned value is 'double') the string s
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXILEN 100 /*change the value based on your needs*/
int main(){
int n, lim = MAXILEN;
char s[MAXILEN], *p = s, c;
/*taking the string from the input -- I do not use scanf*/
while(--lim > 0 && (c = getchar()) != EOF && c != '\n')
*p++ = c;
//here you can also do the check (if you want the '\n' char):
//if(c == '\n')
// *s++ = c;
*p = '\0';
if(s[0] == 'q' && s[1] == '\0')
exit(EXIT_SUCCESS); /*change the argument based on your needs*/
else
n = atoi(s);
printf("[DEBUG]: %d\n", n);
}

Using the Scanf function for inputs for different lengths

I want to use the scanf function to get inputs that are either two numbers, or one number from the user and put them in an array. However, I'm not sure how I can use this same function to get inputs for both one element of the array, and also two elements of the array.
i.e. if the user enters, 9 0, it should be able to successfully store that in an array and move onto new code, or if the user enters something like 1, it should also be able to successfully store that in the array, and move onto new code.
I've tried putting the scanf into a while loop:
int scanned_array[2] = {};
int element = 0;
while(scanf("%d", &scanned_array[element]) {
//... more code here which will have different functions depending on the input...
element++;
}
How can I successfully do this while only using the scanf function, while loops, arrays and if statements?
**Edit: Just wondering, if I changed my code according to what was suggested below by #nmgari, how could I go to if(num == 1) { ... without having to press ctrl+d?
Thanks for reading!
If i understand correctly you want to call scanf() once and read either one number or two.
Something like this should work:
int scanned_array[2];
int num_input = 0;
num_input = scanf("%d %d", &scanned_array[0], &scanned_array[1]);
if(num_input == 1)
{
//Do something
}
else if (num_input == 2)
{
//Do somethine else
}
Anyway, you need to consider that the second element in the array may never get a value.
You should read the input line with fgets() and parse it with sscanf():
char buf[120];
if (fgets(buf, sizeof buf, stdin)) {
int i1, i2;
switch (sscanf(buf, "%d%d", &i1, &i2)) {
case 2:
/* the user entered 2 integers */
handle_2_integers(i1, i2);
break;
case 1:
/* the user entered a single integer */
handle_1_integer(i1);
break;
default:
/* the user did not enter a number */
handle_invalid_input();
break;
}
} else {
/* the input stream is at end of file or encountered an error */
handle_end_of_file();
}
If you run scanf("%d%d", &i1, &i2), scanf() will keep reading the input stream until either end of file, or 2 integers have been read or an character has been input that cannot be converted to an integer, possibly reading multiples lines of input for one of these cases to occur. If you want to handle a single line of input, you cannot use scanf() directly.
A separate scan for whitespace could be used.
The scanset %1[ \t\r\n] will capture whitespace character by character. The loop will exit on non-whitespace or a newline.
Then try to scan an integer.
#include <stdio.h>
#include <stdlib.h>
int main ( void) {
char space[2] = "";
int scanned = 0;
int scanned_array[2] = { 0};
while ( 1) {
while ( 1 == scanf ( "%1[ \t\r\n]", space)) {
if ( '\n' == space[0]) {
break;
}
}
if ( '\n' == space[0]) {
break;
}
if ( 1 != scanf ( "%d", &scanned_array[scanned])) {
fprintf ( stderr, "bad input\n");
return 1;
}
++scanned;
if ( 2 <= scanned) {
break;
}
}
for ( int each = 0; each < scanned; ++each) {
printf ( "%d\n", scanned_array[each]);
}
return 0;
}

While with multiple conditions

This is my code.The user enters a string and if the input is 1,2 or * it displays error.The problem is that the condition is satisfied for all the numbers of which the first digits are 1,2 amd 3.(11,12,22...).I used also strlen and sizeof function to count the digits and create a condition that works but when i printed strlen the output was 1 for every number.
I don't understand if the problem is my multiple conditions or the use of scanf
Here is my code
#include < stdio.h >
int main (void)
{
char choice;
int i=0;
do
{
scanf("%s", &choice);
while(choice !='1' && choice !='2' && choice !='*' )
{
printf("error");
scanf("%s",&choice);
}
}while (choice !='0');
return 0;
}
I would be very thankful for any help. I am quite new in programming, so forgive me if the question is stupid.
I propose you the following code:
#include <stdio.h>
#include <string.h>
int main (void)
{
char choice[201];
do
{
scanf("%200s", choice);
if (strcmp(choice, "1") == 0 ||
strcmp(choice, "2") == 0 ||
strcmp(choice, "3") == 0)
printf("error");
} while (strcmp(choice, "0") != 0);
return 0;
}
%s waits for a char * argument, your &choice was right, but scanf will write a whole string at the address pointed to, which can (will) contain more than one char. By giving the address of a char variable, you provided it with the room for only one char.
You can't compare strings with a comparison operator, you have to use, for example, the strcmp function, which returns 0 if it's two argument do match and non-zero otherwise.
If I properly understood your intent, there is no need for two nested while loop. The two scanf calls aren't needed either.
The 200 in the %200s scanf format string, limits the number of chars which will be written in the array you have provided the address of.
This array is of size 201 to account for the extra '\0' byte, terminating C strings.
To write properly this code, one should test the return of scanf, to check if something has been parsed with success.
Please refer to the man page of scanf to see how to check if the parsing went successfully.
You've declared choice as a char object - it's only large enough to store a single character value. If you're entering a string like "123" on input, only the leading '1' is stored to choice and the remaining input is written to memory immediately following choice, which may cause a runtime error if you clobber anything important.
If you want to read and store the input as a string of characters, then you need to declare choice as an array of char, sized to hold at least one more character than the maximum input size - IOW, if you expect the maximum string to be 3 characters long, then choice must be declared as char choice[4];.
If you want to read and store the input as an integer, then you must declare choice as int instead of char, and you need to use the %d conversion specifier instead of %s.
Consider using fgets to obtain input, then parse with sscanf. Using int choice allows you to distinguish between 1 and 11...
#include <stdio.h>
int main( void) {
char input[99] = "";
int choice = 0;
do {
printf ( "Enter 0 to quit\n");
if ( fgets ( input, sizeof input, stdin)) {
if ( 1 == sscanf ( input, "%d", &choice)) {
if ( choice == 1 || choice == 2 || choice == 3) {
printf ( "error\n");
}
else {
printf ( "you entered %d\n", choice);
}
}
else {
if ( 0 == strcmp ( input, "*\n")) {
printf ( "error\n");
}
//sscanf could not parse an int
choice = -1;
}
}
else {
break;// fgets failed
}
} while ( choice != 0);
return 0;
}
the following proposed code:
cleanly compiles
only calls scanf() once per each outer loop
prompts the user for the desired input
and now the code:
#include <stdio.h> // scanf(), printf(), perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
int main (void)
{
char choice;
do
{
printf( "enter 0:" );
if( 1 != scanf(" %c", &choice) )
{
perror( "scanf failed" ); // to stderr:
// enclosed text + reason OS thinks it failed
exit( EXIT_FAILURE ); // once failed, it will continue to fail
// so exit program with error indication
}
// implied else, scanf successful
// what about other user inputs?
if(choice !='1' && choice !='2' && choice !='*' )
{
printf("error\n"); // trailing '\n'
// so immediately displayed on terminal
// note: should use: 'fprintf( stderr, ... )'
// because error messages should
// be output to 'stderr', not 'stdout'
}
} while (choice !='0');
return 0;
} // end function: main

proper use of scanf in a while loop to validate input

I made this code:
/*here is the main function*/
int x , y=0, returned_value;
int *p = &x;
while (y<5){
printf("Please Insert X value\n");
returned_value = scanf ("%d" , p);
validate_input(returned_value, p);
y++;
}
the function:
void validate_input(int returned_value, int *p){
getchar();
while (returned_value!=1){
printf("invalid input, Insert Integers Only\n");
getchar();
returned_value = scanf("%d", p);
}
}
Although it is generally working very well but when I insert for example "1f1" , it accepts the "1" and does not report any error and when insert "f1f1f" it reads it twice and ruins the second read/scan and so on (i.e. first read print out "invalid input, Insert Integers Only" and instead for waiting again to re-read first read from the user, it continues to the second read and prints out again "invalid input, Insert Integers Only" again...
It needs a final touch and I read many answers but could not find it.
If you don't want to accept 1f1 as valid input then scanf is the wrong function to use as scanf returns as soon as it finds a match.
Instead read the whole line and then check if it only contains digits. After that you can call scanf
Something like:
#include <stdio.h>
int validateLine(char* line)
{
int ret=0;
// Allow negative numbers
if (*line && *line == '-') line++;
// Check that remaining chars are digits
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1; // Remember that at least one legal digit was found
++line;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin)) // Read the whole line
{
if (validateLine(line)) // Check that the line is a valid number
{
// Now it should be safe to call scanf - it shouldn't fail
// but check the return value in any case
if (1 != sscanf(line, "%d", &x))
{
printf("should never happen");
exit(1);
}
// Legal number found - break out of the "while (y<5)" loop
break;
}
else
{
printf("Illegal input %s", line);
}
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Input
1f1
f1f1
-3
Output
Please Insert X value
Illegal input 1f1
Please Insert X value
Illegal input f1f1
Please Insert X value
Illegal input
Please Insert X value
x=-3
Another approach - avoid scanf
You could let your function calculate the number and thereby bypass scanf completely. It could look like:
#include <stdio.h>
int line2Int(char* line, int* x)
{
int negative = 0;
int ret=0;
int temp = 0;
if (*line && *line == '-')
{
line++;
negative = 1;
}
else if (*line && *line == '+') // If a + is to be accepted
line++; // If a + is to be accepted
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1;
// Update the number
temp = 10 * temp;
temp = temp + (*line - '0');
++line;
}
if (ret)
{
if (negative) temp = -temp;
*x = temp;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin))
{
if (line2Int(line, &x)) break; // Legal number - break out
printf("Illegal input %s", line);
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Generally speaking, it is my opinion that you are better to read everything from the input (within the range of your buffer size, of course), and then validate the input is indeed the correct format.
In your case, you are seeing errors using a string like f1f1f because you are not reading in the entire STDIN buffer. As such, when you go to call scanf(...) again, there is still data inside of STDIN, so that is read in first instead of prompting the user to enter some more input. To read all of STDIN, you should do something the following (part of code borrowed from Paxdiablo's answer here: https://stackoverflow.com/a/4023921/2694511):
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Used for strtol
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
#define NaN 3 // Not a Number (NaN)
int strIsInt(const char *ptrStr){
// Check if the string starts with a positive or negative sign
if(*ptrStr == '+' || *ptrStr == '-'){
// First character is a sign. Advance pointer position
ptrStr++;
}
// Now make sure the string (or the character after a positive/negative sign) is not null
if(*ptrStr == NULL){
return NaN;
}
while(*ptrStr != NULL){
// Check if the current character is a digit
// isdigit() returns zero for non-digit characters
if(isdigit( *ptrStr ) == 0){
// Not a digit
return NaN;
} // else, we'll increment the pointer and check the next character
ptrStr++;
}
// If we have made it this far, then we know that every character inside of the string is indeed a digit
// As such, we can go ahead and return a success response here
// (A success response, in this case, is any value other than NaN)
return 0;
}
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
// (Per Chux suggestions in the comments, the "buff[0]" condition
// has been added here.)
if (buff[0] && buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
void validate_input(int responseCode, char *prompt, char *buffer, size_t bufferSize){
while( responseCode != OK ||
strIsInt( buffer ) == NaN )
{
printf("Invalid input.\nPlease enter integers only!\n");
fflush(stdout); /* It might be unnecessary to flush here because we'll flush STDOUT in the
getLine function anyway, but it is good practice to flush STDOUT when printing
important information. */
responseCode = getLine(prompt, buffer, bufferSize); // Read entire STDIN
}
// Finally, we know that the input is an integer
}
int main(int argc, char **argv){
char *prompt = "Please Insert X value\n";
int iResponseCode;
char cInputBuffer[100];
int x, y=0;
int *p = &x;
while(y < 5){
iResponseCode = getLine(prompt, cInputBuffer, sizeof(cInputBuffer)); // Read entire STDIN buffer
validate_input(iResponseCode, prompt, cInputBuffer, sizeof(cInputBuffer));
// Once validate_input finishes running, we should have a proper integer in our input buffer!
// Now we'll just convert it from a string to an integer, and store it in the P variable, as you
// were doing in your question.
sscanf(cInputBuffer, "%d", p);
y++;
}
}
Just as a disclaimer/note: I have not written in C for a very long time now, so I do apologize in advance if there are any error in this example. I also did not have an opportunity to compile and test this code before posting because I am in a rush right now.
If you're reading an input stream that you know is a text stream, but that you are not sure only consists of integers, then read strings.
Also, once you've read a string and want to see if it is an integer, use the standard library conversion routine strtol(). By doing this, you both get a confirmation that it was an integer and you get it converted for you into a long.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool convert_to_long(long *number, const char *string)
{
char *endptr;
*number = strtol(string, &endptr, 10);
/* endptr will point to the first position in the string that could
* not be converted. If this position holds the string terminator
* '\0' the conversion went well. An empty input string will also
* result in *endptr == '\0', so we have to check this too, and fail
* if this happens.
*/
if (string[0] != '\0' && *endptr == '\0')
return false; /* conversion succesful */
return true; /* problem in conversion */
}
int main(void)
{
char buffer[256];
const int max_tries = 5;
int tries = 0;
long number;
while (tries++ < max_tries) {
puts("Enter input:");
scanf("%s", buffer);
if (!convert_to_long(&number, buffer))
break; /* returns false on success */
printf("Invalid input. '%s' is not integer, %d tries left\n", buffer,
max_tries - tries);
}
if (tries > max_tries)
puts("No valid input found");
else
printf("Valid input: %ld\n", number);
return EXIT_SUCCESS;
}
ADDED NOTE: If you change the base (the last parameter to strtol()) from 10 to zero, you'll get the additional feature that your code converts hexadecimal numbers and octal numbers (strings starting with 0x and 00 respectively) into integers.
I took #4386427 idea and just added codes to cover what it missed (leading spaces and + sign), I tested it many times and it is working perfectly in all possible cases.
#include<stdio.h>
#include <ctype.h>
#include <stdlib.h>
int validate_line (char *line);
int main(){
char line[256];
int y=0;
long x;
while (y<5){
printf("Please Insert X Value\n");
if (fgets(line, sizeof(line), stdin)){//return 0 if not execute
if (validate_line(line)>0){ // check if the string contains only numbers
x =strtol(line, NULL, 10); // change the authentic string to long and assign it
printf("This is x %d" , x);
break;
}
else if (validate_line(line)==-1){printf("You Have Not Inserted Any Number!.... ");}
else {printf("Invalid Input, Insert Integers Only.... ");}
}
y++;
if (y==5){printf("NO MORE RETRIES\n\n");}
else{printf("%d Retries Left\n\n", (5-y));}
}
return 0;}
int validate_line (char *line){
int returned_value =-1;
/*first remove spaces from the entire string*/
char *p_new = line;
char *p_old = line;
while (*p_old != '\0'){// loop as long as has not reached the end of string
*p_new = *p_old; // assign the current value the *line is pointing at to p
if (*p_new != ' '){p_new++;} // check if it is not a space , if so , increment p
p_old++;// increment p_old in every loop
}
*p_new = '\0'; // add terminator
if (*line== '+' || *line== '-'){line++;} // check if the first char is (-) or (+) sign to point to next place
while (*line != '\n'){
if (!(isdigit(*line))) {return 0;} // Illegal char found , will return 0 and stop because isdigit() returns 0 if the it finds non-digit
else if (isdigit(*line)){line++; returned_value=2;}//check next place and increment returned_value for the final result and judgment next.
}
return returned_value; // it will return -1 if there is no input at all because while loop has not executed, will return >0 if successful, 0 if invalid input
}

Data validation in C - ensuring the input is in a correct format

I want to write a code to ensure that the users input only 1 digit. If a user enters something like "0 1 3" I want my program to read an error message which I have no idea how to do. Anyone has an idea how to approach this? My current code just takes in the first number if a user enters bunch of numbers with a space in between.
Please see my code below. Thanks :D
//Prompt the user to enter the low radius with data validation
printf("Enter the low radius [0.0..40.0]: ");
do
{
ret = scanf("%lf", &lowRadius);
//type validation
if (ret != 1)
{
int ch = 0;
while (((ch = getchar()) != EOF) && (ch != '\n'));
printf("Wrong input. Please enter one numerical value: ");
}
//range validation
else if((lowRadius < 0 || lowRadius > 40))
{
printf("Incorrect value. Please enter in range 0-40: ");
}
else break;
} while ((ret != 1) || (lowRadius < 0 || lowRadius > 40));//end while lowRadius
If you read the line into a string, then analyse it, you avoid the problem of hanging on unsupplied input. You have done most of the work already, but this shows how to trap too much input. It works by scanning a string after the double to pick up any more input. The return value from sscanf tells you if there was, because it returns the number of items successfully scanned.
#include <stdio.h>
#include <stdlib.h>
void err(char *message)
{
puts(message);
exit(1);
}
int main(void)
{
double lowRadius = 0.0;
char inp[100];
char more[2];
int conv;
if(fgets(inp, sizeof inp, stdin) == NULL) {
err("Input unsuccesful");
}
conv = sscanf(inp, "%lf %1s", &lowRadius, more); // conv is number of items scanned
if(conv != 1) {
err("One input value is required");
}
if(lowRadius < 0.0 || lowRadius > 40.0) {
err("Number out of range");
}
printf("%f\n", lowRadius);
return 0;
}
I'm unsure about your stipulation of a single digit, since that won't allow your maximum value to be entered.
Read a whole line and convert it with strtod.
Alexander has the right approach, but doesn't give much detail. Here is how I would do it, using getline() to read the input, and then strspn() plus strtod() to parse the input that was read. If you are not familiar with working with pointers, this will be difficult to understand - but if you are learning C, you'll get there eventually:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
double lowRadius;
char *lineptr = NULL;
size_t n;
char *startptr;
char *endptr;
char *ws = " \t\n"; /* possible whitespace characters */
printf("Enter the low radius [0.0..40.0]: ");
while(1) {
/* free lineptr if set - neeeded if we iterate on error input */
if( lineptr ) {
free(lineptr);
lineptr = NULL;
}
/* now read a line of input */
while( getline(&lineptr, &n, stdin) == -1 ) {
/* error returned, just retry */
continue;
}
/* skip over any leading whitespace */
startptr = lineptr + strspn(lineptr,ws);
/* Now try to convert double */
lowRadius = strtod(startptr, &endptr);
if( endptr==startptr || endptr[strspn(endptr,ws)] != 0 ) {
/* either no characters were processed - e.g., the
line was empty, or there was some non-whitespace
character found after the number. */
printf( "Wrong input. Please enter one numerical value: ");
} else if( (lowRadius < 0.0) || (lowRadius > 40.0) ) {
printf( "Incorrect value. Please enter in range 0-40: " );
} else {
if( lineptr ) free(lineptr);
break;
}
}
printf( "value entered was %lf\n", lowRadius );
}

Resources