I'm trying to write a function to get a decimal input from the user and return the actual value converted from ASCII. However, the function causes the next input from the user to be skipped. As in:
Enter input: 123
Enter input: /* doesn; allow for input */
Enter input: 456
long sum = 0;
int character = fgetc(stdin);
while(character != '\n'){
if(character >= '0' && character <= '9'){
/* convert from ASCII */
character -= '0';
sum = sum * 10 + character;
}
else{
/* reenter number */
}
character = fgetc(stdin);
}
return sum;
To figure out why your code doesn't work, I suggest you post your full code, because problems may lie in the way you call this function.
So before full code is posted, I can just tell you that this code works well on my machine:
#include <stdio.h>
#include <ctype.h>
int getlong();
int main() {
printf("\t%d\n", getlong());
printf("\t%d\n", getlong());
return 0;
}
int getlong() {
long sum = 0;
int character = fgetc(stdin);
while (character != '\n') {
if (isdigit(character)) {
/* convert from ASCII */
character -= '0';
sum = sum * 10 + character;
character = fgetc(stdin);
}
else {
character = fgetc(stdin);
continue;
}
}
return sum;
}
ctype.h is included in order to use isdigit(), while tells you whether a character is decimal digit.
But in fact, you don't have to do everything on your own. Using standard library is more effective and efficient, both for you and for the computer.
For example, you can scan a long integer directly from stdin:
#include <stdio.h>
int main() {
long value;
puts("Please input numbers:");
while (scanf(" %ld", &value) != 1) {
puts("Only numbers are welcome:");
scanf("%*[^\n]");
}
printf("%ld", value);
return 0;
}
Notice the white-space at the beginning of format, this makes scanf() discard all white-space characters(including spaces, newline and tab characters) extracted until a non-white-space character is met.
Or, use strtol(), while is relatively rarely seen:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char buf[80];
char *pEnd;
long value;
do
{
puts("Numbers please:");
if (fgets(buf, 80, stdin) == NULL)
{
perror("fgets()");
return 1;
}
value = strtol(buf, &pEnd, 10);
}
while (*pEnd != '\n');
printf("%ld", value);
return 0;
}
Of course, sscanf() also works, you can just write the code on your own.
From comments:
an extra newline in the stdin buffer...
Try replacing your current method with scanf() using following format string:
char* fmt = "%[^\n]%*c";
It reads everything up to the newline, then consumes the newline. * is an assignment suppressor.
Example: (includes functions to convert input string to float/integer number)
float get_float(void);
long get_int(void);
int main(void)
{
float num_f = get_float();
long num_i = get_int();
return 0;
}
float get_float(void)
{
char input[80];
char **dummy={0};
char* fmt = "%[^\n]%*c";
printf("Enter floating point number and hit return:\n");
scanf(fmt, input);
return strtod(input, dummy);
}
long get_int(void)
{
char input[80];
char **dummy={0};
char* fmt = "%[^\n]%*c";
printf("Enter integer number and hit return:\n");
scanf(fmt, input);
return strtol(input, dummy, 10);
}
Note: These functions are bare bones illustrations of how converting input into number variables might be done, and were written without any error or range checking. As the commenter has stated, it would be worth your while before implementing production versions to read up on strtol() and strtof in detail. (Links are to the Linux man pages, but because both functions are part of the C standard libraries, documentation can also be found on MSDN here and here)
Why not just use fgets and sscanf?
char buf[80];
float n;
if (fgets(buf, 80, stdin) != NULL) {
if (sscanf(buf, "%f", &n) == 1)
printf("%f\n", n);
else
fprintf(stderr, "invalid float\n");
}
Related
This might be a rookie question, but I need to make sure that the input given by the user is of data type char [%c] or a string [%s].
If it were an integer, I would just do something like this:
int data, x;
do {
printf("Please enter a number: ");
x = scanf(" %d", &data);
getchar();
} while(x!=1);
So I was wondering if there's a similar way to do this, if the input is supposed to be a string or a character. Thanks, Any help would be appreciated!
Avoid to use %c in scanf() because some unexpected character like \r\n will be input.
You can use a char[2] to receive a single character. An \0 will be filled after your string to represent the end of string, so the length of array must be bigger than 1.
An example:
#include <stdio.h>
int main()
{
char data[2];
scanf("%1s", data);
if (data[0] >= 'a' && data[0] <= 'z') // custom your constraint here
{
// legal
printf("legal: %s", data);
}
else
{
// illegal
printf("illegal: %s", data);
}
return 0;
}
While I input b, the data will be "b\0".
part of the answer is if you just want to read only alphabet you can use below.
#include <stdio.h>
#include <ctype.h>
int main()
{
char ch;
do {
printf("enter a char:");
scanf(" %c",&ch);
}while(!isalpha(ch));
printf("%c",ch);
return 0;
}
Update 1:
Just for the completeness and for the FUN part of the programing, have added code here.
This works well (not tested robustly, you can do if you need to) for the single char input or for a string of length 9.
Remember to type the EOF after input is entered in case length of input is < 9.
and read EOF behavior on same line and new line.
#include <stdio.h>
#include <ctype.h>
#define LEN 10
int main()
{
char ch;
char str[LEN] = {0};
int i = 0;
int ret;
printf("enter a char or string(len = 9) and press EOF if len < 9\n");
do {
if(1== (ret = scanf(" %c",&ch)))
{
if(isalpha(ch))
str[i++] = ch;
}
else
printf("scanf:Error (%d)\n", ret);
}while(ret != EOF && ( !isalpha(ch) || i < LEN-1));
str[i] = '\0';
printf("str is %s\n",str);
return 0;
}
Actually, I can easily found a similar question in Google, but it still can not solve my question.
How to prevent non-numeric input in C?
The upper-link is like a similar case.
Here is my code
#include <stdio.h>
int main()
{
int n;
printf("Enter 1 or 2?\n");
scanf("%d", &n);
while(n != 1 && n != 2)
{
printf("Please do not enter other characters\n");
printf("Enter 1 or 2?\n");
scanf("%d", &n);
}
}
I hope if users enter other numbers(e.g. 1, 45, 656), characters (e.g. a, f, u, e), or string(e.g. apple), the upper program can print out an error message and ask for user input again.
Yes! if users enter other numbers, the program can do what I want.
But! if users enter other characters, string, the program will keep looping.
What should I need to add to this program?
How to prevent non-numeric input in C & ask user input again
Do not use scanf()**. Use fgets().
scanf("%d", ...) does not consume non-numeric input. Instead that offending input remains in stdio for the next scanf().
Code cannot prevent non-numeric input unless it locks the keys from being pressed. Instead, read all input, identify the non-numeric text, toss it and present the user with feedback for new input.
Make a helper function to control impact on rest of code.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
// return -1 on EOF
int read_int_in_range(const char *prompt, const char *reprompt, int lo, int hi) {
if (prompt) {
fputs(prompt, stdout);
fflush(stdout);
}
char buf[100];
while (fgets(buf, sizeof buf, stdin)) {
char *endptr;
errno = 0;
long val = strtol(buf, &endptr, 10);
// no overflow, conversion occurred, in range
if (errno == 0 && endptr > buf && val >= lo && val <= hi) {
// Tolerate trailing white-space.
while (isspace((unsigned char ) *endptr)) {
endptr++;
}
// No junk after the numeric text
if (*endptr == '\0') {
return (int) val;
}
}
if (reprompt) {
fputs(reprompt, stdout);
fflush(stdout);
}
}
return EOF; // or `INT_MIN` or TBD code to distinguish `int` from an error.
}
Usage
const char *prompt = "Enter 1 or 2?\n";
const char *reprompt = "Please do not enter other characters\n" "Enter 1 or 2?\n";
int n = read_int_in_range(prompt, reprompt, 1, 2);
**I recommend to not use scanf() anywhere to read user input until ones understands its weaknesses and limitations.
scanf is meant for formatted input, ie: you know what input will be received, in this case the user may enter something other than an int and your program breaks down. So to deal with that unknown treat the input as a string then analyze the string. In this case you could capture the input in buf and use the function atoi to convert it to an int, like this:
#include <stdio.h>
#include <stdlib.h> /* for atoi */
int main()
{
int n;
char buf[10]; /* this is new */
printf("Enter 1 or 2\n");
/*scanf("%d", &n);*/
fgets(buf, 10, stdin);
n = atoi(buf);
while(n != 1 && n != 2)
{
printf("Please do not enter other characters\n");
printf("Enter 1 or 2?\n");
/*scanf("%d", &n);*/
fgets(buf, 10, stdin);
n = atoi(buf);
}
}
fgets is the way to do this, but wanted to post something like this to actually avoid fgets as asked. It may be of some interest. The appending part should've been delegated to some function and buffer size may've not been 10. Anyways:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define endl "\n"
int main (void)
{
int my_char = 0;
short bad = 0;
char text[10];
memset (text, 0, 10);
printf ("enter number: ");
while ( (my_char = getchar()) )
{
if ( my_char < '0' || my_char > '9' )
{
if ( my_char != '\n' ) bad = 1;
}
else
{
size_t len = strlen (text);
char *strtemp = malloc (len + 2);
strcpy (strtemp, text);
strtemp [len] = my_char;
strtemp [len + 1] = '\0';
strncpy (text, strtemp, 9);
free (strtemp);
}
if ( my_char == '\n' )
{
if ( bad )
{
printf ("enter again (just numbers): ");
fflush (stdout);
bad = 0;
memset (text, 0, 9);
}
else break;
}
}
printf ("entered: %s"endl, text);
}
I want to check if a number given by a user is an integer or not in another way i want to verify if the input data is between −(2)^31= −2,147,483,648 and ((2)^31) - 1 =2,147,483,647
this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int x;
int y = pow(3,31) * (-1);
int z = pow(3,32) - 1;
printf("\n\ty = %d et z = %d \n\n", y, z);
scanf("%d", &x);
if ((x < y) || (x > z)) {
printf("x is not an integer");
}
else {
printf("x is an integer");
}
return 0;
}
But while running the program the result always showing me x is integer even if x is greater than 2,147,483,647 or lesser than −2,147,483,648.
Testing whether input is a valid int decimal numeral or is a decimal numeral in [-231, 231) is actually a bit complicated. The C standard does not provide a direct way to do this. What we can do is:
Read characters and check to see whether they are in the expected form: spaces, an optional minus sign (hyphen), and digits. (Any non-digits after the digits will be allowed and ignored.)
Try using strtol to convert the numeral to a long. We use strtol because there is no C-standard library routine for converting to an int (or your fixed bounds using 231) that provides error indications.
Compare the long produced by strtol to the int bounds.
Example code for int bounds follows. If you want bounds of -2147483648 and 2147483647 instead, substitute those for INT_MIN and INT_MAX. To be completely safe, the code should actually use long long and strtoll, since the C standard does not require long to be able to represent −2147483648.
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// Prepare a buffer.
size_t BufferSize = 100, BufferUsed = 0;
char *Buffer = malloc(BufferSize * sizeof *Buffer);
// Skip white space.
int c;
do
c = getchar();
while (isspace(c));
if (c == EOF)
{
printf("Input is not an int: EOF before \"-\" or digit seen.\n");
exit(EXIT_SUCCESS);
}
// Accept a hyphen as a minus sign.
if (c == '-')
{
Buffer[BufferUsed++] = c;
c = getchar();
}
// Accept digits.
while (isdigit(c))
{
Buffer[BufferUsed++] = c;
if (BufferSize <= BufferUsed)
{
BufferSize *= 2;
printf("Realloc: size = %zu, used = %zu.\n", BufferSize, BufferUsed);
char *NewBuffer = realloc(Buffer, BufferSize * sizeof *NewBuffer);
if (!NewBuffer)
{
fprintf(stderr, "Error, unable to allocate %zu bytes.\n",
BufferSize);
exit(EXIT_FAILURE);
}
Buffer = NewBuffer;
}
c = getchar();
}
// Ensure we saw at least one digit (input is not blank or just a hyphen).
if (BufferUsed == 0 || BufferUsed == 1 && Buffer[0] == '-')
{
printf("Input is not an int: No digits present.\n");
exit(EXIT_SUCCESS);
}
// Put back the unaccepted character, if any.
if (c != EOF)
ungetc(c, stdin);
// Terminate the string.
Buffer[BufferUsed] = 0;
// Attempt to convert the numeral to long.
char *End;
errno = 0;
long x = strtol(Buffer, &End, 10);
// Test whether strtol succeeded.
if (*End)
{
/* I do not expect this to occur since we already tested the input
characters.
*/
printf("Input is not an int: strtol rejected %c.\n", *End);
exit(EXIT_SUCCESS);
}
if (errno == ERANGE)
{
printf("Input is not an int: strtol reported out of range.\n");
exit(EXIT_SUCCESS);
}
if (x < INT_MIN || INT_MAX < x)
{
printf("Input is not an int: Value is outside bounds.\n");
exit(EXIT_SUCCESS);
}
printf("Input is an int, %ld.\n", x);
free(Buffer);
}
Maybe i think i should store the number on a char array and check if it contains the float character '.'
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main(){
char number[10];
int flag=0,i = 0;
printf("\n\nEnter a number: ");
scanf("%s", number);
while(number[i++] != '\0'){
if(number[i] == '.'){
flag = 1;
break;}}
if(flag)
printf("\n\n\n\tyou Entered a Floating Number not an integer number\n\n");
else
printf("\n\n\n\t you Entered an integer Number\n\n");
return 0;}
I am new in proggraming and i can't solve a problem. So i have to scanf and check if it is an integer (int n), and than read n floats (with checking if they are floats). Problem is that machine tests add multiple floats separeted by space in input and i don't know how to get these numbers.
I wrote something like this:
int n;
if(!scanf("%d", &n)){
printf("Invalid input");
return 1;
}
float *tab = malloc(n*sizeof(float));
printf("Enter variables: ");
for(int i=0; i<n; i++){
if(scanf("%f", (tab+i))!=1){
printf("Incorrect input data");
return 2;
}
}
I don't know if it is good and what to do if you input less or more numbers in input.
Guys, please explain me what is wrong here and how to solve it.
Thanks for your time.
How to scanf multiple inputs separated by space in C?
The "%d" and "%f" will happily handle numeric text separated by spaces, tabs, end-of-lines, etc., yet not distinguish between spaces and end-of-line. With insufficient input in one line, code will read the input of the next line. With excess input, the entire line is not read - rest of line reamins for next input function.
If OP is concerned about lines of inputs, best to read a line of input and then parse.
I don't know if it is good and what to do if you input less or more numbers in input.
Put yourself in charge: if you directed a team of coders, what would you want? Consume and ignore non-numeric input, consume input and report an error, simple end the code, etc.
Aside from the first scan, code looks reasonable as is.
For me, for robust code, I would drop all scanf() and use fgets() in a helper function to parse. Then sscanf() or strto*() to parse and complain if not as expected.
Sample
Of course this helper function is overkill for such a simple task, yet it is a helper function - one that I can use over and over for anytime I want to read a a group of float from one line. I can improve as desired (e.g. more error handle, handle overly long lines, ...)
// Read 1 line of input.
// return EOF on end-of-file or stream error,
// else return number of float read, even if more than N.
int get_floats(const char *prompt, float *dest, int N) {
if (prompt) {
fputs(prompt, stdout);
fflush(stdout);
}
char buf[BUFSIZ];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return EOF;
}
char *endptr = buf;
int floats_read = 0;
// parse the line into floats
while (*endptr) {
const char *s = endptr;
float f = strtof(s, &endptr);
if (s == endptr) {
break; // no conversion
}
if (floats_read < N) {
dest[floats_read] = f;
}
floats_read++;
}
// Consume trailing white-space
while ((unsigned char) *endptr) {
endptr++;
}
if (*endptr) {
return -1; // Non-numeric junk at the end
}
return floats_read;
}
Usage:
int n;
if(get_floats("Enter variables: ", tab, n) != n) {
printf("Invalid input");
return 1;
}
The answer is really simple: put a space in front of your scanf format specifier. That tells scanf to eat all the whitespace before converting.
Like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
if (1 != scanf(" %d", &n)) {
exit(1);
}
float *tab = calloc(n, sizeof *tab);
if (!tab) {
exit(3);
}
for (int i = 0; i < n; ++i) {
if (1 != scanf(" %f", &tab[i])) {
exit(2);
}
}
const char *sep = "";
for (int i = 0; i < n; i++) {
printf("%s%f", sep, tab[i]);
sep = ", ";
}
printf("\n");
free(tab);
return 0;
}
I'm trying to create a function which can determine if an input can be converted perfectly into a double and then be able to store it into an array of doubles. For example, an input of "12.3a" is invalid. From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer. In my function doubleable, it filters whether the input string consists only of digits. However, I'm aware that double has "." like in "12.3", and my function will return 'X' (invalid).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char doubleable (char unsure[], int length){
int i;
int flag;
for (i=0; i<length; i++ ){
if(isdigit(unsure[i]==0)){
printf("You have invalid input.\n");
flag=1;
break;
}
}
//check for '.' (?)
if(flag==1)
return 'X';
else
return 'A';
}
int main(){
char input [10];
double converted[5];
char *ptr;
int i;
for(i=0; i<5; i++){
fgets(input, 10, stdin);
//some code here to replace '\n' to '\0' in input
if(doubleable(input, strlen(input))=='X'){
break;
}
converted[i]=strtod(input, &ptr);
//printf("%lf", converted[i]);
}
return 0;
}
I'm thinking of something like checking for the occurrence of "." in input, and by how much (for inputs like 12.3.12, which can be considered invalid). Am I on the right track? or are there easier ways to get through this? I've also read about the strtok function, will it be helpful here? That function is still quite vague to me, though.
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double HUGE_VAL= 1000000;
void string_cleaner (char *dirty){
int i=0;
while(1){
if (dirty[i]=='\n'){
dirty[i]='\0';
break;
}
i++;
}
}
int doubleable2(const char *str)
{
char *end_ptr;
double result;
result = strtod(str, &end_ptr);
if (result == HUGE_VAL || result == 0 && end_ptr == str)
return 0; // Could not be converted
if (end_ptr < str + strlen(str))
return 0; // Other input in the string after the number
return 1; // All of the string is part of the number
}
int main(){
char input [10];
double converted[10];
char *ptr;
int i;
for(i=0; i<5; i++){
while (1){
printf("Please enter:");
fgets(input, 10, stdin);
string_cleaner(input);
if (doubleable2(input)==0)
continue;
else if (doubleable2(input)==1)
break;
}
converted[i]=strtod(input, &ptr);
printf("%lf\n", converted[i]);
}
return 0;
}
thank you! It works just fine! I have a follow up question. If I enter a string that is too long, the program breaks. If I am to limit the input to, let's say, a maximum of 9 characters in input[], how am I to do that?
from what I understand about fgets(xx, size, stdin), it only gets up to size characters (including \n, \0), and then stores it to xx. In my program, I thought if I set it to 10, anything beyond 10 will not be considered. However, if I input a string that is too long, my program breaks.
You can indeed use strtod and check the returned value and the pointer given as the second argument:
int doubleable(const char *str)
{
const char *end_ptr;
double result;
result = strtod(str, &end_ptr);
if (result == HUGE_VAL || result == 0 && end_ptr == str)
return 0; // Could not be converted
if (end_ptr < str + strlen(str))
return 0; // Other input in the string after the number
return 1; // All of the string is part of the number
}
Note that you need to remove the newline that fgets most of the time adds to the string before calling this function.
From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer.
That is correct – see its man page:
If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced by endptr.
So use that information!
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
bool doable (const char *buf)
{
char *endptr;
errno = 0;
if (!buf || (strtod (buf, &endptr) == 0 && errno))
return 0;
if (*endptr)
return 0;
return 1;
}
int main (void)
{
printf ("doable: %d\n", doable ("12.3"));
printf ("doable: %d\n", doable ("12.3a"));
printf ("doable: %d\n", doable ("abc"));
printf ("doable: %d\n", doable (NULL));
return 0;
}
results in
doable: 1
doable: 0
doable: 0
doable: 0
After accept answer
Using strtod() is the right approach, but it has some challenges
#include <ctype.h>
#include <stdlib.h>
int doubleable3(const char *str) {
if (str == NULL) {
return 0; // Test against NULL if desired.
}
char *end_ptr; // const char *end_ptr here is a problem in C for strtod()
double result = strtod(str, &end_ptr);
if (str == end_ptr) {
return 0; // No conversion
}
// Add this if code should accept trailing white-space like a \n
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (*end_ptr) {
return 0; // Text after the last converted character
}
// Result overflowed or maybe underflowed
// The underflow case is not defined to set errno - implementation defined.
// So let code accept all underflow cases
if (errno) {
if (fabs(result) == HUGE_VAL) {
return 0; // value too large
}
}
return 1; // Success
}
OP's code
No value with result == 0 in result == 0 && end_ptr == str. Simplify to end_ptr == str.
Instead of if (end_ptr < str + strlen(str)), a simple if (*end_ptr) is sufficient.
if (result == HUGE_VAL ... is a problem for 2 reasons. 1) When result == HUGE_VAL happens in 2 situations: A legitimate conversion and an overflow conversion. Need to test errno to tell the difference. 2) the test should be if (fabs(result) == HUGE_VAL ... to handle negative numbers.