I've been trying to write out code that takes input from the user, stores it into a char array, and then identifies the input as a positive or negative integer, a positive or negative decimal, or a character string. So far this is the code I have.
void input() {
char userInput[500];
printf("Enter something: ");
fgets(userInput, 500, stdin);
for (int i = 0; i < strlen(userInput); i++) {
if (isdigit(userInput) == 0) {
printf("This is not a digit.\n");
}
}
}
I'm aware that trying to use a char array with isdigit() will not work. I'm having issues figuring out how to get around this. I'm assuming it would be possible to run through the array and identify what the input is. And I assume there is a way to cast the char array into an int so isdigit would work, but I'm a bit stumped. Any suggestions?
There seems to be some confusion between digit, which is a character between '0' and '9' and integer which is a number composed of such digits with an optional leading sign.
You can use isdigit() defined in <ctype.h> to check if a character is a digit, but testing if the string encodes a number is a different question.
Passing a char to isdigit() has undefined behavior is the char value is negative because isdigit() is only defined for a values of the type unsigned char and the special negative value EOF. To test if a char is a digit, you can write isdigit((unsigned char) userInput[i]).
To test if the string contains a number, you can use strtol(), and to test for a floating point value (which I assume you mean by decimal), you can use strtod().
You can also use sscanf(), which is probably easier for a simple program.
Here is a modified version:
#include <stdio.h>
void input() {
char userInput[500];
printf("Enter something: ");
if (fgets(userInput, sizeof(userInput), stdin)) {
int n;
double d;
char c;
/* try converting as an int,
test if the conversion succeeds
check that no trailing character is present.
sscanf returns the number of successful conversions
*/
if (sscanf(userInput, "%d %c", &n, &c) == 1) {
printf("string contains an integer %d\n", n);
} else
if (sscanf(userInput, "%lf %c", &d, &c) == 1) {
printf("string contains a double %g\n", d);
} else {
printf("string is an ordinary string: %s\n", userInput);
}
}
}
Note however that the above tests will accept leading and trailing whitespace and may invoke undefined behavior if the number cannot be represented in the target types.
You can use simple heuristics based on the character types to distinquish between integer, floating point, or string.
Introduce some new variables:
int slash = -1;
int digits = 0;
int chars = 0;
int decimals = 0;
int isNumber = 0;
int isNegative = 0;
int isFloat = 0;
int len;
Then your scanning code is this:
len = strlen(userInput);
for (int i = 0; i < len i++) {
if (userInput[i] == '-') {
slash = i;
}
else if (userInput[i] == '.') {
decimals++;
}
else if ((userInput[i] >= '0') && (userInput[i] <= '9')) {
digits++;
}
else {
chars++;
}
}
And then you can print the result as:
// NOT A NUMBER if:
// a dash anywhere but index 0
// more than one decimal
// no digits
// anything else that isn't a digit
isNumber = ( ((slash == -1) || (slash == 0)) &&
(decimals <= 1) &&
(digits > 0) &&
(chars == 0)
);
if (isNumber) {
isFloat = (decimals == 1);
isNegative = (slashPos == 0);
printf("string contains a %s %s: %s\n", (isNegative ? "negative" : "positive"), (isFloat ? "double" : "integer"), userInput);
}
else {
printf("string contains an ordinary string: %s\n", userInput);
}
}
Related
The program receives the data, but treats the string ("20x") as an integer.(This is not my code, I found it on the internet.)
// C program to find data type
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
# define MAX_INPUT 100
int main()
{
// To read input
char value[MAX_INPUT] = "";
// To store numeric value of input if a
// number (float or integer)
double temp;
// To store integral value of input
int n;
// To store string value of input
char str[MAX_INPUT] = "";
// Precision for integer checking
double val = 1e-12;
fgets(value, 100, stdin); // Read input
// Check for integers.
if (sscanf(value, "%lf", &temp) == 1)
{
n = (int)temp; // typecast to int.
if (fabs(temp - n) / temp > val)
printf("The input is a floating point\n");
else
printf("The input is an integer\n");
}
// Check for string
else if (sscanf(value, "%s", str) == 1)
printf("The input is a string\n");
else // No match.
printf("input not recognized\n");
}
So, If we enter "20x" for example, we will get a message "The input is an integer".
I tried changing datatypes and array values, but it still didn't work as it should. Maybe it's a bug of this language.
Thank you.
OP's code fails to check for trailing non-numeric text.
Further, the fabs(temp - n) / temp > val is at best - dodgy. At worst, it is worthless - consider value < 0 always reports as "The input is an integer\n".
(int)temp is UB when temp far out of int range.
A robust test of a string for a valid int does not need a floating point test.
To check if the input string is a integer, directly use strtol() instead of sscanf(). It is more tightly defined.
char *endptr;
errno = 0;
long lval = strtol(value, &endptr, 0);
// If no conversion or out of range.
if (endptr == value || errno == ERANGE) {
printf("The input is not an `long`\n");
} else {
// Tolerated trailing white-space.
while (isspace(*(unsigned char *)endptr)) {
endptr++;
}
// If junk at the end or out of int range.
if (*endptr != 0 || lval < INT_MIN || lval > INT_MAX) {
printf("The input is not an `int`\n");
} else {
printf("The input is an int\n");
}
}
Or not quite as robust, use "%n" to record scanning offset. It does not certainly detect overflow (UB).
int n = 0;
int val;
// v---- Optional spaces
// | v-- Scanning offset
sscanf(value, "%d %n", &val, &n);
if (n && value[n] == 0) {
puts("Success");
} else {
puts("Fail");
}
The key of this program is sscanf() and what the function returns. The sscanf() function returns the number of fields that were successfully converted and assigned. The return value does not include fields that were read but not assigned.
The return value is EOF when the end of the string is encountered before anything is converted. source
The program first checks if there are any double or integer values on the string. Then it checks for non-numeric character strings. So if the input is "20X" or any "1234abcd" the temp value is successfully assigned as 20(for 20X input) or 1234 (for 1234abcd input). So the final verdict is an integer.
Hope this code will help in your purpose to find the datatype of input.
// C program to find data type
#include <stdio.h>
#include <string.h>
# define MAX_INPUT 100
void check_type(char strIn[]){
int dotFlag = 0 ;
int dotPos = 0 ;
int firstSignCheck = 1 ;
int len = strlen(strIn) ;
//checking for string and counting '.'
for (int i = 0 ; i < len ; i ++ ) {
if((strIn[i] == '+' || strIn[i] == '-') && firstSignCheck == 1 ) //skipping first '+' and '-'
continue ;
else
firstSignCheck = 0 ;
if((strIn[i] < '0' || strIn[i] > '9') && strIn[i] != '.') { //if any character out of 0-9 and '.' it is string
printf("The input is string") ;
return ;
}
if(strIn[i] == '.'){ //counting dots and keeping the position
dotFlag ++ ;
dotPos = i ;
}
}
if(firstSignCheck == 1) { // if all are '+' or '-'
printf("The input is string") ;
return ;
}
if(dotFlag > 1) { //if several '.' its a string
printf("The input is string") ;
return ;
}
else if(dotFlag == 0 ) { // no '.' integer
printf("The input is integer") ;
return ;
}
else{
for (int i = dotPos + 1 ; i < len ; i++) { // after '.' checkin for zeros
if(strIn[i] != '0') { // any nonzeros float
printf("%c" ,strIn[i] ) ;
printf("The input is float/double") ;
return ;
}
}
printf("The input is integer") ; // no non zero ineger
return ;
}
}
int main()
{
// To read input
char value[MAX_INPUT] = "";
// To store string value of input
char str[MAX_INPUT] = "";
//input string
scanf("%s" , value) ;
//checking datatype
check_type(value) ;
}
I have a file which stores values like 2.32x7.
I read the floating-point part using:
fscanf(file, "%lf", &value);
It works perfectly... except for when the file stores something like 0x2. In that case, it reads the entire string as a hexadecimal value.
How can I prevent this from happening?
I would like fscanf to just read 0 and ignore x2.
Edit:
As suggested by #dbush, I am adding a sample input file.
I am parsing polynomials. So, the input file will be something like:
0x2+2.32x7-4x-9
Runnable example.
For your purpose, you should read the full polynomial with fgets() and parse it with as hoc code using strtod() and strtol():
#include <errno.h>
#include <stdlib.h>
int parse_polynomial(struct polynomial *p, const char *s) {
for (;;) {
double factor = 1;
int exponent = 0;
char *p;
while (isspace((unsigned char)*s) {
s++;
}
if (*s == '\0')
break;
if (*s == '+') {
s++;
} else
if (*s == '-') {
factor = -1;
}
if (*s != 'x') {
errno = 0;
factor *= strtod(s, &p);
if (p == s || errno != 0) {
/* parse error */
break;
}
s = p;
}
if (*s == 'x') {
exponent = 1;
s += 1;
if (isdigit((unsigned char)*s) {
unsigned long ul;
errno = 0;
ul = strtoul(s, &p, 10);
if (p == s || errno != 0 || ul > INT_MAX)
break;
exponent = (int)ul;
s = p;
}
}
add_component(p, factor, exponent);
}
return (*s == '\0') ? 0 : -1;
}
Reading the line with fgets() and then parsing with crafted code is the most robust.
To read text as a single floating point number with fscanf() up to an 'x', first read with a scanset and then convert.
char buf[400 + 1]; // Something large - consider DBL_MAX may be 1e308
// Scanset of expected FP characters
#define FP_FMT " %400[-+.eE0-9]"
// or maybe simply
#define FP_FMT " %400[^x]"
if (fscanf(FP_FMT, buf) == 1 && sscanf(buf, "%lf", &value) == 1) {
// Success
Pedantic code would use strtod() instead of sscanf(buf, "%lf", &value).
Other consideration include locale use of ',' as the decimal point, NAN, infinity, even wider text as wee exact FP values, how to handle ill formatted text, input errors, EOF, ...
Consider scanning the pair of value and exponent in 1 step.
if (fscanf(FP_FMT "x%d, buf, &power) == 2 && sscanf(buf, "%lf", &value) == 1) {
❗❗❗ Incorrectly handles numbers with dots...
Thinking, how to fix that.
You can read the numeric characters, then parse number from the string: example
#include <stdio.h>
int main()
{
double value;
char s[32];
*s = 0;
scanf("%31[0-9]", s);
sscanf(s, "%lf", &value);
printf("%f\n", value);
scanf("%3s", s);
puts(s);
}
If you need negative numbers too: example
#include <stdio.h>
int main()
{
double value;
char s[32];
*s = 0;
scanf("%1[-+]", s);
scanf("%30[0-9]", s+!!*s);
sscanf(s, "%lf", &value);
printf("%f\n", value);
scanf("%3s", s);
puts(s);
}
Note that the last code eats the sign even if it's not followed by digits.
Instruction: Alright, I am working on a code where I am doing number conversions. I am prompting the user to give me a base and an input of bits with a mathematic symbol such as '+', '-', '*' etc, and I do the calculation, if you have a strategy for that, then feel free to give me an idea.
Problem: Regardless, I am working on some strategy on how to do it, but I am having trouble with my character, strings, char pointers. I don't know how to resolve it. I hardly understand what pointers are, besides a location in memory. I need help resolving this problem.
baseToDec Function: Anyways, I have a method/function called baseToDec, where I perform a conversion from bits to a decimal and return an int. Inside those parameters, I have a char* which takes in the value. such as '1001' which is the value 9.
Ways: However, when I put in the string "first" inside that parameter down in my main, I get a fault segmentation. I don't know how to declare that string value where I won't get warnings or a segmentation fault. I've tried changing the variable to be a char *first, I tried to do the address. I don't understand it. I would like to know how I can do it so I don't get a warning and it returns an integer smoothly.
int baseToDec(int base, char* value)
{
int len = strlen(value);
int power = 1, result = 0,i, j, num;
if(base > 2) //not binary
{
for (i = len - 1; i >= 0; i--)
{
result += number(value[i]) * power;
power = power * base;
}
}
else if(base = 2)
{
while(value[i] == '0' || value[i] == '1' )// (2) remove the most significant binary digit(leftmost) and add it to the result.
{
if(value[i] == '1')
{
result = result * 2 + 1;
}
else if(value[i] == '0')
{
result *= 2;
}
i++;
} // (3) If all binary digits have been removed, you're done. Stop.
}
return result;
}
int main()
{
int base, i = 0, j =0, dec; // dec is declared here.
char input[100], first[100], second[100];
char option;
instructions();
scanf("%s", &option);
while(option != 'q')
{
i = 0;
printf("Base: ");
scanf("%d", &base);
printf("Input: ");
scanf("%s", input);
while(input[i] != '+' && input[i] != '-' && input[i] != '*' && input[i] != '/')
{
i++;
}
printf("%d", i);
if(input[i] == '+')
{
for(j = 0; j < i; j++)
{
first[j] = input[j];
}
first[i] = 0;
dec = baseToDec(base, first); // Error takes place here.
}
}
I know it's a lot of writing, but I listed where the errors take place and the method I pass.
This is wrong:
scanf("%s", &option);
When you use %s, you have to provide a pointer to a string that can hold the entire input. option is a char, not a string. It only has room for a single character, but %s writes the input word followed by a null terminator.
Use %c format to read a single character.
scanf(" %c", &option);
Also,
if (base = 2)
should be
if (base == 2)
But there's no need to treat binary differently from any other base, the conversion process is the same.
First, I apologize if the question doesn't make sense as my English isn't that good...
My question is, how do we print out different things depending on the user input?
What I'm trying to do is: when user inputs integer, the program prints out the inputted number. When the user inputs something that's not integer (like symbols and characters), the program prints out "not integer".
my current idea (pseudo-code) is as follows:
`int main(){
int value;
printf("Enter numbers");
scanf("%d", &value);
if(value is integer){
printf("%d", value);
} else {
printf("not integer");
}
return 0;
}`
what gets me is the scanf; by using %d, I'm assuming that the user will input an integer values, but the user can input values that are not integers so I can't make a comparison using the if statement if( value is integer). How can I make a comparison that will determine whether the inputted value is integer or not?
I don't know if this is a good thing or not.
You can use ASCII to check if the input type is an integer or not
(between 48 - 57 in ASCII)
it will be like this
char value;
int flag = 0; //to check true or false (0 means false, and 1 means true)
printf("Enter numbers");
scanf("%c", &value);
for(int i = 48; i <= 57; i++){
if(value == i){
flag = 1;
break;
}
}
if(flag == 1){
printf("%c", value);
} else {
printf("not integer");
}
How do you print different things depending the user input?
Step 1: Read the line of user input
char buf[100];
if (fget(buf, sizeof buf, stdin)) {
// something was entered
Step 2: test the string
char *end;
long value = strtol(buf, *end);
// If the end is the same as the beginning, no conversion occurred.
if (end == buf) {
puts("not integer");
}
printf("%ld\n", value);
}
}
Additional code could look for input that occurred after the integer. Also code could test for a large number that overflowed the long range.
The code is as follows. It caters for different situations like inputting negative numbers and decimal numbers:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
char input[20];
int wrongFlag = 0;
scanf("%s", input);
if (input[0] == '0' && strlen(input) > 1) {
wrongFlag = 1;
//for number starts with 0, and string length>1 eg: 010
}
for (int i = 0; i < strlen(input); i++) {
if (i == 0 && (input[i] == '-' && strlen(input) > 2 && input[i + 1] == '0')) {
//check first round only: negative number with length >2 and starts with 0 eg: -010.
wrongFlag = 1;
continue;
}
if (i != 0 && !isdigit(input[i])) {
//check following rounds, check if it is not digit
wrongFlag = 1;
break;
}
}
if (wrongFlag) {
printf("Not integer");
}
else {
printf("integer");
}
return 0;
}
Try this it works for me.
#include<stdio.h>
#include<string.h>
int main()
{
int i;
char value[50];
int len;
printf("Enter maximum 50 digits\n");
/* enter the values you wanted*/
printf("Enter the value: ");
gets(value);
len = strlen(value);
/*it will iterate upto the end of the user input*/
for(i=0;i<len;i++)
{
if(48<value[i] && value[i]<=57)
{
if(i==(len-1))
printf("It's an integer");
}
else{
printf(" Not an integer");
break;
}
}
return 0;
}
I've searched in and out of these forums but am still having trouble. My understanding of C is still very basic. I'm creating a small program that takes 3 numerical values entered by the user and then calculates the highest. I nailed that.
I now want to ensure that the user enters only integer values. I managed to get the prog to keep prompting the user to re-enter the value until it is within the specified numerical range (for example, any number between 1 and 1000 inclusive, piece of cake) but that's not good enough. I used 3 while loops to test each value, but this only works as long as the input is of type integer.
The trick is I cant use built in functions. It needs to be manual (sorry, poor choice of words) I tried to use char variables and x = getchar(); to get the ASCII value and test it in a condition but I can't get it working in a loop. (while/ do-while)
I also tried using a "for loop" and array variables but once again am struggling to get it to keep prompting the user.
I've also tried to test the value returned by scanf to see if its integer but my knowledge level of correct C syntax is level: noob. Either my loops don't loop or they loop infinitely.
Here is some sample code:
int x, y, z =0;
printf("Enter the first number:\n");
scanf("d", &x);
while (condition) /* Here is where I need to determine that the entered val is false */
{
printf("Wrong input. Re-enter a valid value.\n");
x =0;
scanf("%d", &x); /*user re-prompted */
}
I'm getting the idea that I'll have to use ASCII and a loop, but I just can't get to it. Also, the values entered get sent to a function for comparing and are then returned.
Could someone give me some advice and a few tips please?
Much thanks
You would have to use something like fgets, and strtol:
long someValue;
char *bufEnd = NULL;
char buf[128]; // max line size
do {
printf("enter a value: ");
fgets(buf, 128, stdin);
someValue = strtol(buf, &bufEnd, 10); // base 10
} while (bufEnd == buf || *bufEnd != '\n');
printf("got value: %li", someValue);
What we are doing here is we are tapping into strtol's capability to tell us where it stopped parsing, by passing in bufEnd.
Then, we are making sure that bufEnd doesn't point to the beginning of buf (in which case, it didn't start with a number), and also checking to make sure that bufEnd points to \n, or the end of the line (making sure that the user didn't enter something like 123abc, which strtol would interpret as 123). You may wish to trim buf of whitespace characters first, however.
You're absolutely on the right track with "scanf()". Just check the return value. If you don't get the expected #/values, then you got invalid input:
char found = FALSE;
int ival;
double x;
while (!found)
{
printf("Please enter a valid integer: ");
if (scanf("%d", &ival) !=1) {
printf ("Invalid! Please re-enter!\n");
continue;
}
printf("Please enter a valid floating point number: ");
if (scanf("%lf", &x) !=1) {
printf ("Invalid! Please re-enter!\n");
continue;
}
found = TRUE;
}
Here's my solution. It safe against buffer overflow and straightforward .
#include <stdio.h>
#define LEN 10
int main() {
int a;
char str[LEN];
fgets( str, LEN, stdin );
while ( !sscanf( str, "%d", &a ) )
fgets( str, 10, stdin );
printf("Num is : %d\n", a);
return 0;
}
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
int getInteger(int* err){
int ch;
int n;//int32
int takeNum, sign;
long long int wk;//long long int as int64
wk=0LL;
*err = 0;
takeNum = 0;//flag
sign = 1;//minus:-1, other:1
/* //skip space character
while(EOF!=(ch=getchar()) && (ch == ' ' || ch == '\t' || ch == '\n'));
ungetc(ch, stdin);
*/
while(EOF!=(ch=getchar())){
if(ch == '-'){
if(takeNum != 0){//in input number
*err = 1;
break;
}
if(sign == -1){//already sign
*err = 2;
break;
}
sign = -1;
continue;
}
if(ch >= '0' && ch <= '9'){//isdigit(ch) in ctype.h
if(takeNum == 0)
takeNum = 1;
wk = wk * 10 + (ch - '0')*sign;
if(INT_MAX < wk || INT_MIN > wk){//overflow
*err = 3;
break;
}
continue;
}
if(ch != '\n'){//input other [-0-9]
*err = 4;
}
break;
}
if(takeNum == 0){//not input number
*err = 5;
} else {
n=wk;
}
while(ch != '\n' && EOF!=(ch=getchar()));//skip to newline
return n;
}
int getValue(const char* redoprompt, int low, int high){
int num, err=0;
while(1){
num = getInteger(&err);
if(err || low > num || high < num)
printf("%s", redoprompt);
else
break;
}
return num;
}
#define max(x,y) ((x)>(y))? (x) : (y)
int main(){
const char *error_message = "Wrong input. Re-enter a valid value.\n";
int x, y, z, max;
x = getValue(error_message, 1, 1000);
y = getValue(error_message, 1, 1000);
z = getValue(error_message, 1, 1000);
max = max(max(x,y), z);
printf("max:%d\n", max);
return 0;
}