Nano Hash - криптовалюты, майнинг, программирование

Как получить целочисленный и плавающий ввод без `scanf()` в c?

Как я могу присвоить целые числа и значения с плавающей запятой, заданные пользователем, переменной или массиву без использования scanf()?

Например, у нас есть getchar, fgetc, fgets... и т. д. для char и string. Есть ли какая-либо функция для чисел с плавающей запятой и целых чисел?

04.08.2017

  • man strtol, man strtof. Обязательно загляните в раздел См. также. 04.08.2017
  • нет специальных функций ввода для чисел. 04.08.2017
  • что на самом деле ваша цель поиска такой вещи может помочь нам направить вас в правильном направлении. 04.08.2017
  • Я рекомендую прочитать руководство по scanf, написанное @ FelixPalmen, особенно раздел 4. Как мне получить числа без scanf()? 04.08.2017
  • Это сложная цель, если ввод должен прекратиться, как только произойдет конец числа. IOWs, 123 456\n должны останавливаться после 3 для имитации scanf("%d", ...) и не читать всю строку. Непросто, особенно с ФП. Я подозреваю, что чтение строки удовлетворит OP. 04.08.2017
  • К вашему сведению: float, написанное в неэкспоненциальной записи, может состоять из десятков символов. (или, может быть, 150+, если читается точное значение float) 04.08.2017
  • в моем ответе у вас есть простая функция, читающая одновременно @Noob в программировании 05.08.2017

Ответы:


1

Нет функций для чтения целых чисел и чисел с плавающей запятой, но вы можете использовать fgets с strtol для целых чисел и strtof для чисел с плавающей запятой:

// 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);

Вы также можете использовать atoi для целых чисел, но это не рекомендуется, поскольку atoi не обнаруживает ошибок и считается устаревшим.

Если вы хотите обнаружить ошибки, вы можете использовать следующий код:

// 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);
}
04.08.2017
  • atoi не обнаруживает ошибок, как и ваш ответ. Любая возможная ошибка полностью игнорируется. 04.08.2017
  • atoi() устарел? Любая ссылка на это или это просто не рекомендуется? 04.08.2017
  • @WeatherVane хорошо, извините, я добавил код для обнаружения ошибок 04.08.2017
  • @chux Функция atoi также считается устаревшей; вместо этого используйте strtol. из документации GNU libc: gnu.org/software/ libc/manual/html_node/Parsing-of-Integers.html 04.08.2017
  • Нет, извините, ваша проверка ошибок для strtof не будет обнаружена при неправильном вводе "1a.2" или при переполнении. Вы не проверили возвращаемое значение из fgets. Необходимо тщательно проверять все действия пользователя, независимо от того, являются ли они злонамеренными или просто неосторожными. 04.08.2017
  • @WeatherVane извините, я отредактировал код для обнаружения ошибок, и теперь он работает правильно 04.08.2017
  • Мелочи: при вводе типа "\n" этот код не сообщает об ошибке. char str_f[20] довольно маленький для float. Кстати, проверка переполнения FP сложна, если вы хотите это сделать. Даже ОФ для float - это боль. 04.08.2017
  • @chux спасибо, я исправил проблему с \n. Я знаю, что 20 мало для чисел с плавающей запятой, но я думаю, что это легко изменить и понять, как работает код, и что, если вы хотите больше чисел с плавающей запятой, вы можете увеличить число 04.08.2017
  • В коде все еще есть проблемы, хотя вы их устраняете. Рассмотрим if (endptr_f == str_f), чтобы определить, не произошло ли преобразование. 04.08.2017
  • И это иллюстрирует, почему мы использовали стандартные функции ввода. Так легко испортить и вызвать трудно найти ошибки. 04.08.2017

  • 2

    Много лет назад я написал это, протестировал в VS2017 и до сих пор работает. Очень просто, не очень хорошо, но, может быть, вы можете использовать его для чего-то

    #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
    
    04.08.2017

    3

    Есть ли функция для чисел с плавающей запятой и целых чисел?

    Да, это scanf(), но OP не хочет его использовать.

    Как получить целочисленный и плавающий ввод без scanf()?

    Это не тривиальная задача, как scanf("%d", &some_int), scanf("%f", &some_float).

    Основная проблема заключается в том, чтобы прекратить чтение символов после того, как будет использован самый длинный допустимый ввод — это может быть в середине строки пользовательского ввода. Я не нашел краткого надежного решения.

    Вместо этого обсуждалась проблема чтения строки пользовательского ввода для одного целого числа long. Чтение float аналогично. Необходимы изменения возле строк ***

    Тем не менее возникает проблема конечной длины текста. В приведенном ниже коде предполагается, что допустимый ввод сделан в 2 раза больше, чем требуется для печати long.

    Переполнение — это проблема, которая в некоторой степени рассматривается здесь. Напомним, что с scanf() поведение OF/UF не определено.

    Основная идея состоит в том, чтобы прочитать строку, пропустив пробелы, прочитав N символов, а затем отыскав после этого любое небелое пространство. Затем проанализируйте буфер.


    #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;
    }
    

    Тестовый код

    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);
      }
    }
    
    04.08.2017
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..