Why does my do while statement work this way? - c

This code works but I'm confused on how. I was writing this program for a class. I needed to only accept positive integers. I created a do...while loop to do so. My question is, why does this code only check the correct way when I have the or "||" in there and not the "&&". I would assume it would need to test both to make sure that it is taking in the correct integers.
#include <stdio.h>
#include <math.h>
main()
{
float i, number, sum=0;
int k;
do
{
printf( "Sumation Calculator\n" );
printf( "Enter number: " );
scanf( "%f", &number );
k = number;
}while(number < 1 || k != number);
while (i <= number)
{
sum = sum + i;
i++;
}
printf( "The summation of %f is %f.\n", number, sum);
return 0;
}

You have two requirements:
That the value be positive
That the value be an integer (no fractional/decimal component)
Your test needs to be true if you need to ask again, not if you have the correct value; testing for the correct value would involve two "positive tests" joined by &&, but you want to test for incorrect values, which means you want to reject if either "negative test" fails. You need to ask again if either condition is violated. If you test number < 1 && k != number that means "I need to ask again only if it's both not positive and non-integer", so 0 (which is not positive, but is an integer) would be accepted, as would 1.5 (which is not an integer, but is positive).
Testing number < 1 || k != number correctly says "I need to ask again if it's not positive or it's not an integer"; if it fails either criterion, you loop and ask again.

Others have explain OP's logic issue.
why does this code only check the correct way when I have the or "||" in there ...
Code is not corrct with only that change. It has too many problems - many of which can be identified by enabling all compiler warnings.
scanf( "%f", &number); will round numeric input text to a float, losing non-integer detection.
k = number; is undefined behavior when number is much outisde int range.
i <= number is bad as i is not yet assigned.
The return value of scanf( "%f", &number ) is not tested for success.
Below is a more robust way to test for input of only positive integers.
I needed to only accept positive integers.
Best to:
Read the line of text into a string.
Parse it as an integer with strtol().
Test for range, etc.
char buf[100];
while (fgets(buf, sizeof buf, stdin)) {
char *endptr;
errno = 0;
long value = strtol(buf, &endptr, 10);
if (buf == endtpr) {
puts("No conversion");
continue;
}
if (errno) {
puts("Out of long range");
continue;
}
if (*endptr != '\n') {
puts("Non-numeric trailing junk");
continue;
}
if (val < 0) {
puts("Only positive values");
continue;
}
// Success, now do something with val
}
This will fail input like "123.0" or "1e2" - which are both whole numbers. Additional code could handle most of those cases.

do
{
...
k = number; // now k == number
} while (number < 1 || k != number);
} while (number < 1 || FALSE);
} while (number < 1);
As you see the condition is not needed.
What is the initial value of i?
By the way it is "Summation" I believe.

Related

How to limits value user input < INT_MAX in C

