Упражнение K & R 1-21 - Психическое непонимание - PullRequest
6 голосов
/ 11 июня 2010

«Невозможное» упражнение K & R.

"Написать программу entab, которая заменяет строки заготовок по минимуму количество вкладок и пробелов для достижения такой же интервал. Используйте ту же вкладку останавливается, скажем, каждые n столбцов. Должен п быть переменной или символической параметр? "

Проблема, с которой я столкнулся, заключается в том, что я не уверен, как правильно это сделать. Я знаю, что это не очень объяснительно, но в этом и заключается проблема. Большинство примеров, которые я видел, подсчитали количество пробелов и заменили эти серии на вкладку, но это не то, о чем она просит, я считаю, что понимаю, о чем она просит, но в настоящее время чувствую, что не могу этого сделать.

Может ли кто-нибудь помочь:)

Редактировать: код, который я написал до сих пор , можно найти здесь .

Ответы [ 8 ]

15 голосов
/ 11 июня 2010

Если твой вопрос "Что это просит меня сделать?" Я думаю, что могу помочь, перефразируя исходный вопрос (излагая тот же вопрос другим способом).

Напишите программу, которая принимает в качестве входного текста пробелы и выдает в качестве выходного визуально эквивалентный текст с использованием вкладок в максимально возможной степени.

Например, с табуляции каждые 8 ​​символов и пробелами в виде '.' и вкладки как '-';

input;
".foo:...bar;......#comment"
output;
".foo:-bar;-..#comment"

input;
".......-foo:.....bar;......#comment"
output;
"-foo:-.bar;-...#comment"

Напишите программу, чтобы можно было варьировать параметр табуляции n, т. Е. Разрешить значения n, отличные от 8. Будьте готовы обосновать свое решение сделать n постоянной или альтернативной переменной.

Редактировать Я посмотрел на ваш код и думаю, что он более сложный, чем должен быть. Мой совет - делать это персонажем одновременно. Там нет необходимости буферизовать целую строку. Сохраняйте количество столбцов при чтении каждого символа («\ n» сбрасывает его в ноль, «\ t» увеличивает его на 1 или более, другие символы увеличивают его). Когда вы видите пробел (или табуляцию), не запускайте ничего сразу, начните процесс включения, выбрасывайте ноль или более табуляций, а затем пробелы позже (в '\ n' или в непропуске, в зависимости от того, что произойдет раньше).

Последний совет: конечный автомат может значительно облегчить написание, проверку, тестирование и чтение такого рода алгоритмов.

Редактировать 2 В бесстыдной попытке заставить ОП принять мой ответ, я теперь пошел вперед и фактически сам кодировал решение, основываясь на подсказках, которые я предлагал выше, и моих комментариях в обсуждении.

// K&R Exercise 1-21, entab program, for Stackoverflow.com
#include <stdio.h>
#define N 4     // Tabstop value. Todo, make this a variable, allow
                //  user to modify it using command line

int main()
{
    int col=0, base_col=0, entab=0;

    // Loop replacing spaces with tabs to the maximum extent
    int c=getchar();
    while( c != EOF )
    {

        // Normal state
        if( !entab )
        {

            // If whitespace goto entab state
            if( c==' ' || c=='\t' )
            {
                entab = 1;
                base_col = col;
            }

            // Else emit character
            else
                putchar(c);
        }

        // Entab state
        else
        {

            // Trim trailing whitespace
            if( c == '\n' )
            {
                entab = 0;
                putchar( '\n' );
            }

            // If not whitespace, exit entab state
            else if( c!=' ' && c!='\t' )
            {
                entab = 0;

                // Emit tabs to get close to current column position
                //  eg base_col=1, N=4, col=10
                //  base_col + 3 = 4 (1st time thru loop)
                //  base_col + 4 = 8 (2nd time thru loop)
                while( (base_col + (N-base_col%N)) <= col )
                {
                    base_col += (N-base_col%N);
                    putchar( '\t' );
                }

                // Emit spaces to close onto current column position
                // eg base_col=1, N=4, col=10
                //  base_col -> 8, and two tabs emitted above
                //  base_col + 1 = 9 (1st time thru this loop)
                //  base_col + 1 = 10 (2nd time thru this loop)
                while( (base_col + 1) <= col )
                {
                    base_col++;
                    putchar( ' ' );
                }

                // Emit buffered character after tabs and spaces
                putchar( c );
            }
        }

        // Update current column position for either state
        if( c == '\t' )
            col += (N - col%N); // eg col=1, N=4, col+=3
        else if( c == '\n' )
            col=0;
        else
            col++;

        // End loop
        c = getchar();
    }
    return 0;
}
1 голос
/ 15 февраля 2018

Я немного опоздал, но вот как я решил это сам. Это другой подход, чем тот, о котором говорилось выше, поэтому, пожалуйста, поделитесь любыми комментариями / отзывами, если они у вас есть.

Проверьте мою общедоступную информацию о Github для получения исходного кода. Есть комментарии к коду, и подход объяснен в верхней части файла, но я скопирую и вставлю его сюда просто, чтобы логика была ясна с самого начала.

