Почему это не устраняет двойные пробелы в 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);
Другие вопросы по тегам