Почему это не устраняет двойные пробелы в C? Это одно из упражнений getchar() в K & R
Это упражнение K&R. Предполагается заменить один пробел двойным или более. Вместо этого он точно отражает ввод, пробелы и все. Кроме того, почему я должен использовать EOF (ctrl-d) в других упражнениях и RETURN (Enter) для этого? (Я запускаю его в Ubuntu, но использую ssh с Mac.)
#include <stdio.h>
main()
{
int c;
c = getchar();
while (c != EOF)
{
while (c != EOF | c != ' ')
{
putchar(c);
c = getchar();
}
putchar(c);
c = getchar();
while (c == ' ' | c != EOF)
c = getchar();
}
4 ответа
Показанный фрагмент содержит [по крайней мере] одну логическую ошибку и другую ошибку, вызванную путаницей между логическими логическими операторами и побитовыми логическими операторами.
Логическая ошибка:
Ваш второй тест на c != EOF
ИЛИ с тестом на символ, не являющийся пробелом (c != ' ')
... Так как вы попадаете в этот тест OR-ed, когда c не является EOF (это условие управления while
), ИЛИ-тест всегда верен!
...
while (c != EOF)
{
// This test always true regardless of c being a space or not
// Also it should be a logical OR, if at all. The bitwise OR will produce
// odd results if you are not sure of the bit patterns of the operands.
while (c != EOF | c != ' ')
{
putchar(c);
c = getchar();
}
...
Путаница с ошибкой оператора: в этом случае вам нужно использовать логические операторы OR (или действительно логические AND), т.е. ||
а также &&
соответственно, а не побитовые логические операторы (|
а также &
).
Как правило, вы обнаружите, что в C вы довольно часто используете логические операторы для выражения логических условий, при этом вам нужны только побитовые операторы, когда вам нужно эффективно связываться с битовыми комбинациями переменных (например, чтобы маскировать некоторые биты или заставлять их быть установить и т. д.)
Теперь, выше было решение проблем в коде "как есть", просто объясняя, почему пробелы обрабатывались так же, как и другие символы... Что касается цели упражнения K&R: заменить последовательность из нескольких пробелов только одним пробелом, Показанная логика явно неверна. Я бы предпочел не отдавать это здесь, но несколько советов:
- ввести переменную "состояние", которая указывает, был ли предыдущий символ пробелом
- используйте один цикл while (в то время как не EOF или другое конечное условие)
- в цикле систематически выводите прочитанный символ, если не установлено состояние var
- после условного вывода текущего символа обновите символ состояния.
Как общий совет, это часто (но не всегда) " запах кода" (т.е. указание на то, что код / логику следует переработать), когда вам нужно повторить условие (я) конца цикла в цикле и / или ввести несколько мест, где вы читаете из некоторого ввода (здесь несколько getchar()
)
Есть две проблемы с вашим кодом.
Во-первых, вы пытаетесь использовать оператор логического ИЛИ (||), но вы используете побитовое ИЛИ (|). Во-вторых, вы все равно должны использовать логическое И, а не логическое ИЛИ:
while (c != EOF && c != ' ')
Попробуйте этот цикл:
while (c != EOF)
{
if (c == ' ')
{
putchar(c);
while(c == ' ' && c != EOF)
c = getchar();
}
else
{
if (c != EOF)
putchar(c);
c = getchar();
}
}
Это много получает и кладет, и проверка значений. Вот кое-что более чистое, что также заботится о вкладках.
void main (void)
{
int F_space=F_tab=0; // Flags for special chars
char ch;
do
{
ch = getchar();
// test for special characters
switch (ch)
{
case ' ': // space
F_space = 1;
continue;
case '\t': // tab
F_tab = 1;
continue;
default: // anything else
// output a space if necessary
if (F_space || F_tab) {
F_space = F_tab = 0; // clear flags
putchar (' ');
}
break;
}
// output the character
putchar (ch);
break;
}
while (ch != EOF);