I have been trying to add some experience in C to my experience with Python and started with a basic addition program. One thing that I'm trying to do is check if the input is a number or a character as seen here:
#include <stdio.h>
#include <ctype.h>
int main()
{
int n, sum=0,c,value;
printf("Enter the Number of Integers You Want to Add\n");
scanf("%d", &n);
if(isdigit(n))
{
printf("Enter %d Integers\n", n);
for(c=1; c<=n; c++)
{
scanf("%d", &value);
if(isalpha(value))
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
else
{
sum = sum + value;
}
}
printf("Sum of Entered Integers = %d\n",sum);
}
else
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
return 0;
}
Initially I had tried this using isalpha(), and the program worked fine when adding numbers but interpreted characters as zeros instead of printing the "not an integer" statement. However, now that I reworked it to use isdigit(), it does not recognize ANY input as an integer, whether or not it is. Is there something that I'm just doing wrong?
When you use scanf to read an integer, you get just that, an integer. (To read a single character, you need %c and a pointer-to-char).
When you use isdigit(), you need to supply the representation of that character (e.g. in ASCII, the character '0' has the representation 48, which is indeed its value as an integer). To recap:
isdigit(0) is false
isdigit(48) is true (for ASCII, ISO8859, UTF-8)
isdigit('0') is true (no matter the character set)
isdigit('0' + n) is true for integers n = 0 ... 9
PS: Not testing the return value from scanf is asking for trouble...
Neither isdigit nor isalpha work as you think they do. The intent of those library functions is to check whether a given code point, represented as an int, is within a subset of points defined by the standard to be digit characters or alpha characters.
You should be checking the results of your scanf calls rather than assuming they just work, and acting on those results accordingly. If you request an integer and one is successfully scanned, then it will tell you so. If that fails, your course of action is probably to consume the rest of the line (through newline or EOF) and possibly try again:
#include <stdio.h>
int main()
{
int n,value,sum=0;
printf("Enter the Number of Integers You Want to Add\n");
if (scanf("%d", &n) == 1 && n > 0)
{
printf("Enter %d Integers\n", n);
while (n--)
{
if (scanf("%d", &value) == 1)
{
sum = sum + value;
}
else
{
// consume the rest of the line. if not EOF, we
// loop around and try again, otherwise break.
while ((value = fgetc(stdin)) != EOF && value != '\n');
if (value == EOF)
break;
++n;
}
}
printf("Sum of Entered Integers = %d\n", sum);
}
return 0;
}
Properly done you should be able to enter valid integers beyond single digits (i.e. values > 10 or < 0), which the above allows.
The %d marker to scanf tells it to interpret the input as a number (more accurately, it indicates that the pointer in the arguments points to an integer type). It can't do anything but put an integer into that argument. If it can't interpret the input as a number, scanf stops scanning the input and returns immediately.
isdigit() evaluates its argument as a character code, as Jens points out above. However, scanf already turned the character code into a pure number.
From the scanf man page:
On success, the function returns the number of items of the argument list
successfully filled.
In your program, you are trying to read just one item from stdin, so scanf should return 1. So check for that and you'll know that it all worked out ok:
printf("Enter the Number of Integers You Want to Add\n");
while(scanf("%d", &n) != 1) {
printf("That's not a valid integer. Please try again.\n");
}
You cannot use isdigit() the way you are using it because you're already using scanf to convert the user input to an integer. If the user had not input an integer, scanf would have already failed.
Look at the man pages for all the C functions you are using, they will show you what the function expects and what the return values will be under different circumstances.
In the case of isdigit(), the input is expected to be an unsigned char representing an ASCII character. This can be a bit confusing because ASCII characters are in fact represented as a type of integer, and a string is an array of those. Unlike languages like Python which hide all that from you. But there is a big difference between the STRING of a number (array of characters that contain the characters of the digits of the number) and the INTEGER itself which is in a form the processor actually uses to do math with... (simplified explanation, but you get the idea).
Related
I am trying to create program which checks if input from user is a number. This works fine for all of the number and charatcers entered, except for numbers in range of 48 to 57. I've been looking through StackOverflow forum and could not find the answer. Could you please advise, what I am doing wrong?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(){
int tab[100];
int input;
int index = 0,count=0;
printf("Podaj liczby:\n");
do{
scanf("%i", &input);
if(!isdigit(input)){
if(input!=0){
tab[index] = (int)input;
index++;
}
}else{
printf("Incorrect input");
return 1;
}
}while(input!=0 && index<100);
if(index<2){
printf("not enough data available");
return 2;
}
for(int i = 0; i <index; i++){
count = 0;
for(int j = i+1;j< index; j++){
if((tab[i] == tab[j]) && tab[i]!=0) {
count++;
tab[j] = 0;
}
}
if(count>0){
printf("%i ",tab[i]);
}
}
return 0;
}
scanf("%i", &input);
scanf with the format %i converts its input to an integer. If the user presses 4 2 Enter, that makes the scanf call equivalent to input = 42.
If the input can't be converted to an integer, scanf returns EOF and doesn't set input. Since you don't check the return value of scanf, your program continues with an indeterminate value in input. (In theory that's undefined behavior, but in practice your program will run with whatever happened to be in the memory location of input.)
if(!isdigit(input)){
This tests whether the number input is the numerical code of a digit character. In practice, the correspondence between characters and their numerical codes on your computer is ASCII, so digits occupy the range from 48 to 57 inclusive. So the body of this if clause only runs if input is not between 48 and 57.
I have no idea why you'd do that. If you meant to check whether the input is valid, check the return value of scanf. If you thought you were checking the first character of the input, then 1. no you aren't, you're checking the result of the conversion, you can't access the raw input from the user; and 2. you'd only be checking one character anyway so your check couldn't possibly be correct.
The if(!isdigit(input)) clause is checking whether input is a digit, and it jumps to the else part if it is. So, if this was ever going to work, you would have to get rid of the '!' operator.
Which leaves us with the next problem: you are using scanf() to read ints. There is no more checking to be done to see whether an int is a number. An int is already a number.
But what you do, is that you treat the int as a char and pass it to isdigit(), which will of course only succeed if the char is between 0 and 9, which corresponds to int numbers between 48 and 57. So, only these numbers succeed, and then you negate the result of isdigit(), so you think that only these numbers fail.
Long story short: quit checking whether your numbers are numbers, they are already numbers.
I'm doing intro to C and I need to write a program that prompts the user to enter in characters, an equal sign, and an integer. I need to use getchar() until the '=' then scanf() for the integer. The program should then output only the integer back to the user.
Right now it prints out unnecessary code re the location for every character input, then at the end outputs the correct integer. This is the code I have:
#include <stdio.h>
#define EQUAL '='
int main(void)
{
char ch;
int integer = 0;
printf("Enter some text, an equal sign and an integer:\n");
while ((ch = getchar())!= '\n') //while not end of line
{
if (ch == EQUAL){
scanf("%d", &integer);
}
printf("The integer you entered is: %d\n", integer);
}
return 0;
}
I can't find an example and need clarification on how to fix the issue.
You got bit by a gotcha in C. The problem is this:
if( ch == EQUAL )
scanf("%d", &integer);
printf("The integer you entered is %d\n", integer);
if with no braces will only include the single statement following it. That code is really this:
if( ch == EQUAL ) {
scanf("%d", &integer);
}
printf("The integer you entered is %d\n", integer);
To avoid this gotcha, I would recommend two things:
Always indent your code properly.
Never use if, else, or while without braces.
gcc supports a warning about this, -Wmisleading-indentation.
For more gotchas like this read "C Traps And Pitaflls" by Andrew Koenig.
I wrote the following code in C to make a program which calculate the factorial of any number.
I want to add to my program some validation/error handling, such as preventing random characters, floats or negative values from being entered, so I used the isdigit function.
Unfortunately there is a hidden problem which I don't know how to solve. When I enter any input it considers it to be false (i.e. not a digit) even if it's a positive digit.
#include <stdio.h>
#include <ctype.h>
int main()
{
char choice;
unsigned long long int factorial=1;
int counter,number;
for(;;)
{
printf("Please , enter a positive integer number only : ");
scanf("%d",&number);
fflush(stdin);
if(isdigit(number))
{
for(counter=number;counter>1;counter--)
factorial*=counter;
printf("The factorial of number %d is %llu",number,factorial);
}
else
{
printf("\a\aError\n");
continue;
}
printf("\n1-Press c or C if you want to calculate the factorial of a new number\n2-Press any key if you want to exit the program\n ");
scanf("%c",&choice);
if(choice=='c'||choice=='C')
{
factorial=1;
system("cls");
continue;
}
else
return 0;
}
}
You are using isdigit wrong. Read its documentation to find out what it actually does.
You probably meant:
if ( number >= 0 && number <= 9 )
However you also need to check whether scanf succeeded or not. If they type in some words, then scanf("%d" fails and does not update number, so trying to access number in that case accesses an uninitialized variable. To deal with that you could either check the return value of scanf, or do:
int number = -1;
scanf("%d",&number);
because the value will be left unchanged if the input failed.
NB. Don't use fflush(stdin)
isdigit checks a single character if that's a decimal digit character.
But, your input could be say 25, multiple characters. So, I changed a portion:L
char input[30];
for(;;)
{
printf("Please , enter a positive integer number only : ");
scanf("%s",input);
if(isdigit(input[0]))
{
number = atoi(input);
for(counter=number;counter>1;counter--)
Keeping rest of your program snippet same.
Here, isdigit is used to check if the first character in input is a digit and therefore a valid candidate to be converted by atoi into an integer value number.
I am making a typical guessing game to learn C for the first time in my life and I noticed a bug. If you enter an integer you will get Guess a higher value or Guess a lower value and that works just fine. But if you put in a string, it goes insane and prints out a lot of strings saying Guess a higher value.
What I am trying to do now is to make a check for if the user enters a string, it will say to the user something like Enter a number, not text. How do I do this?
Is there anything you see that I can improve in this code?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main () {
int secret, answer;
srand((unsigned)time(NULL));
secret = rand() % 10 + 1;
do {
printf ("Guess a number between 1 and 10");
scanf ("%d",&answer);
if (secret<answer) puts ("Guess a higher value");
else if (secret>answer) puts ("Guess a lower value");
} while (secret!=answer);
puts ("Congratz!");
return 0;
}
You are ignoring the return value of scanf, which will tell you if the conversion went well or not. scanf will return the number of items assigned, so if it returns 1 you know that answer was assigned to a number. If it returns 0, you know that something went wrong.
What I am trying to do now is to make a check for if the user enters a
string, it will say to the user something like Enter a number, not
text. How do I do this?
scanf does formatted input. You may also want to check out advanced formatting specifiers in scanf -- such as ignoring parts of the input, specifying buffer size for reading in strings, specifying only a particular set of characters that you want to read etc. If you want to verify input, you are probably best of reading a line from the console using fgets and then parsing the line.
Is there anything you see that I can improve in this code?
You may want to improve your random number generation algorithm. Read the C FAQ.
Check the return value of scanf . It will return the number of items successfully matched and assigned. In this case if you enter a string then it will not be matched and assigned, but the string stays in the input buffer, and the scanf tries to read it in each iteration and fails, and thus the problem arises.
You may change the code to:
int main () {
int secret, answer;
srand((unsigned)time(NULL));
secret = rand() % 10 + 1;
do {
printf ("Guess a number between 1 and 10");
if (scanf ("%d",&answer) != 1)
{
printf ("\nPlease enter an integer\n\n");
scanf ("%*s");
continue;
}
if (secret<answer) puts ("Guess a higher value");
else if (secret>answer) puts ("Guess a lower value");
} while (secret!=answer);
puts ("Congratz!");
return 0;
}
Note that inside the if the line scanf ("%*s"); is done. In the %*s the * is the input supression indicator, this tells that a string (stands for %s) will be read but the * tells that although the string will be read from the input, it will be discarded. This is being done to simply discard the previously entered string which is not read by the scanf ("%d",&answer) . In case you do not discard the string in the buffer, it will remain, and each iteration the scanf ("%d",&answer) will fail to match any integer, as it will encounter the leftover string in the input buffer.
On the other hand you may read a string and convert the string to an integer.
Like as below:
int main () {
int secret, answer;
char buff[128];
srand((unsigned)time(NULL));
secret = rand() % 10 + 1;
do {
printf ("Guess a number between 1 and 10");
scanf ("%s",buff);
if ((answer = atoi (buff)) == 0)
{
printf ("\nPlease enter an integer\n\n");
continue;
}
if (secret<answer) puts ("Guess a higher value");
else if (secret>answer) puts ("Guess a lower value");
} while (secret!=answer);
puts ("Congratz!");
return 0;
}
atoi () will convert a string to an integer (in 10 base). If the characters which comprises the integer does not contain valid digits, it will return 0. Checking for it we can detect if the user entered correctly. Also because your application needs to enter an integer within 1 and 10 therefore 0 is not included, therefore it is okay to take 0 as an invalid. To get better control on detecting an invalid integer format, and the location of the error in the string use strtol ()
You may want to make a function to check if the input is numeric. Like:
int isNumeric( char *str){
while(*str)
{
if (!isdigit(*str))
return 0;
str++;
}
return 1;
}
int main(){
char guess[3];
int iGuess;
do {
printf("Guess a number between 1 and 10");
gets(guess);
if (!isNumeric(guess)){
printf("Invalid input");
continue;
}
iGuess = atoi(guess);
if (iGuess<secret)
printf("Higher");
else if (iGuess>secret)
printf("Lower");
} while (secret!=iGuess);
printf("Congrats");
return 0;
}
You need to include ctype.h and string.h
I started learning C programming and in this program I am trying to get user input and then a line at a time and decide if it contains non-int characters. I've been trying this method:
scanf("%d", &n);
if (isalpha(n))
{
i = -1;
}
I googled a bit and learned the function isalpha is good way to do it. However, I'm getting a segmentation fault every time I test the fragment above with non-int characters (letters for example). Any suggestion would be appreciated.
The %d format specifier forces scanf() to only accept strings of digits. Given anything else, it will fail and leave n unfilled (and assuming you didn't initialize n before, it will be filled with garbage).
The crux of the problem is that isalpha() expects a value between 0 and 255, and has an assertion to enforce it. At least on my VC++ compiler, it causes a crash with an access violation when given an invalid value (in non-debug mode).
To solve this you just have to switch to a %c format specifier. Converting n to a char would also be advisable as that makes your intent of reading a single character clearer.
EDIT: Given your clarifications in the comments, you can leave everything as is and simply check the return value of scanf() instead of going the isalpha() route. It returns the number of values read successfully, so when it encounters a non-integer or end of file, it will return 0. E.g.:
int main() {
int n;
while (scanf("%d", &n)) {
printf("Got int: %d\n", n);
}
}
I have no idea why you're getting a seg-fault. I'd have to see more of your program.
But using "%d" for scanf will only accept integer values and you'll get "0" for n that isn't an integer and therefore isalpha(n) will always be false and i will never be set to -1.
Perhaps you aren't initializing i and therefore it is never set. If you are referencing it later, that's probably the source of your seg-fault.
Use scanf("%c", &n), like this:
int main(char** argc, int argv) {
char n = 0;
int i = 0;
scanf("%c", &n);
if (isalpha(n)) {
i = -1;
}
printf("you typed %c, i=%d", n, i);
}
Make sure you have a character buffer to store the value in. Scan it as a string, and then use isalpha():
char buffer[32];
sscanf("%32s", buffer);
// loop and check characters...
if(isalpha(buffer[i])) ....
Note the use of %32s, this is to prevent buffer overflows (32 == size of buffer)
Given that n is an integer, we can diagnose that you are reading a value into n which is not in the range 0..255 plus EOF (normally -1), so that the code for isalpha(n) is doing something like:
(_magic_array[n]&WEIRD_BITMASK)
and the value of n is causing it to access memory out of control, hence the segmentation fault.
Since scanf():
Returns the number of successful conversions, and
Stops when there is a non-integer character (not a digit or white space or sign) in the input stream,
you can use:
#include <stdio.h>
int main(void)
{
char n = 0;
while (scanf("%c", &n) == 1)
printf("you typed %d\n", n);
return 0;
}