How to reject letter when requesting int in C - c

When I enter a letter the loop runs infinitely. Does a letter store as a zero when it is input as an int? How can I reject a non digit answer, just I have rejected an answer outside the range?
int main(int argc, const char * argv[]) {
// insert code here...
int categoryToScore;
int categoryScores = 6;
printf("Enter category to save score: ");
scanf("%d", &categoryToScore);
while (categoryToScore >= categoryScores || categoryToScore <= 0) {
printf("Error: invalid command. Enter 1-5 to save to an unused category\n");
printf("Enter category to save score: ");
scanf("%d", &categoryToScore);
}
return 0;
}
Just for background
I want to:
print a request an input that is between 1 and an upper bound
scanf for the input
check if the input is of a correct type and within the correct range
if it isn't then print an error message and go back to 1.
if it is then proceed

You are asking scanf to read a number from standard input. Scanf finds a non-digit character in the standard input and does not remove it from the standard input. Scanf fails and returns 0 (the number of fields successfully processed).
The next time you call scanf, it finds the same character at the start of standard input. So the process repeats indefinitely.
One solution is to read stdin one character at a time.
Another solution is to read (and discard) the one character from stdin before calling scanf again.
int main(int argc, const char * argv[]) {
// insert code here...
int categoryToScore;
int categoryScores = 6;
int scantRetVal;
printf("Enter category to save score: ");
scantRetVal = scanf("%d", &categoryToScore);
if (scantRetVal != 1) {
getchar(); // read and discard one character from stdin
categoryToScore = 0;
}
while (categoryToScore >= categoryScores || categoryToScore <= 0) {
printf("Error: invalid command. Enter 1-5 to save to an unused category\n");
printf("Enter category to save score: ");
scantRetVal = scanf("%d", &categoryToScore);
if (scantRetVal != 1) {
getchar(); // read and discard one character from stdin
categoryToScore = 0;
}
}
return 0;
}

Rather than fix this particular program I will show how to solve ANY similar problem using a concept called an "exit condition".
The idea of an exit condition is that you have an infinite loop and it has various exit conditions. Often there are two exit conditions: one for success and one for an error.
while( true ){ /* infinite loop */
char c = ... /* get the character you want */
if( c < '0' || c > '9' ){
printf( "invalid character, not a digit\n" );
continue; // get another character
}
... /* do whatever you with valid data */
if( c == '3' ) break; /* your exit condition, whatever it is */
if( c == '7' ) exit(0); /* exit the whole program */
}
Note: If you are accepting free form input (numbers and strings), scanf is probably not a good idea. scanf accepts very specific, well-formatted input. So if you ask for a %d, then there better be a %d (decimal number) in the input or you will have problems.
For example, if you accept numbers and strings, you should take everything as strings using fgets or something like that.
Here is a complete program that does what you want:
#include <stdio.h>
#include <stdbool.h>
int main(int argc, const char * argv[]) {
int iMaxScore = 6;
int charInput = 0;
int iInputValue = 0;
while( true ){
printf("Enter category to save score: ");
GetInput:
charInput = getchar();
if( charInput == 10 || charInput == 13 ) goto GetInput; /* ignore enter key */
if( charInput == 'q' ) break;
if( charInput < '0' || charInput > '9' ){
printf( "invalid entry, not a digit %d\n", charInput );
break;
}
iInputValue = charInput - '0';
if( iInputValue > iMaxScore ){
printf( "Error, input value exceeds maximum category %d\n", iMaxScore );
continue; /* try again */
}
printf( "you entered category %d\n", iInputValue );
/* continue ... */
}
return 0;
}

Related

c programming: Error handling. How do I stop characters from being entered into program

