Ниже приведен быстрый подход к удалению потенциала '\n'
из строки, сохраненной в fgets()
. Он использует strlen()
с двумя тестами.
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') {
buffer[--len] = '\0';
}
Теперь используйте buffer
и len
по мере необходимости.
Этот метод имеет побочное преимущество len
значение для последующего кода. Это может быть быстрее, чем strchr(Name, '\n')
. Ref YMMV, но оба метода работают.
buffer
, из оригинала fgets()
не будет содержать в "\n"
при некоторых обстоятельствах: A) Линия был слишком длинным для buffer
, поэтому только char
, предшествующий '\n'
, сохраняется в buffer
. В потоке остаются непрочитанные символы. B) Последняя строка в файле не заканчивалась символом '\n'
.
Если на входе есть встроенные нулевые символы '\0'
в нем где-то, длина, сообщенная strlen()
, не будет содержать местоположение '\n'
.
Некоторые другие ответы ' Проблемы:
strtok(buffer, "\n");
не удаляет '\n'
, когда buffer
- "\n"
. Из этого ответа - изменен после этого ответа, чтобы предупредить об этом ограничении. char
, прочитанный fgets()
, является '\0'
. Это происходит, когда ввод начинается со встроенного '\0'
. Тогда buffer[len -1]
становится buffer[SIZE_MAX]
доступным к памяти, конечно, вне допустимого диапазона buffer
. Что-то хакер может попытаться найти в глупости чтения текстовых файлов UTF16. Это было состояние ответа , когда этот ответ был написан. Позже не-OP отредактировал его, чтобы включить код, подобный проверке этого ответа на ""
. size_t len = strlen(buffer);
if (buffer[len - 1] == '\n') { // FAILS when len == 0
buffer[len -1] = '\0';
}
sprintf(buffer,"%s",buffer);
- неопределенное поведение: Ref . Кроме того, он не сохраняет никаких ведущих, разделяющих или завершающих пробелов. Теперь удален . buffer[strcspn(buffer, "\n")] = 0;
, отличным от производительности, по сравнению с strlen()
. Производительность при обрезке обычно не является проблемой, поскольку код вводит I / O - черную дыру процессорного времени. Если следующий код нуждается в длине строки или имеет высокую производительность, используйте этот подход strlen()
. Иначе strcspn()
является прекрасной альтернативой. Может быть, вам нужен тип Maybe?
data Infinite a = Infinite | Only a
затем напишите экземпляр Num для Num a => Infinite a с необходимыми числовыми правилами.
Попробуйте что-нибудь подобное. Однако, чтобы получить операции Num
(например, +
или -
), вам нужно будет определить экземпляр Num
для Infinitable a
типа. Точно так же, как я сделал это для класса Ord
.
data Infinitable a = Regular a | NegativeInfinity | PositiveInfinity deriving (Eq, Show)
instance Ord a => Ord (Infinitable a) where
compare NegativeInfinity NegativeInfinity = EQ
compare PositiveInfinity PositiveInfinity = EQ
compare NegativeInfinity _ = LT
compare PositiveInfinity _ = GT
compare _ PositiveInfinity = LT
compare _ NegativeInfinity = GT
compare (Regular x) (Regular y) = compare x y
main =
let five = Regular 5
pinf = PositiveInfinity::Infinitable Integer
ninf = NegativeInfinity::Infinitable Integer
results = [(pinf > five), (ninf < pinf), (five > ninf)]
in
do putStrLn (show results)
Ну как насчет того! Оказывается, если вы просто наберете 1/0
, он вернет Infinity
! На ghci:
Prelude> 1/0
Infinity
Prelude> :t 1/0
1/0 :: (Fractional t) => t
Prelude> let inf=1/0
Prelude> filter (>=inf) [1..]
и затем, конечно, он работает вечно, никогда не находя числа больше бесконечности. (Но см. Комментарии ephemient ниже о фактическом поведении [1 ..]
)
Если у вас есть граничные условия, которые иногда нужно проверять, а иногда нет, вы можете решить это следующим образом:
type Bound a = Maybe a
withinBounds :: (Num a, Ord a) => Bound a -> Bound a -> a -> Bool
withinBounds lo hi v = maybe True (<=v) lo && maybe True (v<=) hi
Посмотрите на мою библиотеку RangedSets, которая делает именно это в очень общем виде. Я определил тип "Boundary" так, что значение типа "Boundary a" всегда либо выше, либо ниже любого данного "a". Границы могут быть "AboveAll", "BelowAll", "Above x" и "Below x".