isprint()
возвращает логический результат - ноль, если символ не «печатный», и ненулевой, если он есть. Как таковой isprint(ch) != '\n'
не имеет смысла. Ваше полное выражение в вопросе имеет еще меньшее значение, но я подойду к этому в конце.
isprint()
сам по себе возвращает true (не ноль) для всех печатаемых символов, поэтому вам не нужны другие тесты. Более того, вы увеличиваете count
безоговорочно и в каждом условном блоке, поэтому вы учитываете каждый символ, а некоторые - дважды.
Вам просто нужно:
if( isprint(ch) )
{
count++;
}
putc( ch, stdout ) ;
Хотя ваш код явно является неполным фрагментом, неясно, где и как вы читаете ch
. Вам нужен getc()
или эквивалент там.
while( (ch = getc(fp)) != EOF )
{
if( isprint(ch) )
{
count++;
}
putc( ch, stdout ) ;
}
Не ясно, нужно ли считать все пробелы (включая пробел, табуляцию и новую строку) или просто "пробелы", как вы указали. Если это так, то ясно, что isprint()
будет соответствовать пробелу, но не символам новой строки или табуляции. isspace()
соответствует всем этим, но не должен учитываться отдельно до isprint()
, потому что «пробел» находится как в пробелах, так и в печатных наборах. Если новая строка и табуляция должны быть подсчитаны (и менее вероятно; «вертикальная табуляция»), то:
while( (ch = getc(fp)) != EOF )
{
if( isprint(ch) || isspace(ch) )
{
count++;
}
putc( ch, stdout ) ;
}
Еще один аспект C, который вы, похоже, неправильно поняли, - это как работают логические выражения. Чтобы проверить одну переменную для нескольких значений, вы должны написать:
if( var == x || var == y || var == z )
Вы написали:
if( var == x || y || z )
, что может иметь смысл в английском (или другом естественном языке), когда вы читаете его вслух, но в C это означает:
if( var == (x || y || z ) )
оценивая (x || y || z )
как true
или false
и сравнивая его с var
.
Вероятно, стоит рассмотреть семантику вашего существующего решения, чтобы показать, почему оно на самом деле компилируется, но дает ошибочный результат.
Во-первых,
isprint(ch) != '\n' || '\t' || '\0'
эквивалентно isprint(ch) != true
по причинам, описанным ранее. Таким образом, вы увеличиваете счетчик для всех символов, которые не для печати.
Тогда вот:
isspace(ch) == NULL
NULL
- это макрос, представляющий недопустимый указатель, а isspace()
не возвращает указатель. Однако NULL
будет неявно приводить к нулю (или ложь). Таким образом, здесь вы увеличиваете счетчик для всех печатаемых символов, которые не пробелы.
Наконец, вы безоговорочно отсчитываете здесь каждый символ:
putc(ch,stdout); // same as putchar(ch);
count++;
Итак, ваш результат будет:
number-of-non-printing-characters +
number-of-printing-characters - number-of-spaces +
total-number-of-characters
что я думаю (2 x file-length) - number-of-spaces
Наконец, обратите внимание, что если вы откроете текстовый файл с концами строк CR + LF (обычным для текстовых файлов в Windows) в «двоичном» режиме, isspace()
будет считать два символа для каждой новой строки. Обязательно откройте в «текстовом» режиме (независимо от платформы).