How I can exclude characters from being entered as a value in my programs?
Is there a way through the scanf function to recognize the input as a character and then write a printf to show an invalid value message? It would be more recognizing the character then printing the message I'm concerned with.
Edit:
So as asked, the below is my code for a program that first reads five numbers(each between 1 and 30).For each number read, the program should print a line containing that number of adjacent asterisks.
For this, if I enter a number value it causes the program to stop working. So if i could add a way to create "Try again" message or something similar when they are entered, this will stop it from having errors.
#include <stdio.h>
int main(void)
{
int number1 = 0; int counter;
int sentinelcount = 1;
printf("Please enter 5 values, between 1 and 30");
while (sentinelcount <= 5) {
printf("\n\nEnter number: \n"); /*prompt*/
scanf_s("%d", &number1); /*read an interger*/
sentinelcount++;
if (number1 < 1 || number1 > 30)
{
sentinelcount--;
printf("\nWrong Value\n");
}
if (number1 < 1 || number1 > 30)
{
printf("Enter within correct value range: 1 - 30! ");
}
else if (number1 >= 1 || number1 <= 30)
{
printf("Number of asterisks:\n");
for (counter = 1; counter <= number1;
counter++)
{
printf("*");
}
}
}
return 0;
How do I stop characters from being entered into program
Short of some magic hand that prevents the user from typing in non-numeric or a limited key board, the better approach is not to stop characters from being entered, but accept them as input and then detect invalid input.
I recommend to consume invalid input and alert the user of the issue.
A good first attempt is to read a line of input into a string with fgets().
Test for input, conversion success, extra junk and range.
char buf[80];
if (fgets(buf, sizeof buf, stdin)) { // TBD deal with lines longer than 79
If a line was read, process it with strtol(), sscanf(), etc. Use "%n" to detect where scanning ended. Perform error checking.
int num;
int n;
// If an integer was parsed with no trailing junk and in range ...
if (sscanf(buf, "%4d %n", &num, &n) == 1 && buf[n] == 0 &&
(num >= 1 && num <= 30)) {
Oh_Happy_Day(); // TBD code
} else {
Invalid_input(): // TBD code
}
One way to determine whether the user entered a character or a number is to call scanf with the %d conversion format specifier, and check the return value of scanf. If it returns 1, then the conversion format specifier was successfully matched. Otherwise, you print an error message and prompt the user again to enter input. For example:
#include <stdio.h>
int main( void )
{
int i;
//infinite loop, equivalent to while(1)
//repeat the loop until the input is valid
for (;;)
{
//prompt user for input
printf( "Please enter a number: " );
//attempt to read and convert user input
if ( scanf( "%d", &i ) == 1 )
{
//input was valid
break;
}
//print error message
printf( "Input was invalid, please try again!\n" );
//discard remainder of line
for ( int c; c = getchar(), c != '\n' && c != EOF; )
;
}
printf( "Input was successfully converted to the number %d.", i );
}
This is the output of the program:
Please enter a number: sjdfk
Input was invalid, please try again!
Please enter a number: erlh89
Input was invalid, please try again!
Please enter a number: 34
Input was successfully converted to the number 34.
However, this code has one problem: It will accept input such as "6sdfj23jlj" as valid input for the number 6:
Please enter a number: 6sdfj23jlj
Input was successfully converted to the number 6.
You would probably want to reject the input instead, in this case.
The function scanf will do this, because it is not line-based; it only processes as much input as it can to match the %d conversion format specifier.
One thing you could do to detect such invalid input would be to look at the remainder of the line, and verify that it is empty, apart from the newline character:
#include <stdio.h>
#include <stdbool.h>
int main( void )
{
bool successfully_matched = false;
bool found_newline = false;
int i;
//infinite loop, equivalent to while(1)
//repeat the loop until the input is valid
for (;;)
{
//prompt user for input
printf( "Please enter a number: " );
//attempt to read and convert user input
if ( scanf( "%d", &i ) == 1 )
successfully_matched = true;
//verify that remainder of line is empty
if ( getchar() == '\n' )
found_newline = true;
//break loop if everything was ok
if ( successfully_matched && found_newline )
break;
//print error message
printf( "Input was invalid, please try again!\n" );
//discard remainder of line, if necessary
if ( !found_newline )
{
for ( int c; c = getchar(), c != '\n' && c != EOF; )
;
}
}
printf( "Input was successfully converted to the number %d.", i );
}
Now, the program correctly rejects 6sdfj23jlj as invalid input:
Please enter a number: 6sdfj23jlj
Input was invalid, please try again!
Please enter a number:
However, this code will reject input such as 21 (note the space character after the number). I'm not sure if you want to reject input simply because of a trailing space. If you want to allow spaces and other whitespace characters, then this is possible too, but would require a bit more coding.
In your question, you stated that even if the input is a valid number, you want to additionally check whether the number is in a certain range. This can be accomplished too. However, since the code is starting to get complicated, it seems better to create a new function get_int_from_user to actually get a number from the user. After calling that function, we can then perform the range check, and if the number is not in the desired range, we print an error message and then call the function again.
#include <stdio.h>
#include <stdbool.h>
int get_int_from_user( const char *prompt )
{
bool successfully_matched = false;
bool found_newline = false;
int i;
//infinite loop, equivalent to while(1)
//repeat the loop until the input is valid
for (;;)
{
//prompt user for input
printf( "%s", prompt );
//attempt to read and convert user input
if ( scanf( "%d", &i ) == 1 )
successfully_matched = true;
//verify that remainder of line is empty
if ( getchar() == '\n' )
found_newline = true;
//break loop if everything was ok
if ( successfully_matched && found_newline )
break;
//print error message
printf( "Input was invalid, please try again!\n" );
//discard remainder of line, if necessary
if ( !found_newline )
{
for ( int c; c = getchar(), c != '\n' && c != EOF; )
;
}
}
return i;
}
int main( void )
{
int i;
//repeat until input is in the desired range
for (;;)
{
//read number from user
i = get_int_from_user( "Please enter a number: " );
//perform range check on number
if ( 1 <= i && i <= 30 )
{
//input is in the desired range
break;
}
//print error message
printf( "Number is not in the desired range, please try again!\n" );
}
printf( "The number %d is in the desired range.", i );
}
This program has the following output:
Please enter a number: 342
Number is not in the desired range, please try again!
Please enter a number: 27
The number 27 is in the desired range.
However, I generally do not recommend using scanf for line-based user input. As previously stated, the function scanf does not read one line of input at a time. This means that is can leave leftovers of the line on the input stream, which can be confusing to the programmer, and can lead to bugs, such as this one. See this question for more information on the disadvantages of using scanf.
For line-based user input, it is generally better to use the function fgets. Here is a very robust implementation of the function get_int_from_user which I copied from this previous answer of mine to another question. This function uses fgets and strtol instead of scanf, and performs extensive input validation and error checking:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p;
long l;
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "error converting string to number\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "number out of range error\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfj23jlj" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
If you want to exclude characters from being in your code you can use something like this:
unsigned long long answer1,answer2,answer3,c;
scanf("%*[^0123456789]%llu%*[^0123456789]%llu%*[^0123456789]%llu",&answer1,&answer2,&answer3);
printf("%lld %lld %lld",answer1,answer2,answer3);
return 0;
and if you want to print characters you shouldn't scan characters like this: scanf("%d"&a) instead you scan them with this: scanf("%c",&a) and the same point stands in print. but with this you can only scan one character at a time and if you want to scan more than that use more %c in the scanf and printf.

Wanted to check if the value entered is a number or else. "isdigit() is not working here as expected

I am stuck with a problem here in C. I am posting the question and the code I have written below. Here I have to enter 10 numbers in an array and then I need to check how many times a number appeared. But to verify that I have entered a number and not anything else, I have used "isdigit()" function. But this is of no use. Can anyone help me to solve it.
/*
(a) Ten numbers are entered from the keyboard into an array. The number to be searched is entered through the
keyboard by the user. Write a program to find if the number to be searched is present in the array and if it is present, display
the number of times it appears in the array.
*/
#include<stdio.h>
#include<ctype.h>
main()
{
int num[10];
int i, j, cnt=0;
char rept;
printf("Enter 10 numbers: \n\n");
for(i=0; i<=9; i++)
{
printf("Number %d = ", i+1);
scanf("%d", &num[i]);
fflush(stdin);
if ( !isdigit(num[i]) )
{
printf("OK\n");
}
else
{
printf("Invalid number. Enter again.\n");
i=i-1;
}
}
do
{
printf("\nEnter the number to be searched in array: ");
scanf(" %d", &j);
for (i=0 ; i<=24; i++)
{
if(num[i]==j)
cnt++;
}
if(cnt>0)
printf("\nNumber %d is present at %d places", j, cnt);
else
printf("\nNumber not present.");
printf("\n\nDo you want to search another number. Press Y to repeat. Any other key to exit");
fflush(stdin);
scanf("%c", &rept);
}while (rept=='y'||rept=='Y');
getch();
}
No you can't do that. isdigit() is supposed to work with characters and you passed a multigit integer variable.
What you can do is simply like this
if( scanf("%d",&a[i])== 1){
// you can be sure number is entered
}
And fflush(stdin) is undefined behavior.
So the use of scanf will be more prominent if you would do this
int clearstdin(){
int c;
while ((c = getchar()) != '\n' && c != EOF);
return (c == EOF);
}
In main()
int earlyend = 0;
for(size_t i=0; i<SIZE; i++){
...
...
int ret = scanf("%d",&a[i]);
while( ret == 0){
if( clearstdin() ){ /* EOF found */earlyend = 1; break; }
fprintf(stderr,"%s\n","Entered something wrong");
ret = scanf("%d",&a[i]);
}
if( earlyend ){ /*EOF found*/ }
if( ret == EOF) { /* Error occured */}
...
}
The %d conversion specifier will cause scanf to skip over any leading whitespace, then read a sequence of decimal digits, stopping at the first non-digit character. If there are no digit characters in the input (for example, you enter something like ”abc”), then nothing is read from the input stream, a[i] is not updated, and scanf will return 0 to indicate a matching failure.
So, you can do a test like
if ( scanf( “%d”, &a[i] ) == 1 )
{
// user entered valid input
}
But...
This doesn’t fully protect you from bad input. Suppose you enter something like ”123abc” - scanf will read, convert, and assign 123 and return a 1 indicating success, leaving ”abc” in the input stream to potentially foul up the next read.
Ideally, you’d like to reject the whole thing outright. Personally, I do this as follows:
char inbuf[SOME_SIZE]; // buffer to store input
if ( fgets( inbuf, sizeof inbuf, stdin ) ) // read input as text
{
char *chk; // use strtol to convert text to integer
int temp = (int) strtol( inbuf, &chk, 10 ); // first non-digit character written to chk
if ( isspace( *chk ) || *chk == 0 ) // if chk is whitespace or 0, input is valid
{
a[i] = temp;
}
else
{
// bad input
}
}
This still isn’t a 100% solution - it doesn’t make sure the user didn’t enter more characters than the buffer can hold, but it’s a step in the right direction.
Input validation in C is, frankly, a pain in the ass.

Re-prompting a user until he/she enters a positive integer value greater than 1

I'm solving CS50 (problemset 1) i.e water.c. It asks user to write a program that prompts the user for the length of his or her shower in minutes (as a positive integer) and then prints the equivalent number of bottles of water (as an integer).
1 min of shower = 12 bottles consumed
MAIN PROBLEM: The problem is that we have to ensure that the user inputs a positive number of minutes otherwise it keeps on re-prompting his back to input/scanf statement. As long as he enters he enters length<=0, I can re-prompt him back using while(length<=0) condition but as he enters a character i.e abc123 in input my code keeps on executing. Any solutions??
>
#include <stdio.h>
int main()
{ int length=0;
int min=12;
int bottle=0;
printf("Enter length of his or her shower in minutes");
scanf("%d", &length);
while (length <= 0){
printf("Enter length of his or her shower in minutes");
scanf("%d", &length);
}
bottle= (min*length);
printf("%d", bottle);
return 0;
}
You can solve this by reading a string first, and then extracting any number:
#include <stdio.h>
int main(void)
{
int length = 0;
char input[100];
while(length <= 0) {
printf("Enter length: ");
fflush(stdout);
if(fgets(input, sizeof input, stdin) != NULL) {
if(sscanf(input, "%d", &length) != 1) {
length = 0;
}
}
}
printf("length = %d\n", length);
return 0;
}
Program session:
Enter length: 0
Enter length: -1
Enter length: abd3
Enter length: 4
length = 4
Crucially, I always check the return value from scanf, the number of items successfully converted.
If you don't care about Inputs like 1f then the Above Answers are ok For you, but if you do not want to accept this kind of Input, then the following approach does something like that:
#include<stdio.h>
int checkInput(void);
int main(void){
int number = checkInput();
printf("\nYour number is\t%d\n",number);
return 0;
}
int checkInput(void){
int option,check;
char c;
do{
printf("Please type a number:\t");
if(scanf("%d%c",&option,&c) == 0 || c != '\n'){
while((check = getchar()) != 0 && check != '\n' && check != EOF);
printf("\tI sayed a Number please\n\n");
}else{
if ( option < 1){
printf("Wrong input!\n");
}else{
break;
}
}
}while(1);
return option;
}
Output:
Please type a number: 1f
I sayed a Number please
Please type a number: f1
I sayed a Number please
Please type a number: -1
Wrong input!
Please type a number: 1
Your number is 1
You don't need the first prompt outside the loop because you have already initialised length to zero, so the loop will prompt at least once.
On most platforms other then Wndows, you need to flush stdout to show text not terminated with a newline.
scanf will return so long as a newline character is buffered and %d alone will not consume the newline, so you need to ensure that any remaining characters up to and including the newline are flushed to prevent an endless loop.
It is good practice to check the return value from scanf() since it makes no guaranteed about not modifying its arguments even when a conversion fails.
It is not clear why min is a variable here sine it is initialised but never re-assigned, but presumably that may be the case in the final program?
#include <stdio.h>
int main( void )
{
int length = 0 ;
int min = 12 ;
int bottle = 0 ;
while( length <= 0 )
{
int converted = 0 ;
printf( "Enter length of his or her shower in minutes: " ) ;
fflush( stdout ) ;
converted = scanf( "%d", &length ) ;
if( converted != 1 )
{
length = 0 ;
}
while( (c = getchar()) != '\n' && c != EOF ) { } // flush line buffer
}
bottle = min * length ;
printf( "%d", bottle ) ;
return 0;
}
int min = 0;
do {
printf("Enter minutes: ");
scanf("%i", &min);
} while(min <= 0);
//programs resumes after this.

Difficulty using scanf for input

Can someone help me to solve my problem? I have a problem with %[^\n]. When I try to enter a false input the program loop the warning that I wrote, but if I use %s and I enter my string the next statement is not working properly.
#pragma warning (disable:4996)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("input name [1..30 char]: ");
scanf("%[^\n]", name); fflush(stdin);
if ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) {
flag = 1;
}
else {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z)\n");
}
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
else {
flag1 = 1;
}
} while (flag == 0 || flag1 == 0);
do {
printf("Input phone number[6..12 digits]: ");
scanf("%s", number); fflush(stdin);
for (i = 0; i < strlen(number); i++) {
if (number[i] >= '0' && number[i] <= '9') {
flag2 = 1;
}
else {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9)\n");
}
if (strlen(number) >= 6 && strlen(number) <= 12) {
flag3 = 1;
}
else {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits\n");
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
getchar();
return 0;
}
Oh by the way, the problem might simply be that the scanf call leaves the newline in the buffer, and if you loop and try again the first character seen will be the newline and scanf should not read any thing.
There are two things you should do: First check what scanf returns, it should return 1 if it read a string. Secondly you should tell scanf to discard any possible leading white-space by adding a space first in the format string: " %[^\n]".
Most scanf formats automatically skips leading white-space, but not when using the "%[" or "%c" formats.
Also, to not worry about writing out of bounds of the array, you should add a length modifier to make sure that scanf doesn't read more input than it can write: " %29[^\n]". If the length of the string is 29 after this, then you should probably read until you reach the end of the line, character by character.
Here is your program fixed:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
// In case you need this -- not needed for this case
void discard_input()
{
char c;
while( ( c = getchar() ) != '\n' && c != EOF );
}
void remove_trailing_newline(char * s)
{
char * ch = s + strlen( s ) - 1;
while( ch != s ) {
if ( *ch == '\n' ) {
*ch = 0;
break;
}
--ch;
}
return;
}
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("\nInput name [1..30 char]: ");
fgets( name, 30, stdin );
remove_trailing_newline( name );
flag1 = flag = 1;
if ( !isalpha( name[ 0 ] ) ) {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z), found: %s\n", name );
}
// impossible
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
} while (flag == 0 || flag1 == 0);
do {
printf("\nInput phone number[6..12 digits]: ");
fgets( number, 12, stdin );
remove_trailing_newline( number );
flag2 = flag3 = 1;
int len_phone = strlen( number );
for (i = 0; i < strlen(number); i++) {
if ( !isdigit( number[ i ] ) ) {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9), found:'%s'\n", number);
}
if ( len_phone < 6 || len_phone > 12) {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits, found: %d\n", len_phone );
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf( "Name: '%s'\n", name );
printf( "Phone: '%s'\n", number );
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
return 0;
}
You can find the program here.
The fixings are more or less interesting, I enumerate they here:
At first, I thought that the problem was that the trailing new line was being left in the input buffer. fflush(stdin) is actually undefined behaviour in C, since the fflush() function is there for output streams. Anyway, I included the code in question 12.26b of the comp.lang.c FAQ, since I think it is interesing to have it as reference. Then, I decided to change scanf() with fgets(). This is due to the scanf() taking spaces as delimiters, so you wouldn't be able to write a complete name, i.e., name and surname. Remember that gets() is not an option, since it writes the input past the limit of the buffer. Actually, fgets() solves this by letting us define a limit of chars to read. The problem is that fgets() also includes the '\n' in the buffer, so, that's why I included the remove_trailing_newline() function. Tricky, isn't it?
You added a condition to check whether the name input had more than thirty chars. Actually, this is impossible to check in your program. First of all, fgets() will read 29 chars + the final char mark (0). Secondly, if you were actually allowing to input more than 30 chars, then the input would be written past the size of the buffer, which is undefined behaviour (crashes in most cases). You would have to use something more complex, like std::string in C++, and then check its length. Or maybe use a third party expandable string for C. Or roll out your own expandable string...
You can decide whether there is an alphabetic char or a digit by using isalpha(c) and isdigit(c) functions.
When you are going to use a value many times, such as strlen(name), then you should precompute it and store it in a local variable. Though a good compiler (its optimizer) will detect this situation and solve it for you, you never know which compiler is going to compile your code, and how advanced it is. Also, there is nothing wrong making things easier for the optimizer.
When you have a situation in which you set a flag for signaling an error condition, it is easier to set it to the "no error" value before checking anything, and solely in case of an error, set it to the "error" value. This will be easier to read, and therefore, to understand.
Hope this helps.

Check if input is a string (4 characters only) and if not return to input again

My aim is to accept 4-digit numbers, and 4-character strings (string should not contain digits or special characters)
If an invalid input is given the program should not terminate and it must allow the user to enter the details and continue until he wish to terminate.
I am able to find whether the input is a digit.
if(scanf("%d",&input)!=1)
{
printf("enter the number please");
... // I have option to re enter using while and flags
}
else
{
// I continue my work
...
}
To check it is four digits I have tried using the commands
i=0;
num = input;
while(num>0)
{
i = i+1;
num = num/10;
}
if(i==4){
...//I continue
}
else
printf("please enter four digit");
I have no idea of checking the same for characters. (I know how to check its length using strlen())
Please help me with the code in C. (Also help me to reduce/optimize the above logic to check whether the input is a 4-digit number)
I believe you want 2 inputs a number and a string. You can do that as
int number= 0;
char string[10] = { 0 };
do {
printf("please enter four digit");
scanf("%d", &number);
if(number >=1000 && number<= 9999)
break;
} while(1);
do {
printf("please enter four character string");
fgets(string, sizeof(string), stdin);
if(strlen(string) == 4)
break;
} while(1);
To check it is four digit number you can simply put a check whether the number lies between 1000 and 9999. (I am assuming you don't want the number to start with 0.)
strtol can help:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char s[32], *p;
int x;
fgets(s, sizeof(s), stdin);
if ((p = strchr(s, '\n')) != NULL)
*p = '\0';
x = (int)strtol(s, &p, 10);
if ((p - s) == 4) {
printf("%d\n", x);
} else {
printf("Please enter four digit\n");
}
return 0;
}
char input[16];
int ok = 1, k = 0;
if (scanf("%s", input) > 0 && strlen(input) == 4) {
// check if it's a word
for (; k < 4; k++)
if (!isalpha(input[k])) {
// check if it's a number
for (int k = 0; k < 4; k++)
if (!isdigit(input[k]))
ok = 0;
break;
}
}
else ok = 0;
if (!ok)
printf("invalid input, please enter a 4-digit number or 4-letter word");
else {
printf("valid input");
...
}
You can use gets()1 fgets() to get the whole line and check line length. If the first character is between '0' and '9' then check the remaining if they are 3 numbers too. If the first character is a valid character in string then check the 3 remaining chars if it's also valid in string.
1See Why is the gets function so dangerous that it should not be used?

Resources