Замена двух пробелов на один

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

#include <stdio.h>

#define OUT 0 /* "состояние - вне пробела" */
#define IN 1  /* "в пробеле" */

/* Программа, заменяющая два стоящих подряд пробела на один */

int main()
{
    int c, state;

state = OUT; /* начальное состояние - вне, т.к не было еще пробела */
while ((c = getchar()) != EOF)
    if (c == ' ') /* если будет введен пробел ... */
        state = IN; /* ... то текущее состояние сменится на "в пробеле" */
    else {
        state = OUT; /* в остальных же случаях - "вне пробела" */
    }

while (state == IN) { /* пока состояние "в пробеле" ... */
    if (c == ' ') /* если в этом состоянии будет введен еще один пробел */
        ; /* ... то ничего не делать. Не знаю, можно ли ставить пустую инструкцию в if .. */
}
return 0;
}

Написал, скомпилировал, запустил... в итоге машина не слушается хозяина =(
Просьба указать, что в коде не так. И правильна ли вообще сама идея в корне?

Написал, скомпилировал, запустил... в итоге машина не слушается хозяина =(

Дрессировал плохо ;)

1) Постановка задачи нечеткая. Что значит «заменяла 2 стоящих подряд пробела на один»? На входе 2 пробела — на выходе один пробел — это понятно. На входе 3 пробела — на выходе один пробел или два пробела (пара пробелов схлопнулась в один + один непарный пробел). Ну и так далее. Исходя из контекста программы с учетом комментариев, видимо подразумевается "заменяла 2 и более стоящих подряд пробелов на один". Из этого и будем исходить.

2) В коде «не так» всё. Самое минимальное, почему программа «не слушается»:

    // в этом цикле символ считывается из STDIN и,
    // в зависимости от символа, устанавливается переменная state
    while ((c = getchar()) != EOF)
        if (c == ' ') /* если будет введен пробел ... */
            state = IN; /* ... то текущее состояние сменится на "в пробеле" */
        else
            state = OUT; /* в остальных же случаях - "вне пробела" */
    // здесь цикл заканчивается

    // сюда попадаем только после достижения EOF на STDIN
    // переменная c содержит символ EOF (-1), 
    // переменная state - последнее, уже бесполезное здесь, значение

    // здесь либо попадаем в бесконечный цикл, либо проскакиваем мимо цикла
    // в зависимости от значения переменной state
    while (state == IN) { /* пока состояние "в пробеле" ... */
        if (c == ' ') /* если в этом состоянии будет введен еще один пробел */
            ; /* ... то ничего не делать. Не знаю, можно ли ставить пустую инструкцию в if .. */
    }
    return 0;
}

... и никакого копирования ввода на вывод нет вообще.

3) Такие задачи хорошо решаются с помощью конечных автоматов (тыц, тыц). В вашем случае это будет выглядеть примерно так:

int main() {
    int c, state;

    state = OUT; /* начальное состояние - вне, т.к не было еще пробела */
    while ((c = getchar()) != EOF)
        switch (state) {
            case OUT:
                putchar(c);
                if (c == ' ')
                    state = IN;
                break;
            case IN:
                if (c != ' ') {
                    putchar(c);
                    state = OUT;
                }
                break;
        }
    return 0;
}

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.