1007 * * Подход:
  • Мы будем отслеживать количество встреченных пробелов (между непробельными / непробельными символами)

  • Мы будем отслеживать символы (которые не являются символами табуляции / пробелов / новых строк) для каждой строки ввода

  • Мы оценим "пробелы", образованные пробелами, по:

    • Оценка количества пробелов между этими символами.

    • Пробел будет "достаточно большим", если количество пробелов> = TABSIZE

    • Затем для всех оставшихся пробелов в нашем «буфере» мы распечатаем их по отдельности

Наконец, мы печатаем символ, который был прочитан (который не был табуляцией / пробелом)

А также обновление количества пробелов и знаков при необходимости.

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

Надеюсь, это поможет кому-то позже!

1 голос
/ 11 июня 2010

Я согласен с вашей оценкой.Недостаточно заменить каждые n пробелов вкладкой;например, если n == 4, «hi blank blank blank blank» следует заменить не на «hi tab», а на «hi tab blank blank».

Звучит так, как вам нужноотслеживать текущую позицию, когда вы читаете в каждой строке, и использовать эту информацию, чтобы определить, сколько вкладок вам нужно.Это помогает?Пожалуйста, дайте мне знать, если вам нужно больше деталей!

Что касается части «переменная в сравнении с символическим параметром», то любая из них определенно будет жизнеспособной, но я могу представить одно существенное преимущество использования переменной:программа для разных значений n без перекомпиляции.

0 голосов
/ 13 ноября 2016

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

#include <stdio.h>

#define TS 8

int main(int arg, char *argv[]) {
    int counter = 0, space_counter = 0, c;
    while ((c = getchar()) != EOF) {
        ++counter;
        if (c == ' ' && ++space_counter && (counter % TS) == 0) {
            space_counter = 0;
            c = '\t';
        } else if (c == '\t') {
            counter = space_counter = 0;
        } else if (c != ' ') {
            while (space_counter--)
                putchar(' ');
            space_counter = 0;
            if (c == '\n')
                counter = 0;
        } else {
            continue; /* don't call putchar(c) */
        }
        putchar(c);
    }
    return 0;
}

За исключением пробелов, каждый читаемый символ печатается дословно. Бланки засчитываются вместо. Если программа встречает непустой символ, она печатает столько пробелов, сколько насчитала до этого, а затем сбрасывает этот счетчик. Если он встречает пробел, он проверяет с помощью второго счетчика (напечатанные символы с начала строки / последней табуляции), находится ли курсор на табуляции. Если это так, то печатается вкладка, в противном случае просто подсчитывается пробел.

Вкладка на входе имеет дело со сбросом счетчика пробелов и выводом вкладки, устраняя любые лишние пробелы в процессе.

0 голосов
/ 11 ноября 2014

В ответе с самым высоким рейтингом выше, программа является слишком сложной. В попытке упростить эту часть ответа я прикрепил гораздо более простой код, который, как мы надеемся, был написан в стиле K & R (в основном путем увеличения на строку с ++).

включает

определить TAB 4

int main () {

char newsentence[255],c;
int spacecount = 0, oldsentencepointer = 0, newsentencepointer = 0;

printf("Give me a sentence please:\n");

while ((c = getchar()) != '\n') {
    if ((oldsentencepointer != 0) && (oldsentencepointer % TAB == 0) && (spacecount > 0))
       {
        newsentencepointer -= spacecount;         //if at tabstop, and spaces and not
                                                    first, go back to 1st space, set tab.
        newsentence[newsentencepointer++] = '\t';
        spacecount = 0;
        }

    if (c == ' ') {
        newsentence[newsentencepointer++] = ' ';
        spacecount++;                       //keep track of spaces before tab stop
    }

    else if (c == '\t') {
        newsentence[newsentencepointer++] = '\t' ;
        oldsentencepointer = TAB;   //set old pointer to TAB (does not matter if actual,
                                      only cadence important)
        continue;                   //continue from here so as not to increment 
                                      old sentence counter.
        }

    else {
        newsentence[newsentencepointer++] = c ;   //write whatever was old into new.
        spacecount = 0;                           //reset space counter.
        }

    oldsentencepointer++;

}

newsentence[newsentencepointer] = '\0';    //cap it off.

puts(newsentence);

return 0;

}

0 голосов
/ 05 сентября 2010

Я сейчас пашу KnR и наткнулся на эту страницу:

Ответы на упражнения

Ваше упражнение находится в:

Надеюсь, вы найдете это полезным.

С уважением, Морфх

1 : http://users.powernet.co.uk/eton/kandr2/index.html "Язык программирования C", 2-е издание, Керниган и Ричи - Ответы на упражнения

0 голосов
/ 11 июня 2010

Я очень бегло посмотрел на твой код, и ничто не показалось мне вопиющим неправильным.

Так что мой совет - либо пошагово пройти несколько примеров ввода в отладчике, исследуязначения переменных, как вы идете, или добавить целую кучу отладочных операторов печати.В любом случае ваша цель - найти точку, в которой состояние программы начинает отклоняться от того, что вы ожидали или намеревались.

0 голосов
/ 11 июня 2010

Насколько я понимаю, вам не обязательно знать, в чем заключается проблема или как ее решить, чтобы ответить на этот вопрос.Кажется, возникает вопрос: понимаете ли вы, когда использовать переменные вместо «символических параметров».Я не совсем уверен, что подразумевается под «символическим параметром»;Похоже, это устаревшая номенклатура.

Сказав это, решение первой части вопроса (замена пробелов табуляцией) довольно простое.Думай о разделении и остатках.

...