-1

How can I assign a integer and float values given by user to a variable or array without using scanf()?

Like we have getchar,fgetc,fgets...etc for char and string, Is there any function for floats and integers ?

0___________
  • 60,014
  • 4
  • 34
  • 74

3 Answers3

1

There aren't functions to read integers and floats but you can use fgets with strtol for integers and strtof for floats:

// floats:
char str_f[20];
float f;

fgets (str_f, 20, stdin);
f = strtof(str_f, NULL);

// integers:
char str_i[20];
int i;

fgets(str_i, 20, stdin);
i = strtol(str_i, NULL, 0);

You can also use atoi for integers but it's not recommended because atoi doesn't detect errors and it's considered obsolete.

If you want to detect errors you can use the following code:

// floats:
char *endptr_f;
char str_f[20];
float f;

fgets (str_f, 20, stdin);
f = strtof(str_f, &endptr_f);

if (*endptr_f != '\n' || str_f[0] == '\n' || endptr_f == str_f)
{
    printf("ERROR: \"%s\" is an invalid float!\n", str_f);
}

// integers:
char *endptr_i;
char str_i[20];
int i;

fgets(str_i, 20, stdin);
i = strtol(str_i, &endptr_i, 0);

if (*endptr_i != '\n' || str_i[0] == '\n' || endptr_i == str_i)
{
    printf("ERROR: \"%s\" is an invalid integer!\n", str_i);
}
  • 1
    "`atoi` doesn't detect errors" and neither does your answer. Any possible error is completely overlooked. – Weather Vane Aug 04 '17 at 17:46
  • `atoi()` is obsolete? Any reference on that or is it just not recommended? – chux - Reinstate Monica Aug 04 '17 at 17:49
  • @WeatherVane ok, sorry, I added the code to detect errors –  Aug 04 '17 at 18:05
  • @chux "The atoi function is also considered obsolete; use strtol instead." from the GNU libc documentation: https://www.gnu.org/software/libc/manual/html_node/Parsing-of-Integers.html –  Aug 04 '17 at 18:06
  • 2
    No sorry, your error checking for `strtof` will not pick up on the bad input `"1a.2"` nor when there is an overflow. You have not checked the return value from `fgets`. It is *essential* to thoroughly check all user input, whether they are malicious or just careless. – Weather Vane Aug 04 '17 at 18:10
  • @WeatherVane sorry, I edited the code for error detection and now it works correctly –  Aug 04 '17 at 18:35
  • Minor stuff: With input like `"\n"`, this code reports no error. `char str_f[20]` is fairly [small](https://stackoverflow.com/questions/45512240/how-to-get-integer-and-float-input-without-scanf-in-c/45512686?noredirect=1#comment77988032_45512240) for a `float`. BTW FP underflow checking is tricky if you want to do that. Even OF for `float` is a pain. – chux - Reinstate Monica Aug 04 '17 at 18:38
  • @chux thanks, I corrected the thing with `\n`.I know that 20 is small for floats but I think that it's easy to change and understand how the code works and that if you want more floating points you can increase the number –  Aug 04 '17 at 18:50
  • Code still has issues, although you are plugging them up. Consider `if (endptr_f == str_f)` to detect if no conversion occurred. – chux - Reinstate Monica Aug 04 '17 at 18:59
  • 2
    And this illustrates the point with why we used canned input functions. So easy to screw up and cause hard to find errors. – Michael Dorgan Aug 04 '17 at 20:31
0

Years ago I wrote this, Tested in VS2017 and still works. Very simple, Not very good but maybe you can use it for something

#define INT_CONVERTED       (1 << 0)
#define FLOAT_CONVERTED     (1 << 1)

char *strlwr(char *str)
{
    char *ptr = str;

    while (*ptr)
    {
        *ptr = tolower(*ptr);
        ptr++;
    }
    return str;
}


int NumberOfDots(char *s)
{
    int dots = 0;
    while (*s)
        dots += *s++ == '.';
    return dots;
}

int NOTstrcasechr(char *str, int ch)
{
    return strchr(str, ch) == NULL && strchr(str, toupper(ch)) == NULL;
}

int ReadNumber(double *db, int *in)
{
    int result = 0;

    do
    {
        char str[100];
        int dots;

        result = 0;
        printf("Enter number: ");
        fgets(str, 100, stdin);
        if ((dots = NumberOfDots(str)) > 1) str[0] = '\0';

        if (sscanf(str, "%lf", db) == 1)
        {
            result |= FLOAT_CONVERTED;
        }
        if (!result || (!dots && NOTstrcasechr(str, 'e')))
            if (NOTstrcasechr(str, 'x'))
            {
                if (sscanf(str, "%d", in) == 1)
                {
                    result |= INT_CONVERTED;
                }
            }
            else 
                if(result)
                {
                    result |= INT_CONVERTED;
                    *in = (int)*db;
                }
        if (strstr(strlwr(str), "exit") != NULL) result = -1;

    } while (!result);
    return result;
}


int main(int argc, char **argv)
{
    double db;
    int in;
    int result;

    while ((result = ReadNumber(&db, &in)) != -1)
    {

        if (result & FLOAT_CONVERTED) printf("Float = %lf ", db);
        if (result & INT_CONVERTED) printf("Integer = %d ", in);
        printf("\n\r");

    }
    return 0;
}

Enter number: xfdsfdsfdsf
Enter number: rthdgfhghg
Enter number: 0x4567
Float = 17767.000000 Integer = 17767
Enter number: 3e67
Float = 30000000000000000978680950144401383192292617328216608963406365458432.000000
Enter number: 54567
Float = 54567.000000 Integer = 54567
Enter number: dfgdfgdfgdfgdgg
Enter number: 3456
Float = 3456.000000 Integer = 3456
Enter number: 12354654465454654654565567567576
Float = 12354654465454653961713368432640.000000 Integer = -1
Enter number: exit
0___________
  • 60,014
  • 4
  • 34
  • 74
-2

Is there any function for floats and integers ?

Yes, it is scanf(), yet OP does not want to use that.

How to get Integer and float input without scanf()?

This is not a trivial task to do just like scanf("%d", &some_int), scanf("%f", &some_float).

The primary problem is to stop reading characters once the longest valid input is consumed - this could be in the middle of a line of user input. I did not find a terse robust solution.

Instead, talcked the problem of reading a line of user input for one integer long. Reading a float is similar. Changes needed near *** lines

Still the problem of finite text length occurs. The below code assumes valid input is made of up to 2x the maximum needed to print a long.

Overflow is an issue somewhat addressed here. Recall with scanf(), OF/UF is undefined behavior.

The central idea is to read a line by skipping whitespace, reading N characters and then looking for any non-white space after that. Then parse the buffer.


#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// character array size needed to represent all `long`
#define INT_STR_SIZE (sizeof(long)*CHAR_BIT/3 + 3)
#define INT_BUF_SIZE (INT_STR_SIZE*2)

int readline_long(long *dest) {                        // ***
  int ch;
  while (isspace(ch = getchar()) && ch != '\n') {
    ;
  }
  if (ch == EOF) return EOF;
  ungetc(ch, stdin);

  char buf[INT_BUF_SIZE];                                 // ***
  if (fgets(buf, sizeof buf, stdin) == NULL) return EOF;
  if (strchr(buf, '\n') == NULL) {
    // Get rest of line
    bool only_white_space = true;
    while ((ch = getchar()) != '\n' && ch != EOF) {
      if (!isspace(ch)) only_white_space = false; // consume rest of line
    }
    if (!only_white_space) return 0;  // extra junk
  }
  char *endptr;
  errno = 0;
  long y = strtol(buf, &endptr, 10);                    // ***
  if (buf == endptr) return false;  // no conversion
  while (isspace((unsigned char) *endptr)) {
    endptr++;
  }
  if (*endptr) return 0; // extra junk
  *dest = y;
  return 1;
}

Test code

int main(void) {
  long lg;
  int retval;
  while ((retval = readline_long(&lg)) != EOF) {
    printf("retval = %d", retval);
    if (retval > 0) printf(" val = %ld", lg);
    if (errno) printf(" errno = %d", errno);
    putchar('\n');
    fflush(stdout);
  }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256