I've recently started programming and currently i'm working on a game.
In this game i need to compare current input with the last input from an array.
It's really easy in number systems up to decimal.
Here is the code that i've written and works with numbers from systems up to decimal.
#include <stdio.h>
#define Max_size 256
#define N 36
void Game(int NumberSystem,int MaxRepetitions,char *Player1,char *Player2);
int main (void)
{
int temp,status,NumberSystem,MaxRepetitions ;
char Player1 [Max_size] ;
char Player2 [Max_size] ;
printf("Please enter the first player's name\n");
scanf("%s",&Player1);
printf("Please enter the second player's name\n");
scanf("%s",&Player2);
printf("Please enter a Number System between %d and %d\n",4,35);
status = scanf("%d",&NumberSystem );
while( NumberSystem > 35 || NumberSystem < 4 || status != 1 )
{
while((temp=getchar()) != EOF && temp != '\n');
printf("Please enter a valid Number System \n");
status = scanf("%d", &NumberSystem );
}
printf("Please enter a Number of maximum repetitions\n");
status = scanf("%d",&MaxRepetitions);
while( (MaxRepetitions<= 0) || (status != 1) )
{
while((temp=getchar()) != EOF && temp != '\n');
printf("Please enter a valid number of maximum repetitions\n");
status = scanf("%d",&MaxRepetitions);
}
Game(NumberSystem,MaxRepetitions,Player1,Player2);
}
void Game(int NumberSystem,int MaxRepetitions,char *Player1,char *Player2)
{
int status,counter,k,i,temp;
char fnumber,number;
counter = k = 1;
int *array1 = malloc(MaxRepetitions*NumberSystem*sizeof(int));
int *array2 = malloc(NumberSystem*sizeof(int));
char CharArray[N] = {'0','1','2','3', '4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
for(i=0; i<NumberSystem*sizeof(int),i++;)
array2[i] = 0;
printf("Let's start the game! %s begins.\n",Player1);
status = scanf("%d",&fnumber);
while(status != 1 || fnumber <= 0 || fnumber>NumberSystem-1)
{
while((temp=getchar()) != EOF && temp != '\n');
printf("First number must be a positive decimal number between %d and %d\n",1,NumberSystem-1);
status = scanf("%d", &fnumber);
}
array1[0] = fnumber;
array2[fnumber]++;
while( array2[number] < MaxRepetitions)
{
status = scanf("%d",&number);
while(status != 1 || number < 0 || number>NumberSystem-1 || ( (array1[k-1]!= NumberSystem-1) && (array1[k-1] >= number) ) )
{
while((temp=getchar()) != EOF && temp != '\n');
printf("You must enter a number greater than %d and smaller or equal to %d\n",array1[k-1],NumberSystem-1);
status = scanf("%d", &number);
}
array2[number]++;
array1[k] = number;
k++;
counter++;
}
if(counter%2 == 0)
{
printf("%s entered %d for the %dth time and exceeded the possible limit. %s won!",Player2,array1[k-1],MaxRepetitions,Player1);
}
else
{
printf("%s entered %d for the %dth time and exceeded the possible limit. %s won!",Player1,array1[k-1],MaxRepetitions,Player2);
}
free (array1);
free (array2);
}
Problem is i'd like it to be possible to play with greater numeric systems for example hexadecimal. I'm stuck at comparing value of the currently entered letter with letter that was entered before.
I'm seeking for any advice or suggestions.
Also if i did something really dumb in the first code (which probably i did) i would be glad to hear constructive criticism from you guys.
Thank you!
Here is the code to the "2nd" version where i tried to make this work with greater numeric systems. It's buggy and i don't know what have i done wrong.
#include <stdio.h>
#define Max_size 256
#define N 36
void Game(int NumberSystem,int MaxRepetitions,char *Player1,char *Player2);
int main (void)
{
int temp,status,NumberSystem,MaxRepetitions ;
char Player1 [Max_size] ;
char Player2 [Max_size] ;
printf("Please enter the first player's name\n");
scanf("%s",&Player1);
printf("Please enter the second player's name\n");
scanf("%s",&Player2);
printf("Please enter a Number System between %d and %d\n",4,35);
status = scanf("%d",&NumberSystem );
while( NumberSystem > 35 || NumberSystem < 4 || status != 1 )
{
while((temp=getchar()) != EOF && temp != '\n');
printf("Please enter a valid Number System \n");
status = scanf("%d", &NumberSystem );
}
printf("Please enter a Number of maximum repetitions\n");
status = scanf("%d",&MaxRepetitions);
while( (MaxRepetitions<= 0) || (status != 1) )
{
while((temp=getchar()) != EOF && temp != '\n');
printf("Please enter a valid number of maximum repetitions\n");
status = scanf("%d",&MaxRepetitions);
}
Game(NumberSystem,MaxRepetitions,Player1,Player2);
}
void Game(int NumberSystem,int MaxRepetitions,char *Player1,char *Player2)
{
int status,counter,k,i,temp;
char fnumber,number;
counter = k = 1;
char *array1 = malloc(MaxRepetitions*NumberSystem*sizeof(char));
int *array2 = malloc(NumberSystem*sizeof(int));
char CharArray[N] = {'0','1','2','3', '4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
for(i=0; i<NumberSystem*sizeof(int),i++;)
array2[i] = 0;
printf("Let's start the game! %s begins.\n",Player1);
//scanf("%c",&fnumber); // This part is ignored completely i don't know why
status = 0;
// for(i=0; i<NumberSystem-1; i++)
//{if(fnumber == CharArray[i]) status = 1;}
printf("Current status : %d\n",status);
while(status == 0)
{
while((temp=getchar()) != EOF && temp != '\n');
scanf("%c", &fnumber);
for(i=0; i<NumberSystem-1; i++)
if(fnumber == CharArray[i]) status = 1;break;
printf("First number must be a positive decimal number between %d and %d (in %d number system)\n",1,NumberSystem-1,NumberSystem);
}
array1[0] = fnumber;
array2[fnumber]++;
printf("Przed druga petla array1[0] : %c,array2[fnumber] : %d\n",array1[0],array2[fnumber]);
while( array2[k] < MaxRepetitions)
{
scanf("%c",&number);
status = 0;
for(i=0; i<NumberSystem-1; i++)
if(number == CharArray[i]) status = 1;
while(status == 0 || ( (array1[k-1] != CharArray[NumberSystem-1]) && (array1[k-1] >= number) ) )
{
while((temp=getchar()) != EOF && temp != '\n');
printf("You must enter a number greater than %c and smaller or equal to %d\n",array1[k-1],NumberSystem-1);
scanf("%c", &number);
status = 0;
for(i=0; i<NumberSystem-1; i++)
if(number == CharArray[i]) status = 1;break;
}
array2[number]++;
array1[k] = number;
k++;
counter++;
}
if(counter%2 == 0)
{
printf("%s entered %d for the %dth time and exceeded the possible limit. %s won!",Player2,array1[k-1],MaxRepetitions,Player1);
}
else
{
printf("%s entered %d for the %dth time and exceeded the possible limit. %s won!",Player1,array1[k-1],MaxRepetitions,Player2);
}
free (array1);
free (array2);
}
As far as I can understand what you want to do, you are not far from the solution. But I would recommend to use %1s instead of %c to read your characters. %c accept any characters including blank and newline. In the opposite, %1s will skip all eventual blanks and newline.
Simply, as %1s gives a null terminated string, you have to use an array (char anumber[2];), read one character into the array (the second will be\0`) and affect it to the char you use. For example, you have just to replace
scanf("%c", &fnumber);
with
scanf("%1s", anumber);
fnumber = anumber[0];
Related
I have an integer 'n' that is responsible for amount of numbers to enter later on.
I need to check for any incorrect inputs here.
The first scanf for 'n' works fine, but the second has some flaws.
The case is following:
n = 3 (e.g.) - doesn't matter
Then I want to scanf: 1 2 3 4
It will be scanned first 3 values but I need to throw out an error.
Same goes with: 1 2 3.5 - (last number is float but it still reads 3)
and with a char: 1 2 3g
if (scanf("%d", n) == 1 && getchar() == '\n') {
if (n > NMAX || n < 0) {
error = 1;
return;
}
for (int i = 0; i < n; i++) {
if (scanf("%d", p) == 1) {
The ONLY correct input is the exact same amount of integer numbers (equals to 'n') to scan in a for loop.
UPD: I can use only <stdio.h> library as well as only scanf.
Create a helper function to read an int and validate it.
The key is that to validate input, form a helper function that you can improve as needed, like using fgets() rather than scanf() once the poor "only scanf" requirement is removed.
// Sample
// Return 1 on success
// Return EOF on end-of-file
// Else return 0
int read_int(int *i, int min, int max, int line) {
long long num;
int result = scan("%18lld", &num); // Accept many out of int range input
if (result == EOF) return result; // or if (result < 0)
if (line) {
// consume the rest of the line
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
if (!isspace(ch)) { // or `ch != ' ' && `ch != '\t' && ...
result == 0;
}
}
}
if (result == 1) {
if (num < min || num > max) {
return 0;
}
*i = (int) num;
}
return result;
}
Sample usage
if (read_int(&n, 0, NMAX, 1) != 1) {
error = 1;
return;
}
for (int i = 0; i < n; i++) {
if (read_int(&p, INT_MIN, INT_MAX, i + 1 == n) != 1) {
error = 1;
return;
}
...
Note: read_int() does not catch all errors, just many of them. Easy enough to improve, once all OP's limitations and goals are known.
Try using scansets with scanf. %1[\n] will scan up to one character that is a newline. %99[ \t] will scan up to 99 characters that are space or tab. If the character is not a newline, space or tab, it is replaced in the input stream.
If scanf with %d can't scan an int, it will return 0. scanf could also return EOF.
fgets and parse with strtol or others is the better solution.
#include <stdio.h>
int main ( void) {
char space[100] = "";
char newline[2] = "";
int number = 0;
int count = 0;
int quantity = 3;
printf ( "enter %d integers\n", quantity);
while ( 1) {
if ( 1 == scanf ( "%d", &number)) {
++count;
}
else {
printf ( "could not parse an integer\n");
break;
}
scanf ( "%99[ \t]", space);
if ( 1 == scanf ( "%1[\n]", newline)) {
if ( count == quantity) {
printf ( "scanned %d integers\n", quantity);
break;
}
else if ( count > quantity) {
printf ( "too many integers\n");
break;
}
else printf ( "enter another integer\n");
}
}
return 0;
}
Check if this works
while(n-1)
{
scanf("%d ",p);
n-=1;
}
scanf("%d",p);
//After this you can scan again to check if there is anything extra in input
//and throw error accordingly
I have a convoluted plan for a program.
I would like to have datasets of three values be stored in different arrays, i.e the first value be stored in the first array, the second value in the second array and the third in the third array.
For example:
"How often would you like to repeat the program"
2
"Enter the first value:"
1
"Enter the second value:"
2
"Enter the third value:"
3
"Enter the first value:"
4
"Enter the second value:"
5
"Enter the third value:"
6
The output should be something like this
a_arr = [1 4]
b_arr = [2 5]
c_arr = [3 6]
I have come up with this code but I can't seem to get it to work.
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 255
//validation function
int a_arr[MAX_SIZE]; // Declare an array of MAX_SIZE
int b_arr[MAX_SIZE]; // Declare an array of MAX_SIZE
int c_arr[MAX_SIZE]; // Declare an array of MAX_SIZE
int i;
int checkInput0(void);
float checkInput1(void);
float checkInput2(void);
float checkInput3(void);
a_arr[] = checkInput1;
b_arr[] = checkInput2;
c_arr[] = checkInput3;
int main()
{
int repeats = 0, counter = 0;
//Amount of triangles
repeats = checkInput0();
// create arrays for all values
do {
i = counter;
for(i=0; i<repeats; i++)
{
scanf("%f", &a_arr[i]);
}
for(i=0; i<repeats; i++)
{
scanf("%f", &b_arr[i]);
}
for(i=0; i<repeats; i++)
{
scanf("%f", &c_arr[i]);
}
counter++;
}while(counter < repeats);
do {
printf("%f\n",a_arr );
printf("%f\n",b_arr );
printf("%f\n",c_arr );
counter++;
}while(counter < repeats);
return 0;
}
// Validate Value of a
float checkInput1(void){
float option1,check1;
char c;
do{
printf("Enter the first side of the triangle");
if(scanf("%f%c",&option1,&c) == 0 || c != '\n') {
while((check1 = getchar()) != 0 && check1 != '\n' && check1 != EOF);
printf("\t[ERR] Invalid number for the triplet.\n");
}else {
break;
}
}while(1);
// printf("returning the value of option, which is %f", option);
return option1;
}
// Validate Value of b
float checkInput2(void){
float option2,check2;
char c;
do{
printf("Enter the second side of the triangle");
if(scanf("%f%c",&option2,&c) == 0 || c != '\n'){
while((check2 = getchar()) != 0 && check2 != '\n' && check2 != EOF);
printf("\t[ERR] Invalid number for the triplet.\n");
}else{
break;
}
}while(1);
//printf("returning the value of option, which is %f", option2);
return option2;
}
// Validate Value of c
float checkInput3(void){
float option3,check3;
char c;
do{
printf("Enter the third side of the triangle");
if(scanf("%f%c",&option3,&c) == 0 || c != '\n'){
while((check3 = getchar()) != 0 && check3 != '\n' && check3 != EOF);
printf("\t[ERR] Invalid number for the triplet.\n");
}else{
break;
}
}while(1);
// printf("returning the value of option, which is %f", option);
return option3;
}
Note: the functions are there for validation such that the input is a number.
All help is greatly appreciated
I think you may have complicated this.
You can do something like this.
printf("How many...");
scanf("%d", &num); //num is the user input
int i;
for(i=0; i<num; i++)
{
printf("enter first number");
a_arr[i] = checkInput1();
printf("enter first number");
b_arr[i] = checkInput2();
printf("enter first number");
c_arr[i] = checkInput3();
}
The last 3 declarations before main have no sense.
Answering the question, the pseudocode is simple. You have 3 arrays, so when the iterator of scans reach i = 3n-1, being n= 0,1,2,3,4..., then the index is increased.
E.g., scanf 0, 1 and 2 are all saved in index 0 of the respective array (2 = 3n-1, n being 1); scanf 3,4 and 5 are all saved in index 1 of the respective array (5 = 3n-1, n being 2) and so on...
I think you are wasting lot of memory doing this statically, simple malloc can save lot of memory and time(speed of execution i meant)
printf("How many...");
scanf("%d", &num); //num is the user input
int * a_arr = (int *)malloc( num * sizeof(int));
int * b_arr = (int *)malloc( num * sizeof(int));
int * c_arr = (int *)malloc( num * sizeof(int));
int count;
for(count=0; count<num; count++)
{
printf("enter first number");
scanf("%d",a_arr[count]);
printf("enter first number");
scanf("%d",b_arr[count]);
printf("enter first number");
scanf("%d",c_arr[count]);
}
//print or whatever you wanna do processing on it
I want to be able to input a character and the program would printf("Invalid entry. \nPlease try again:\n") but I also need to be able to input 0, I do not see why it does not work, the way I have it set up a the moment.
for (i=0; i<*r; i++)
{
printf("Please enter the number of 1's in row %d :\n", (i+1));
scanf("%s", &str);
if(atoi(str)!=sizeof(char))
{
while(atoi(str)==0)
{
printf("Invalid entry. \nPlease try again:\n");
scanf("%s",str);
}
f = atoi(str);
}
else
f=0;
if (f>0)
{
printf("Please enter column location of the 1's in row %d : \n", (i+1));
for (j=0; j<f; j++)
{
scanf("%d", &g);
p[i][g-1]= 1;
}
}
}
atoi() always returns zero if the string does not start with valid decimal digits, so cannot be used to distinguish between invalid input and a valid '0' input.
Instead use scanf() with the "%d" format specifier and check its return value:
int i = 0 ;
do
{
int check = scanf( "%d", &i ) ;
while( getchar() != '\n' ) ; // flush until end of line
if( check == 0 )
{
printf( "Invalid entry. \nPlease try again:\n");
}
} while( check == 0 ) ;
// Now work with the valid input integer value in i ...
Consider putting the code in a function so you don't have to repeat yourself:
int getIntegerInput()
{
int i = 0 ;
do
{
int check = scanf( "%d", &i ) ;
while( getchar() != '\n' ) ; // flush until end of line
if( check == 0 )
{
printf( "Invalid entry. \nPlease try again:\n");
}
} while( check == 0 ) ;
return i ;
}
I didn't understand why won't you get an integer as your input and then you can get rid of converting String to Integer.
int num;
printf("Please enter the number of 1's in row %d :\n", (i+1));
scanf("%d", &num);
while(!num)
{
printf("Invalid entry. \nPlease try again:\n");
scanf("%d", &num);
}
You found out why atoi() is bad. atoi() doesn't do any error reporting such as integer overflow, invalid input etc and it can't distinguish a valid 0 input and a conversion failure.
Use strto*l() functions to do the conversion as they can detect conversion failures. Your input reading can be done as follows:
#include <stdio.h>
#include <stdlib.h>
#include<limits.h>
#include<errno.h>
....
for(;;) {
scanf("%s", str);
errno=0;
long f = strtol(str, &endp, 0);
if (endp == str || *endp != 0 ||
(errno == ERANGE && (f == LONG_MAX || f == LONG_MIN)) ||
(errno != 0 && f == 0)) {
printf("Invalid entry. \nPlease try again:\n");
}
else break;
}
I'm just a beginner and I'm trying to use whatever I know to make a simple program that:
Asks the user to input the letter 'S' or 's'. The program loops if 's' is not input. If the user does input 's', the program then
Asks the user to input a number, 1 or 2. The program loops if the incorrect number is input.
The problem I'm having is that after 's' is successfully input and the user is asked to enter a number, if an incorrect number is input (not 1 or 2) the program asks the user to input a letter again from the beginning which is incorrect. The program loops from the very beginning and doesn't work anymore. Can anyone help me fix this please?
#include <stdio.h>
#include <ctype.h>
int function(int num);
int main()
{
char input,ch,temp,c[64],exit;
int i,invalid,num,index,flag,day;
invalid = 0;
num = 0;
size_t length = 0;
index = 0;
flag = 0;
do
{
puts("Enter the letter S to start the program:");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
{
if(isalpha(input)==0)
{
printf("Invalid input. Please input something.\n");
continue;
}
if(input == 'S' || input == 's')
{
printf("\nProgram start.");
while( sscanf(c, "%d", &num) != 1)
{
length = 0;
flag = 0;
num = 0;
printf("\nEnter 1 for Module A. Enter 2 for Module B. Enter here: ");
fgets(c, 63, stdin);
length = strlen(c);
for(index = 0; index < length; ++index)
{
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
}
if( flag)
{
printf("\nInvalid character\n");
continue;
}
if( sscanf(c, "%d", &num) != 1)
{
printf("\nNo input detected.");
continue;
}
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
}
}
else
{
printf("\nInvalid input.");
continue;
}
}
}
while(1);
}
Make the scanf into like this.
scanf(" %c",&input);
Then While getting the input from the user using fgets It will place the new line character into that buffer. So this will lead to fails this condition.
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
So make the this condition into like this.
length=strlen(c)-1;// to skip the new line character
Or else to like this.
length=strlen(c);
if ( c[length] == '\n' )
c[length]='\0';
Output After placing this,
Enter the letter S to start the program:
S
Program start.
Enter 1 for Module A. Enter 2 for Module B. Enter here: 1
Module A Selected.
Make this in you code.
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
else if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
else
{
printf("\nInvalid option\n");
c[0]='\0'; // It is for satisfy the second while loop condition.
continue;
}
Note that the loop:
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
is limited to the one line by the semicolon at the end. The following code is not the body of the loop, despite indentation trying to pretend that it is.
Also note that getchar() returns an int, not a char; you cannot reliably assign the result to a char and then test it for EOF. Depending on the platform, you will either never detect EOF at all or you will misdetect EOF when some other character (often ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) is typed. You must use int ch;.
Here. I fixed the problem using the following code. This way the code does the following:
Scans letters 'S' or 's'. Keeps looping if these are not entered.
Scans either number 1 or 2. Keeps looping until either number is entered and then exits.
The program does not loop from the very beginning (by outputting "Enter 'S' to start program), if any number other than 1 or 2 in entered in part 2 of the program. This was the problem originally.
The following is the correct code:
#include <stdio.h>
#include <ctype.h>
int function();
char input,temp,c[64],ch,exit;
int i,invalid,num,index,flag,start;
start = 0;
invalid = 0;
num = 0;
size_t length = 0;
index = 0;
flag = 0;
int main()
{
do
{
puts("Enter the letter S to start the program: ");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
{
if(isalpha(input)==0)
{
printf("Invalid input. Please input something.\n");
continue;
}
if(input == 'S' || input == 's')
{
printf("\nProgram start.");
start = 1;
if(start == 1)
{
function();
return(0);
}
}
else
{
printf("\nInvalid input.");
continue;
}
}
}
while(1);
}
int function()
{
while( sscanf(c, "%d", &num) != 1)
{
length = 0;
flag = 0;
num = 0;
printf("\nEnter 1 for Module A. Enter 2 for Module B. Enter here: ");
fgets(c, 63, stdin);
length = strlen(c);
length --;
for(index = 0; index < length; ++index)
{
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
}
if( flag)
{
printf("\nInvalid character\n");
continue;
}
if( sscanf(c, "%d", &num) != 1)
{
printf("\nNo input detected.");
continue;
}
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
else if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
else
{
printf("\nInvalid option\n");
c[0]='\0'; // It is for satisfy the second while loop condition.
continue;
}
}
}
I am trying to get my input validated between a range and to type integer. Currently I have the following code.The range needed is 0-100 for X and 0-50 for Y.
for(loop=0;loop<3;loop++){
printf("\n\nEnter MAGENTA X coordinate from 0 to 100:\n");
scanf("%d",&mg[loop].x);
printf("\nEnter MAGENTA Y coordinate from %d to 50:\n");
scanf("%d",&mg[loop].y);
}
I need the option of the user ending the input prematurely with perhaps by entering "end" or something like that. This should then move onto the next color which is Yellow.
Does anyone know how I could implement this using scanf?
------EDIT-----
I've implemented the following and it defaults to "failure". I increased the handle to 2 and got the error end is being use without being initialized.
for(loop=0;loop<3;loop++){
printf("\n\nEnter MAGENTA X coordinate from 0 to 100:\n");
if(scanf("%d%c",&mg[loop].x) != 1 || end !='\n')
printf("failure");
else
printf("\nEnter MAGENTA Y coordinate from 0 to 50:\n");
scanf("%d",&mg[loop].y); /*Use the same validation here as above*/
}
You can use scanf, that's fine. Why not? scanf returns the number of items successfully read, so that 0 indicates a format error. After such you want to discard the remaining input before asking for another one.
Then you test the read variables against the boundaries.
You can specify a special value for the user's wish to exit, perhaps some string like "exit" which makes scanf fail whereupon you check whether it's "exit". The break command comes handy when you want to exit from a loop.
You can use scanf() but error reporting tends to be trickier. Minimally adapting your code:
for (loop = 0; loop < 3; loop++)
{
int rc;
printf("\n\nEnter YELLOW X coordinate from 0 to 100:\n");
while ((rc = scanf("%d", &ylw[loop].x)) == 1 &&
(ylw[loop].x < 0 || ylw[loop].y > 100)
printf("Enter a value between 0 and 100\n");
if (rc != 1)
{
fprintf(stderr, "Error reading x-value.\n");
break;
}
printf("\nEnter YELLOW Y coordinate from 0 to 50:\n");
while ((rc = scanf("%d", &ylw[loop].y)) == 1 &&
(ylw[loop].x < 0 || ylw[loop].y > 50)
printf("Enter a value between 0 and 50\n");
if (rc != 1)
{
fprintf(stderr, "Error reading y-value.\n");
break;
}
}
However, that repetition cries out for a function — albeit one with a modestly complex interface:
int prompt_for(const char *what, int min, int max, int err)
{
int value;
int rc;
printf("\nEnter %s from %d to %d:", what, min, max);
while ((rc = scanf("%d", &value)) == 1 && (value < min || value > max))
printf("Enter a value between %d and %d\n", min, max);
if (rc != 1)
{
fprintf(stderr, "Error reading %s.\n", what);
return err;
}
return value;
}
Sample use:
for (loop = 0; loop < 3; loop++)
{
ylw[loop].x = prompt_for("YELLOW X coordinate", 0, 100, -1);
if (ylw[loop].x == -1)
break;
ylw[loop].y = prompt_for("YELLOW Y coordinate", 0, 50, -1);
if (ylw[loop].y == -1)
break;
}
If you were using fgets() and sscanf(), you'd use:
int prompt_for(const char *what, int min, int max, int err)
{
int value;
int rc;
char line[4096];
printf("\nEnter %s from %d to %d:", what, min, max);
while (fgets(line, sizeof(line), stdin) != 0 &&
(rc = sscanf(line, "%d", &value)) == 1 &&
(value < min || value > max))
printf("Enter a value between %d and %d\n", min, max);
if (rc != 1)
{
fprintf(stderr, "Error reading %s.\n", what);
return err;
}
return value;
}
This isn't making much use of fgets(), though; it scores when you want multiple data items on a single line, because then you can report the whole line that was entered.
Warning: none of this code has been compiled
If you want to enforce that every input is on its own line of input (which is advisable when alternating prompt and reading from stdin), I recommend first reading a line into a temporary line buffer and then scanning that buffer with sscanf. Then check whether your input is valid in a last step.
Because this can clutter up your code, you might wright your own function for this:
/*
* Read an integer from stdin. Repeat until a valid number between
* lo and hi has been given. Returns 0 when a number was read and
* -1 when the input has run out.
*/
int read_int(int *x, int lo, int hi)
{
char buf[80];
char c;
for (;;) {
if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;
if (sscanf(buf, "%d %c", x, &c) != 1 || *x < lo || *x > hi) {
printf("Please enter a single value between %d and %d.\n",
lo, hi);
} else {
break;
}
}
return 0;
}
You can then read your coordinates like so:
struct Coord ylw[3] = {{0, 0}};
int i;
for(i = 0; i < MAX; i++) {
printf("\n\nEnter YELLOW X coordinate #%d from 0 to 100:\n", i);
if (read_int(&ylw[i].x, 0, 100) < 0) break;
printf("\nEnter YELLOW Y coordinate #%d from 0 to 50:\n", i);
if (read_int(&ylw[i].y, 0, 50) < 0) break;
}
If the user types an eod-of-file character (Ctrl-D un Unix, Ctrl-Z on Windows), the number of coordinates can be cut short. If you want to end the input with a certain keyword, say "end", you can add this to your function by reading a string and checking first:
int read_int(int *x, int lo, int hi)
{
char buf[80];
char key[5];
char c;
for (;;) {
if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;
if (sscanf(buf, "%4s ", key) == 1) {
if (strcmp(key, "end") == 0) return -1;
if (strcmp(key, "END") == 0) return -1;
}
if (sscanf(buf, "%d %c", x, &c) != 1 || *x < lo || *x > hi) {
printf("Please enter a single value between %d and %d.\n",
lo, hi);
} else {
break;
}
}
return 0;
}
(Scahhing a string from a string may seem redundant, but this way the user can type "end" after some spaces. You can also use a case-insensitive string comparison function.)