Определите, является ли строка целым числом или числом с плавающей точкой в ​​ANSI C - PullRequest
9 голосов
/ 17 сентября 2008

Используя только ANSI C, каков наилучший способ с достаточной уверенностью определить, является ли строка в стиле C целым или действительным числом (т. Е. Float / double)?

Ответы [ 9 ]

34 голосов
/ 17 сентября 2008

Не используйте atoi и atof, так как эти функции возвращают 0 при сбое. В прошлый раз, когда я проверял 0, является допустимым целым числом и числом с плавающей запятой, поэтому нет смысла определять тип.

использует функции strto {l, ul, ull, ll, d}, так как они устанавливают errno при сбое, а также сообщает, где закончились преобразованные данные.

strtoul: http://www.opengroup.org/onlinepubs/007908799/xsh/strtoul.html

В этом примере предполагается, что строка содержит одно значение для преобразования.

#include <errno.h>

char* to_convert = "some string";
char* p = to_convert;
errno = 0;
unsigned long val = strtoul(to_convert, &p, 10);
if (errno != 0)
    // conversion failed (EINVAL, ERANGE)
if (to_convert == p)
    // conversion failed (no characters consumed)
if (*p != 0)
    // conversion failed (trailing data)

Спасибо Джонатану Леффлеру за то, что он указал, что я забыл сначала установить для errno значение 0.

9 голосов
/ 17 сентября 2008

Используя sscanf , вы можете быть уверены, является ли строка float или int или чем-то другим без особого случая 0, как в случае с atoi и atof solution.

Вот пример кода:

int i;
float f;
if(sscanf(str, "%d", &i) != 0) //It's an int.
  ...
if(sscanf(str "%f", &f) != 0)  //It's a float.
  ...
3 голосов
/ 17 сентября 2008

Я согласен с Patrick_O, что функции strto {l, ul, ull, ll, d} являются наилучшим способом. Однако есть пара моментов, на которые стоит посмотреть.

  1. Установите errno на ноль перед вызовом функций; никакая функция не делает это для вас.
  2. Страница Open Group, на которую ссылается (на которую я пошел, прежде чем заметить, что Патрик тоже на нее ссылался), указывает, что errno не может быть установлен. Он установлен на ERANGE, если значение выходит за пределы диапазона; может быть установлено (но в равной степени может не быть установлено) в EINVAL, если аргумент недействителен.

В зависимости от выполняемой работы, я иногда устраиваю пропуск через пробелы в конце возвращаемого указателя конца преобразования, а затем жалуюсь (отклоняю), если последний символ не является завершающим нулем '\ 0'. Или я могу быть неаккуратным и позволить мусору появляться в конце, или я могу принять дополнительные множители, такие как 'K', 'M', 'G', 'T' для килобайт, мегабайт, гигабайт, терабайт, ... или любой другой требование основано на контексте.

3 голосов
/ 17 сентября 2008

atoi и atof конвертируют или возвращают 0, если не могут.

2 голосов
/ 17 сентября 2008

Используйте strtol / strtoll (не atoi) для проверки целых чисел. Используйте strtof / strtod (не atof) для проверки двойников.

atoi и atof преобразуют начальную часть строки, но не сообщают вам, использовали ли они всю строку. strtol / strtod сообщает вам, был ли лишний мусор после преобразования символов.

Так что в обоих случаях не забудьте передать ненулевой параметр TAIL и убедиться, что он указывает на конец строки (то есть ** TAIL == 0). Также проверьте возвращаемое значение на предмет переполнения и переполнения (подробности см. В справочных страницах или стандарте ANSI).

Обратите внимание, что strod / strtol пропускает начальные пробелы, поэтому, если вы хотите обрабатывать строки с начальными пробелами как плохо отформатированные, вам также необходимо проверить первый символ.

2 голосов
/ 17 сентября 2008

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

1 голос
/ 17 сентября 2008

atoi и atof преобразуют число, даже если за ним идут нечисловые символы. Однако, если вы используете strtol и strtod, он не только пропустит начальный пробел и необязательный знак, но и оставит вас с указателем на первый символ, а не в число. Затем вы можете проверить, что остальное пустое пространство.

1 голос
/ 17 сентября 2008

Это действительно зависит от того, почему вы спрашиваете в первую очередь.

Если вы просто хотите разобрать число и не знаете, является ли оно числами с плавающей точкой или целым числом, то просто проанализируйте число с плавающей точкой, оно также правильно проанализирует целое число.

Если вы действительно хотите знать тип, может быть, для сортировки, тогда вам следует рассмотреть возможность проверки типов в том порядке, который вы считаете наиболее подходящим. Например, попытаться разобрать целое число, и если вы не можете, то попробуйте разобрать число с плавающей точкой. (С другой стороны, вы получите немного больше поплавков ...)

0 голосов
/ 15 февраля 2014

Ну, если вам не хочется использовать новую функцию, такую ​​как strtoul, вы можете просто добавить еще одну инструкцию strcmp, чтобы увидеть, равна ли строка 0.

т.е.

if(atof(token) != NULL || strcmp(token, "0") == 0)
...