Минимальная длина буфера для чтения с плавающей точкой - PullRequest
1 голос
/ 15 сентября 2011

Я пишу небольшую программу командной строки, которая читает два числа с плавающей запятой, целое число и небольшую строку (максимум 4 символа) из стандартного ввода.Я пытаюсь выяснить размер буфера, который я должен создать и передать в fgets.Я подумал, что мог бы рассчитать это на основе того, сколько цифр должно быть включено в максимальные значения float и int соответственно, например, так:

#include <float.h>
#include <limits.h>

...

int fmax = log10(FLOAT_MAX) + 2;     // Digits plus - and .
int imax = log10(INT_MAX) + 1;       // Digits plus -
int buflen = 4 + 2*fmax + imax + 4;  // 4 chars, 2 floats, 1 int, 3 spaces and \n

...

fgets(inbuf, buflen + 1, stdin);

Но мне пришло в голову, что это на самом деле не можетбудь прав.imax заканчивается 10 в моей системе, что кажется немного низким, в то время как fmax, если 40. (Что я думаю, немного выше, учитывая, что более длинные значения могут быть представлены с помощью электронной записи.)

Итак, мой вопрос: это лучший способ решить это?Это даже необходимо?Это просто более элегантно, чем назначить буфер 256 и предположить, что этого будет достаточно.Назовите это делом гордости; P.

Ответы [ 4 ]

5 голосов
/ 15 сентября 2011

Этот тип вещей - это место, где я бы на самом деле использовал fscanf вместо того, чтобы сначала читать в буфер фиксированного размера.Если вам нужно убедиться, что вы не пропускаете символ новой строки или другие значащие пробелы, вы можете использовать fgetc для обработки посимвольных символов до тех пор, пока не получите начало числа, затем ungetc перед вызовом fscanf.

Если вы хотите быть ленивым, просто выберите большое число, например 1000 ...

2 голосов
/ 15 сентября 2011

Это определено для базовых 10 чисел с плавающей точкой (#include <float.h> или эквивалентного члена std::numeric_limits<float_type>):

FLT_MAX_10_EXP // for float
DBL_MAX_10_EXP // for double
LDBL_MAX_10_EXP // for long double

Как и максимальная точность для десятичных чисел в базе 10:

FLT_DIG // for float
DBL_DIG // for double
LDBL_DIG  // for long double

Хотя это действительно зависит от того, что вы определяете как действительное число с плавающей запятой.Вы можете представить, что кто-то ожидает:

00000000000000000000000000000000000000000000000000.00000000000000000000

будет считаться нулем.

0 голосов
/ 15 сентября 2011

Следуя ответу @MSN, вы не можете знать, что ваш буфер достаточно велик.

Обратите внимание:

const int size = 4096;
char buf[size] = "1.";
buf[size -1 ] = '\0';
for(int i = 2; i != size - 1; ++i)
    buf[i] = '0';
double val = atof(buf);
std::cout << buf << std::endl;
std::cout << val << std::endl;

Здесь atof() обрабатывает (как и предполагалось), представление из тысячи символов 1.

Так что на самом деле вы можете сделать одно или несколько из следующих действий:

  • Обрабатывать случай, когда буфер не достаточно большой
  • Лучше контролировать входной файл
  • Используйте fscanf напрямую, чтобы сделать размер буфера чужой проблемой
0 голосов
/ 15 сентября 2011

Я уверен, что есть хороший способ определить максимальную длину строки с плавающей запятой алгоритмически, но что это интересно?Давайте разберемся с помощью грубой силы!

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int, char **)
{
   float f;
   unsigned int i = -1;
   if (sizeof(f) != sizeof(i))
   {
      printf("Oops, wrong size!  Change i to a long or whatnot so the sizes match.\n");
      return 0;
   }
   printf("sizeof(float)=%li\n", sizeof(float));

   char maxBuf[256] = "";
   int maxChars = 0;
   while(i != 0)
   {
      char buf[256];
      memcpy(&f, &i, sizeof(f));
      sprintf(buf, "%f", f);
      if ((i%1000000)==0) printf("Calclating @ %u: buf=[%s] maxChars=%i (maxBuf=[%s])\n", i, buf, maxChars, maxBuf);
      int numChars = strlen(buf);
      if (numChars > maxChars)
      {
         maxChars = numChars;
         strcpy(maxBuf, buf);
      }
      i--;
   }
   printf("Max string length was [%s] at %i chars!\n", maxBuf, maxChars);
}

Похоже, что ответ может быть 47 символов в поплавке (по крайней мере, на моей машине), но я не собираюсь позволить ему работать до конца, поэтому этобольше.

...