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
Related
So I'm trying to do a program that reads a sequence of numbers separated by spaces and new lines. The output should be the same sequence, but erasing unnecessary zeros(The sequence of charachters 'EOF' ends the program). Per example
01492 102934 should come out as 1492 102934
9312 0 01923 should come out as 9312 0 1923
0001249 0000 should come out as 1249 0
Well I've achieved that purpose but have come across a roadblock. The program doesn't exit unless I type the EOF sequence. Maybe it's because I have a while(1) running that gives an infinite loop. But when I try to delete it the program doesn't even print at all. I'm still learning this is for a school project.
Any help would be apreciated!
Here's the code:
#include <stdio.h>
int main(){
char c;
int i=0;
while(1){
c=getchar();
if (i==0){
if(c=='0'){
while (c=='0'){
c=getchar();
}
}
printf("%c",c);
i=i+1;
}
else if (c==' '){
printf("%c",c);
c=getchar();
if(c=='0'){
while (c=='0'){
c=getchar();
}
}
printf("%c",c);
}
else if (c=='E'){
c=getchar();
if (c=='O'){
c=getchar();
if(c=='F'){
printf("\n");
return 0;
}
}
}
else{
printf("%c",c);
}
}
}
The important stuff:
int c; // IMPORTANT, cannot be char
while (1) {
c = getchar();
if (c == EOF) break; // exit loop
// ...
}
There has to be some way to tell the program to exit.
With this, the program will exit on the letter x or two consecutive newlines or entering END.
getchar will return EOF when there is nothing left to read from a file. That can be simulated from stdin ( the keyboard) with ctrl + z on Windows or ctrl + d on Linux.
#include <stdio.h>
#include <string.h>
int main ( void) {
char done[4] = "";
int c = 0;
int prior = 0;
int reading = 0;
int zero = 1;
while ( EOF != ( c = getchar ( )) && 'x' != c) {
if ( '\n' == c && '\n' == prior) {
break;
}
if ( c >= '0' && c <= '9') {
reading = 1;
if ( '0' != c) {
zero = 0;
}
if ( ! zero) {
putchar ( c);
}
}
else {
if ( reading) {
if ( zero) {
putchar ( '0');
}
if ( ' ' == c || '\n' == c) {
putchar ( c);
}
else {
putchar ( ' ');
}
}
reading = 0;
zero = 1;
}
prior = c;
done[0] = done[1];
done[1] = done[2];
done[2] = c;
done[3] = 0;
if ( 0 == strcmp ( done, "END")) {
break;
}
}
putchar ( '\n');
return 0;
}
getchar() returns an int, not a char. If it only returned a char, there would be no way for it to return a value that indicates end of file, since all char values are valid and can’t be used for another purpose.
A motivating example in decimal system may be: A function checks the temperature returns a two-digit number. Any temperature between 0 and 99 is valid. How do you report errors when the thermometer is disconnected? You have to return a number with more digits, and use a special value like UNPLUGGED = 100.
But int is a wider type: it has many more values than char, and the “extra” values can be used to indicate some special condition that means “hey, this is not a valid character, but something else I had to tell you”.
getchar() returns the EOF constant upon failure (any failure), for example if no more input is available. There’s nothing sensible you can do even if the reason for the failure other than end of input. You should end processing at the first EOF.
Thus, change the type of c to int, and every time you call getchar(), you must check that its value is not EOF, and return when you encounter it.
The nested structure of your loops means that EOF checking has to be repeated all over the place. There are other ways to structure the code to keep this check in one place, but, admittedly, the nested loops have at least the potential to exploit the branch predictor, whereas a single getchar followed by a state-machine style switch statement will make it perform potentially worse. None of this matters in a simple homework problem, but it’s something to keep in mind. In any case, performance has to be benchmarked - no other way around it.
Try this code, I think it does what you requested:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
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 -2;
// 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.
if (buff[strlen(buff) - 1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? -1 : 0;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff) - 1] = '\0';
return 0;
}
int* convert2numbers(char* arr, int size) {
int i;
int j;
int k;
char token[100];
int* numbers;
int last_space = 0;
int index = 1;
int amount = 1;
// Count the amount of tokens.
for (i = 0; i < size; ++i) {
if (arr[i] == ' ') {
++amount;
}
}
numbers = (int *)malloc(amount * sizeof(int));
numbers[0] = amount;
for (j = 0; j <= size; ++j) {
if (arr[j] == ' ' || arr[j] == '\0') {
// Copy token from input string.
for (k = 0; k < j; ++k) {
token[k] = arr[k + last_space];
}
token[j] = '\0';
numbers[index] = atoi(token);
// Clear the token and continue.
memset(token, '\0', sizeof(token));
last_space = j;
++index;
}
}
return numbers;
}
int main(void) {
int i;
int size;
int* numbers;
int amount;
char input[100];
char help[] = "Numbers> ";
printf("Input numbers below or press enter to exit!\n");
while (1) {
getLine(help, input, sizeof(input));
// If input is empty exit.
if (input[0] == '\0') {
break;
}
size = strlen(input);
numbers = convert2numbers(input, size);
amount = numbers[0];
for (i = 1; i < amount + 1; ++i) {
printf("%d ", numbers[i]);
}
printf("\n");
}
return 0;
}
When run with these inputs this code outputs:
Input numbers below or press enter to exit!
Numbers> 01492 102934
1492 102934
Numbers> 9312 0 01923
9312 0 1923
Numbers> 0001249 0000
1249 0
Also if you press enter in console, it exits, as to escape the while(1) loop, easily.
writing a program that will be finding min, max, avg of values entered by user. Having trouble writing something that will check to make sure there are only postive integers entered and produce an error message. heres my for statement that is reading the input so far:
for (int value = 0; value <= numofvals; ++value) {
printf("Value %d: %f\n", value, val_input);
scanf("%f", &val_input);
}
mind you I've been learning code for about 3 weeks and was just introduced to loops this week so my understanding is rudimentary at best!
First, don't use scanf. If stdin doesn't match what it expects it will leave it in the buffer and just keep rereading the same wrong input. It's very frustrating to debug.
const int max_values = 10;
for (int i = 0; i <= max_values; i++) {
int value;
if( scanf("%d", &value) == 1 ) {
printf("Got %d\n", value);
}
else {
fprintf(stderr, "I don't recognize that as a number.\n");
}
}
Watch what happens when you feed it something that isn't a number. It just keeps trying to read the bad line over and over again.
$ ./test
1
Got 1
2
Got 2
3
Got 3
foo
I don't recognize that as a number.
I don't recognize that as a number.
I don't recognize that as a number.
I don't recognize that as a number.
I don't recognize that as a number.
I don't recognize that as a number.
I don't recognize that as a number.
I don't recognize that as a number.
Instead, use fgets to reliably read the whole line and sscanf to parse it. %f is for floats, decimal numbers. Use %d to recognize only integers. Then check if it's positive.
#include <stdio.h>
int main() {
const size_t max_values = 10;
int values[max_values];
char buf[1024];
size_t i = 0;
while(
// Keep reading until we have enough values.
(i < max_values) &&
// Read the line, but stop if there's no more input.
(fgets(buf, sizeof(buf), stdin) != NULL)
) {
int value;
// Parse the line as an integer.
// If it doesn't parse, tell the user and skip to the next line.
if( sscanf(buf, "%d", &value) != 1 ) {
fprintf(stderr, "I don't recognize that as a number.\n");
continue;
}
// Check if it's a positive integer.
// If it isn't, tell the user and skip to the next line.
if( value < 0 ) {
fprintf(stderr, "Only positive integers, please.\n");
continue;
}
// We got this far, it must be a positive integer!
// Assign it and increment our position in the array.
values[i] = value;
i++;
}
// Print the array.
for( i = 0; i < max_values; i++ ) {
printf("%d\n", values[i]);
}
}
Note that because the user might input bad values we can't use a simple for loop. Instead we loop until either we've read enough valid values, or there's no more input.
Something easy like this may work for you:
int n;
int ret;
for (;;) {
ret = scanf("%d", &n);
if (ret == EOF)
break;
if (ret != 1) {
puts("Not an integer");
for (;;)
if (getchar() == '\n')
break;
continue;
}
if (n < 0) {
puts("Not a positive integer");
continue;
}
printf("Correct value %d\n", n);
/* Do your min/max/avg calculation */
}
/* Print your results here */
This is just an example and assumes you do not need to read floating point numbers and then check if they are integers, as well as a few other things. But for starters, it is simple and you can work on top of it.
To break out of the loop, you need to pass EOF (typically Ctrl+D in Linux/macOS terminals, Ctrl+Z in Windows ones).
An easy and portable solution
#include <limits.h>
#include <stdio.h>
int get_positive_number() {
char buff[1024];
int value, ch;
while (1) {
printf("Enter positive number: ");
if (fgets(buff, 1023, stdin) == NULL) {
printf("Incorrect Input\n");
// Portable way to empty input buffer
while ((ch = getchar()) != '\n' && ch != EOF)
;
continue;
}
if (sscanf(buff, "%d", &value) != 1 || value < 0) {
printf("Please enter a valid input\n");
} else {
break;
}
}
return value;
}
void solution() {
// Handling malformed input
// Memory Efficient (without using array to store values)
int n;
int min = INT_MAX;
int max = INT_MIN;
double avg = 0;
printf("Enter number of elements: ");
scanf("%d", &n);
getc(stdin);
int value;
for (int i = 0; i < n; i++) {
value = get_positive_number();
if (value > 0) {
if (min > value) {
min = value;
}
if (max < value) {
max = value;
}
avg += value;
}
}
avg = avg / n;
printf("Min = %d\nMax = %d\nAverage = %lf\n", min, max, avg);
}
int main() {
solution();
return 0;
}
Output:
Enter number of elements: 3
Enter positive number: 1
Enter positive number: 2
Enter positive number: a
Please enter a valid input
Enter positive number: -1
Please enter a valid input
Enter positive number: 1
Min = 1
Max = 2
Average = 1.333333
If I have a while or do while loop in C, is there some (native) way I can have something happen on the second loop?
I ask for getting inputs; I have this:
int size;
do {
printf("Size of tower (0 <= x <= 23): ");
scanf("%i", &size);
} while (size > 23 || size < 0);
If the user inputs some value which is not between 0 and 23, I want to display an error message and ask for another value. Obviously I could do it like this:
int size;
int error = 0;
do {
if (error) { printf("Invalid size\n"); }
printf("Size of tower (0 <= x <= 23): ");
scanf("%i", &size);
error = 1;
} while (size > 23 || size < 0);
However, this feels gross. I'm looking for an elegant solution, and I figure that having something run on the second loop would work.
I think you want something like this:
int size = -1;
int MAX_TRIES = 10;
while (MAX_TRIES--)
{
printf("Size of tower (0 <= x < 23): ");
if (scanf("%i", &size) != 1)
{
printf("Read error!!\n");
break;
}
if (size >= 0 && size < 23)
{
break;
}
printf("Error: You entered '%d' which is not in the range 0 <= x < 23\n", size);
}
By writing it this way, you won't have to compute the negation of your boolean condition logic mentally while writing the code.
Also, checking for the return value of scanf() is important. Thanks to Weather Vane's comment for reminding this.
Further, it is probably better to limit the number of executions of this loop rather than letting it run till infinity. ( Thanks to Jonathan Leffler's comment )
The conversion and error reporting could be moved to a function to simplify the calling code. Input is taken by fgets and the value is parsed in the function by strtol. This function returns success or failure. Other values get back to the caller through pointers.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int get_int_range ( char *line, char **next, char *delim, int *value, int min, int max);//prototype
int main( int argc, char *argv[])
{
char line[100] = {'\0'};//input buffer
int valid = 0;
int size = 0;
do {
printf ( "Size of tower (0 <= x <= 23) or quit\n");
fgets ( line, sizeof ( line), stdin);//read a line
if ( strcmp ( line, "quit\n") == 0) {
valid = 0;
break;// if quit is entered, exit loop
}
valid = get_int_range ( line, NULL, "\n", &size, 0, 23);// call to parse a value
} while ( !valid);// on failure, keep looping the above
if ( valid) {
printf ( "Size of tower is %d\n", size);
}
return 0;
}
//inputs
// char *line : pointer to text to be parsed
// char **next : pointer to pointer to allow modification of caller's pointer
// char *term : pointer to characters to be considered terminators
// int *value : pointer to int to allow modification of caller's int
// int min : minimum value of range
// int max : maximum value of range
// returns : 0 failure or 1 success
int get_int_range ( char *line, char **next, char *delim, int *value, int min, int max)
{
long int input = 0;
char *end = NULL;//will point to end of parsed value
if ( line == NULL) {
printf ( "no text to parse\n");
return 0;
}
if ( value == NULL) {
printf ( "unable to save parsed value\n");
return 0;
}
errno = 0;
input = strtol ( line, &end, 10);//get the integer from the line. end will point to the end of the parsed value
if ( ( errno == ERANGE && ( input == LONG_MAX || input == LONG_MIN))
|| ( errno != 0 && input == 0)){// parsing error from strtol
perror ( "input");
return 0;
}
if ( end == line) {// nothing was parsed. no digits
line[strcspn ( line, "\n")] = '\0';//remove newline
printf ( "input [%s] MUST be a number\n", line);
return 0;// return failure
}
// *end is the character that end points to
if ( *end != '\0' && !( delim && strchr ( delim, *end))) {// is *end '\0'? is *end in the set of term characters?
line[strcspn ( line, "\n")] = '\0';//remove newline
printf ( "problem with input terminator: [%s] \n", line);
return 0;
}
if ( input < min || input > max) {// parsed value is outside of range
printf ( "input out of range %d to %d\n", min, max);
return 0;
}
if ( next != NULL) {// if next is NULL, caller did not want pointer to end of parsed value
*next = end;// *next allows modification to caller's pointer
}
*value = input;// *value allows modification to callers int
return 1;// success
}
My preferred technique would involve duplicating the input, but would simplify your loop:
printf("Size of tower (0 <= x <= 23): "); // Try to get good input once.
scanf("%i", &size);
while (size < 0 || 23 < size ) { // While the user is wrong:
printf("Invalid size\n");
printf("Size of tower (0 <= x <= 23): "); // Try, try again.
scanf("%i", &size);
}
I wrote a small C program which will get an input from the user and check if the input is even or odd.
#include<stdio.h>
int main()
{
int n;
printf("Enter an integer number: ");
scanf("%d",&n);
if(n%2 == 0)
{
printf("\n%d is an EVEN number.\n",n);
}
else
printf("\n%d is an ODD number.\n",n);
return 0;
}
but when I enter an alphabet or a symbol, it shows the output as 0 and says input is EVEN. How can I prevent user from entering alphabets and symbols? What's the easiest way to do that?
You have to check the return value of scanf. From the documentation:
Return Value
Number of receiving arguments successfully assigned, or EOF if read failure occurs before the first receiving argument was assigned.
Applied to your code:
#include <stdio.h>
#include <stdlib.h>
int
main()
{
int n;
printf("Enter an integer number: ");
if (scanf("%d", &n) != 1)
{
printf("This is not a number.\n");
return EXIT_FAILURE;
}
else if (n % 2 == 0)
{
printf("\n%d is an EVEN number.\n", n);
return EXIT_SUCCESS;
}
else
{
printf("\n%d is an ODD number.\n", n);
return EXIT_SUCCESS;
}
}
Simply check the return value of scanf - it'll tell you how many format objects were successfully parsed. In this case, it'll return 1 if it could parse an int, and 0 if it couldn't.
If the input is an integer, then scanf() will return 1 so you can check
if (scanf("%d", &integer) != 1)
invalidInput();
to ask the user again you should know that there could be characters left in the stdin that need to be read so you can flush them with getchar() so a complete function would be
int scanint(const char *const message)
{
int value;
printf("%s > ", message);
while (scanf("%d", &value) != 1)
{
int chr;
printf("\tinvalid input...\n");
do {
chr = getchar();
} while ((chr != EOF) && (chr != '\n'));
printf("%s > ", message);
}
return value;
}
and you can use it like this
int main()
{
int value = scanint("please input an integer");
printf("your input was: %d\n", value);
return 0;
}
I can give you two approaches:
very easy — check for return value of scanf(). 1 indicates success (integer read) and 0 if any non-integer is put in there (or EOF on EOF).
by writing code for it:
#include <ctype.h>
#include <stdlib.h>
int isNumeric (const char * s)
{
if (s == NULL || *s == '\0' || isspace(*s))
return 0;
char * p;
strtod (s, &p);
return *p == '\0';
}
Now in this case your scanf has to take a string from user and then pass that string to the function isNumeric().
I need scanf to read numbers, including the number which is entered just before EOF (no space or enter after putting this number, just EOF - like "1 2 3 4EOF" - 4 is not read). My code looks like this:
for (i = 0; i < 100; i++)
{
if ((scanf ("%d", &number) != 1 && !feof(stdin)))
{
printf ("Wrong input.\n");
return (0);
}
if (feof(stdin) && count == 0)
{
printf("Empty input.\n");
return 0;
}
if (feof(stdin)) break;
field[i] = number;
count++;
}
Where is the part which needs to be adjusted to accept also the last entered number not separated before EOF? Thanks a lot, I really can't see it..
It is the if (feof(stdin)) break; that does the damage. You should only break on EOF if you do not get 1 from scanf(). In your example, the system knows it has reached EOF, but it also successfully converted a value, and it told you so by returning 1 from scanf(), but you went ahead and ignored the successfully converted value because EOF was also detected.
You should probably use:
#include <stdio.h>
int main(void)
{
int field[100];
int count = 0;
int n;
for (int i = 0; i < 100; i++)
{
int number;
if ((n = scanf("%d", &number)) != 1)
break;
printf("-- %d: %d (%d)\n", i, number, n);
field[i] = number;
count++;
}
if (n == 0)
{
printf("Wrong input.\n");
return 1;
}
else if (ferror(stdin))
{
printf("I/O error on stdin\n");
return 1;
}
else if (feof(stdin) && count == 0)
{
printf("Empty input.\n");
return 1;
}
printf("Count: %d\n", count);
for (int j = 0; j < count; j++)
printf("%d: %d\n", j, field[j]);
return 0;
}
check !feof(stdin) right at the end of the loop. It will be true after you have read the last value, so in this case the last value is not stored
After successfully reading the last number via scanf ("%d"..., calling feof() may return true or false, depending on if additional white space, like \n follows the number. Thus feof() is not a definitive test to stop looping. Simpler code is possible.
In general, avoid using fscanf() and feof() in the same parsing routine. Instead use the return value from fscanf() to know when EOF occurred.
while ((retval = fscanf(...)) == expected value) {
// The happy path
do_stuff();
}
if (retval == EOF) {
Deal_with_EOF_or_IOerror();
}
else {
Deal_with_unexpected_number_of_parameters_scanned();
}