#include <stdio.h>
#include <stdlib.h>
#include<limits.h>
int getInt() {
int n, check;
char ch;
do {
fflush(stdin);
printf("Enter positive integer n = ");
check = scanf("%d%c", &n, &ch);
if ((check == 2)&&(ch == '\n')) {
if (n > INT_MAX) {
printf("Invalid number\n");
} else if (n < 0) {
printf("n must > 0");
} else {
break;
}
} else printf("Invalid number\n");
} while (1);
return n;
}
int main(int argc, char** argv) {
int n;
n = getInt();
}
My code accepts user input number in range 0 to INT_MAX.
When I input -1, program displays "n must > 0".
But when I input '77777777777777777777777777777777' (> INT_MAX) program still displays "n must > 0", and not 'Invalid number'.
With out of range input in scanf("%d%c", &n, &ch);, the behavior is undefined.
Instead read a line of input with fgets(), then quality using strtol()
for (;;) {
char buf[100];
if (fgets(buf, sizeof buf, stdin) == NULL) {
printf("No more input\n");
return -1;
}
errno = 0;
char *endptr;
long val = strtol(buf, &endptr, 0);
// No numeric conversion done at all?
// Numeric input outside long range?
// Junk after the numeric text?
if (buf == endptr || errno == ERANGE || *endptr != '\n') {
printf("Invalid number\n");
continue;
}
// Outside int range?
if (val < INT_MIN || val > INT_MAX) {
printf("Invalid number\n");
continue;
}
if (val < 0) {
printf("n must > 0");
continue;
}
n = (int) val;
}
I'd recommend a re-usable int get_int(int *val) helper function.
First you need to understand how variables stores data.
In 64 bits architeture, the int type have 4 bytes (either the C long type, regardless architeture), so can store the following values:
00000000 00000000 00000000 00000000 = 0 (decimal value)
01111111 11111111 11111111 11111111 = 2,147,483,647 (decimal value)
11111111 11111111 11111111 11111111 = 4,294,967,294 (unsigned decimal value)
11111111 11111111 11111111 11111111 = -1 (signed decimal value)
Note that the integer types can use the Most Significant Bit (MSB) to represent signal (0 to positive, 1 to negative) using a modular aritmetic.
For more details about integer signal: https://en.wikipedia.org/wiki/Two%27s_complement
So, to store decimal data higher than INT_MAX, you need more bytes than you have using int type. A good way, compatible with 64 bits architeture, is using long long type.
Long long type uses 8 bytes, so can stores value higher than INT_MAX.
You will have to declare:
long long n;
And use scanf() like this:
scanf("%lld%c", &n, &ch);
Your fflush(stdin) have to be after the scanf(), because if your aplication break the loop after the scanf() and before have reached the fflush() instruction you may have problem in further input handling. Like this:
check = scanf("%lld%c", &n, &ch);
fflush(stdin);
However, some developers disapprove use fflush() in stdin, so this is an alternative (a bit more complex) using getch() accepting only numbers and converting char* to long long using strtoll():
char c = 0;
char* input_number = malloc(32);
int accepted_chars = 0;
memset(input_number, 0, 32);
while(c != '\r'){ //loop until user press ENTER
c = getch();
//receive numbers keys pressed
if(c >= '0' && c <= '9'){
*(input_number + accepted_chars) = c;
accepted_chars ++;
printf("%c", c);
}
//receive backspace key pressed
if(c == 8){
if(accepted_chars > 0){ //don't do nothing if there is nothing to clear
accepted_chars --;
*(input_number + accepted_chars) = 0;
printf("\b");
printf(" ");
printf("\b");
}
}
}
printf("\n");
char* endptr;
n = strtoll(input_number, &endptr, 10); //convert string in base 10 (decimal) long long type
Just checking
int x;
...
if (x > INT_MAX) { ...
is something that will never work. If an int value cannot have values above INT_MAX then it is impossible that you can ever get x stored a value higher than that. So that if will become always false and the compiler will probably eliminate all the code you put inside that if's then block.
Normal reading routines like scanf() actually limit the input to a value in the range of allowable values.
But if you want to read and build the number yourself, you need to ancitipate the possibility, and use better triggers to stop.
For example, checking that the number is above (INT_MAX - 9) / 10 will tell you that if you try to add another digit to it, you'll run the risk of overflowing the integer, when you add the digit. You can simply stop there and don't continue reading, but if you want to read one more digit (who knows, it could be a 0 and that doesn't hurt, you'll have to check for something like
int digit;
int the_integer = 0;
while ( (digit = fgetchar(stdin)) != EOF
&& isdigit(digit)
&& the_integer <= (INT_MAX - (digit - '0')))
{
the_integer *= 10;
the_integer += digit;
} /* while */
if (digit != EOF && isdigit(digit)) {
/* x > (INT_MAX - (digit - '0')) */
/* this is necessary, as if you don't do it, you'll lose
* the next character to read. */
unput(digit, stdin);
}
This way you'll check the number x before multiplying it by 10 and adding the digit - '0' value.
As pointed out in the comments section, there is no point in testing if n > INT_MAX, as n is of type int and therefore by definition unable to represent any value larger than INT_MAX.
A simple, flexible way of checking the size of a number provided as user input would be to read it in as a string and count the number of digits by using the function strlen and possibly also isdigit to count the actual digits.
However, when dealing with potentially large numerical values as user input, it is usually better to first read this input into a data type that is larger than int and do your range checks with this larger data type. After you are satisfied that the number is in the desired range, you can convert it to the smaller int data type. Although the ISO C standard does not guarantee that a long long is larger than an int, this is a reasonable assumption and it is the case on all compilers that I am aware of. However, on some platforms (including 64-bit Windows), the data type long is the same size as int, so a long cannot be reliably used for this on all platforms.
Probably the easiest solution to your problem would be to use the function strtol or strtoll. Using these functions has the advantage that you don't need a larger data type and it explicitly tells you if a number is out of range, by setting errno to ERANGE. However, these functions only support the data types long and long long, but not int. Therefore, if you want to use int, you will have to do your range checks manually before you convert it.

C programming function calling to return values

I'm a college student in my first year of software engineering. I am in the fourth week of my semester and am having trouble in my programming class. Currently, I was given this assignment in which I was given a function called "getNum()" and I had to use it in another function where the program user, would input a number and the function that I program (must be named isOdd()) would determine if the number is odd or even. Then the main function would print whether the number is odd or even. This is the way that my professor worded it:
" Write a program that uses the getNum() function provided to you in Assignment 2 to get anumber from the user (prompting them first, as always). Create and use a function called isOddwith parameters (the number) and return values (1 ifthe number is odd, 0 if the number is evenOR use a bool or boolean data type, your choice) to determine if thenumber is odd. In main(), tell the user (by displaying using printf()or cout) whether the number is evenor odd."
Now, the problem I am having is understanding programming as I am fairly new to it and some words confuse me, such as parameter and return value. To give you and idea of what I have written so far,
#include <stdio.h>
int isOdd(int numInput);
int getNum(void);
int main(void)
{
int number = 0;
while (number > -1)
{
if (isOdd(0))
{
printf("The number is even.\n");
}
else if (isOdd(1))
{
printf("The number is odd.\n");
}
}
return 0;
}
int isOdd(int numInput)
{
int myNumber = 0;
printf("Please enter a number: ", numInput);
myNumber = getNum();
if (myNumber % 2 == 0)
{
myNumber == 0;
}
else
{
myNumber == 1;
}
return myNumber;
}
#pragma warning(disable: 4996)
int getNum(void)
{
/* the array is 121 bytes in size; we'll see in a later lecture how we can improve this code */
char record[121] = { 0 }; /* record stores the string */
int number = 0;
/* NOTE to student: indent and brace this function consistent with your others */
/* use fgets() to get a string from the keyboard */
fgets(record, 121, stdin);
/* extract the number from the string; sscanf() returns a number
* corresponding with the number of items it found in the string */
if (sscanf(record, "%d", &number) != 1)
{
/* if the user did not enter a number recognizable by
* the system, set number to -1 */
number = -1;
}
return number;
}
This is what I have written, trying to do things accordingly to my professor's instructions, as I do not yet know how to properly use booleans. As you can see, at the bottom is the getNum() function that my professor has said is mandatory for this assignment. As of now, everything I input, I am told is even. I am not asking for you guys to solve and do everything for me but I want to understand what I am doing wrong, what my thinking is doing wrong and to overall better my understanding for future programming. Thank you
It's hard to help you without knowing why you did what you did. A lot of the code is just baffling:
if (isOdd(0))
Why are you passing a zero to isOdd?
printf("Please enter a number: ", numInput);
myNumber = getNum();
Is numInput supposed to be the number they enter or is myNumber supposed to be?
if (myNumber % 2 == 0)
{
myNumber == 0;
}
The statement myNumber == 0 compares myNumber to zero to see if they're equal. It does nothing useful here since you ignore the result of the comparison.
The function:
int getNum(void)
Takes no parameters (void), and returns an integer (int) value. The function itself accepts input from the standard input (stdin) stream - this is normally from the keyboard.
To complete your assignment you should write a function:
int isOdd( int value ) ;
Where value is an integer parameter and the return value is 1 if value is odd and 0 if it is even. Alternatively you are allowed to use the Boolean type:
#include "bool.h"
bool isOdd( int value ) ;
In which case you would return true for odd, and false for even.
Your isOdd() includes the getNumber() call and user prompt code. Not only is that not specified in the assignment, it is poor design making isOdd() difficult to use in more general situations. The assignment explicitly requires you to pass the value to be tested as a parameter.
The assignment does not require you to iterate the test (the while loop is not needed). The user input prompt and acceptance should be in main as follows:
int main(void)
{
printf( "Please enter a number: " ) ;
fflush( stdin ) ; // you'll may this on some platforms
int myNumber = getNum();
if( isOdd( myNumber ) )
{
printf("The number is odd.\n");
}
else
{
printf("The number is even.\n");
}
}
return 0;
}
Note that there are only two possible outcomes, so you do not need an else if( !isOdd( myNumber ) ... - if it is not odd it is implicitly even.
Your isOdd() function will work, but is over complicated. You are required to return a Boolean (a type with two possible values true/false - or an integer 1/0 which can be implicitly converted to a Boolean), and (myNumber % 2 == 0) is a Boolean expression (an expression with two possible results true or false). Anywhere you see the pattern:
if( <boolean expression> )
{
b = true ;
}
else
{
b = false ;
}
you can simply write:
b = <boolean expression> ;
In your case the Boolean determination of odd-ness is simply value % 2 != 0. You can return that directly:
bool isOdd( int value )
{
return value % 2 != 0 ;
}

Scanf more values C

i need help with short Code in C. I must read floats on input line seperated with space and input is ended with float 0 or EOF.
How to do this if i dont know how many numbers or in input, or how it works and ask to EOF if i am reading just numbers and not chars?
Thanks for any response.
example of input in one line:
12 11 10 45 50 12 EOF
12 10 11 45 0
int main(void)
{
float num;
float sum = 0;
do{
scanf("%f", num);
sum += num;
} while(EOF || num == 0);
return 0;
}
From the man page of scanf -
scanf returns the number of items successfully matched and assigned
which can be fewer than provided for, or even zero in the event of an
early matching failure. The value EOF is returned if the end of input
is reached before either the first successful conversion or a matching
failure occurs.
This means that scanf will return EOF only when it encounters EOF as the first input when it is called because EOF must be preceded with a newline '\n' else it won't work (depending on the OS). You must also account for the matching failure scanf may encounter.
#include <stdio.h>
int main(void) {
float num;
float sum = 0;
int val;
while((val = scanf("%f", &num)) != EOF && val == 1) {
sum += num;
}
if(val == 0) {
printf("matching failure. input is not a float.\n");
}
else {
printf("end of input.\n");
}
return 0;
}
From scanf reference:
On success, the function returns the number of items of the argument
list successfully filled. This count can match the expected number of
items or be less (even zero) due to a matching failure, a reading
error, or the reach of the end-of-file.
If a reading error happens or the end-of-file is reached while
reading, the proper indicator is set (feof or ferror). And, if either
happens before any data could be successfully read, EOF is returned.
If an encoding error happens interpreting wide characters, the
function sets errno to EILSEQ.
So, you may rewrite your do-while loop to something like
int retval;
while((retval = scanf("%f", &num)) != EOF && retval > 0 && num != 0) {
sum += num;
}
if(retval == 0) {
printf("input read error.\n");
}
to match your constraints.
Also note you need to prefix your variable with & when passing it to scanf(), since the function expects a pointer to deal with (you need to pass variable address).
EDIT:
see this topic concerning EOF problems in Windows
You can re write your code like this
int main(void)
{
float num;
float sum = 0;
do
{
scanf("%f", &num);
sum += num;
} while((!feof(stdin)) && (num != 0));
printf("%f", sum);
return 0;
}
Here feof indicates end of input stream.
The following may be a slightly more robust way to do this:
#include <stdio.h>
#include <string.h>
int main(void) {
int sum=0;
int num;
char *p;
char buf[1000];
fgets(buf, 1000, stdin);
p = strtok(buf," ");
while(p!=NULL) {
if(sscanf(p, "%d", &num) == 1) sum+=num;
p = strtok(NULL, " ");
}
printf("the sum is %d\n", sum);
}
Test:
> testme
1 2 3 4 0
the sum is 10
> testme
1 2 3 4 ^D
the sum is 10
Note - you have to enter ctrl-D twice to get the desired effect when you are at the end of a line.
you can get your doubt clear by reading "C programming a modern approach by K N King"
This book provides proper clarification on this topic
Test the result of scanf() for 0, 1 or EOF.
Test the value scanned for 0.0.
int main(void) {
float num;
float sum = 0;
int cnt;
while ((cnt = scanf("%f", &num)) == 1) {
if (num == 0.0) break;
sum += num;
}
// cnt should be EOF, 0 or 1
if (cnt == 0) {
printf("Input is not a number\n");
}
else {
printf("Sum %f\n", sum);
}
return 0;
}
Although, in general, scanf() returns values EOF, 0, 1, ... "number of format specifiers", a value of 0 occurs rarely. Example input is "+".

How do I force user to input a positive integer?

Force user to input a positive integer and put user in a loop till they do.
So I want everything including characters not allowed just over > 0
I tried the following:
while (i < 0) do {
printf("please input a number that's positive");
scanf("%d", i);
}
For positive integer use the following code
int i;
do
{
printf("please input a number that's positive");
scanf("%d", &i);
}while (i < 0);
The c language provides no error checking for user input. The user is expected to enter the correct data type. For instance, if a user entered a character when an integer value was expected, the program may enter an infinite loop or abort abnormally.
Both of these while functions manage the numbers, the int k is the set integer which can only be set below 20, the first while loop makes a statement that calls for another scan if the number is greater than 20
and the second loop prints a k*k box.
Hope this helps.
int main ( )
{
int i, j,k;
printf("Please enter Box size:\n\n");
scanf("%d",&k);
while(k>20){
printf("Please enter a value below 20\n\n");
scanf("%d"),&k;
}
while(k<=20)
{
for (i = 0; i < k; i++)
{
printf("\n");
for (j = 0; j < k; j++)
{
printf("#");
}
}
return 0;
}
}
I would do this: declare char term and int wrong = 0.
do {
printf("Enter a number: ");
fflush(stdin);
if (scanf("%d%c", &n, &term) != 2 || term != '\n' || n <= 0) {
printf("Only positive numbers.\n");
wrong = 1;
}
else {
wrong = 0;
//do something here if correct;
}
} while (wrong);
The code above detects invalid input if the user entered a mixture of characters and numbers, or negative numbers (and zero).
However, it doesn't detect if the user entered trailing zeros in front followed by valid digits eg. 001or 00000738. If anyone else could figure this out, please share below. Thanks! :)
Here is another alternative of a function which takes in a char str[20] (of say, maybe 20 elements), analyses the string to check for positive integers, and returns a 0 or 1 accordingly. Lastly, convert that string to an integer using atoi().
int checkPositiveIntegers(char str[]) {
char *ptr = str;
if (*ptr == '-' || *ptr == '0') //checks for negative numbers or zero
return 1;
else {
do {
if (isdigit(*ptr) == 0) { //checks for non-digit at ptr location; isdigit() returns 0 if non-digit
return 1;
break;
}
ptr++;
} while (*ptr != '\0' && *ptr != '\n');
return 0; //returns 0 if positive integer
}
}
So the function only accepts positive numbers from 1 to 9,999,999,999,999,999,999 (up to 19 digits if char str[] holds 20 elements).
However, if you converted the string back to int n = atoi(str);, the maximum value it could reach would be 2,147,483,647 since n is declared as a signed integer. Play around with different datatypes for exploration.
Hope this helps! :)

Dealing with unexpected input

Just a small query really, through the use of scanf, which in my case, will be scanning in X number of integers into variables, each integer separated by a space. Any hints/clues as to how to deal with input if when the integers are input, there are no spaces between them, for example, my input is such X X X X, but if XX X X was input, how could I deal with that within my scanf function?
Bearing in mind my scanf(%d %d %d %d"....)
Cheers.
I would read one value at a time with a counter and check whether a number is larger than 9, 99 or 999 to check for multiple digits. If you do, extract each digit with division and increase your counter for each digit.
You could check the return value of your scanf() to make sure it matches, and then validate that the values are between 0 and 9 after you receive them. Like so:
int vars[4];
if (scanf("%d %d %d %d", vars[0], vars[1], vars[2], vars[3]) != 4) {
// error
}
Then check each variable for being in range:
for (int i = 0; i < 4; i++) {
if (vars[i] < 0 || vars[i] > 9) {
// error
}
}
I'd just avoid scanf(). If each integer is just a single digit, something like the following would probably work:
int vars[4];
for (int i = 0; i < 4;) {
int c = getchar();
if (isdigit(c)) {
vars[i++] = c - '0';
} else if (!isspace(c)) {
// error
break;
}
}
The above does of course assume that the digits are '0' to '9' and have increasing, sequential values... and are each represented by a single char -- but those are probably safe assumptions.
While scanf reads after the enter button is pressed, it might be easier to read the line as a string and then try to analyze it. You can correct your input with backspace etc. on a fully featured terminal, so it's a bit more comfortable for user than getchar.
We look for single digits only, is that right?
Maybe something like:
char buffer[SOMECOUNT];
int digits[4];
int read, i;
scanf("%s", buffer);
for(int i = 0; i < strnlen(buffer, SOMECOUNT); ++i)
{
if( read >= 4 )
break;
if( isdigit(buffer[i]) )
{
digits[read] = buffer[i] - '0';
read++;
}
}
if ( read < 4 )
printf(error...);
Of course, this SOMECOUNT constant makes the solution a bit fragile for nasty input, so you may want to use the limit: scanf("%20s",buffer) or even construct the format string to include SOMECOUNT.

Resources