K & R Глава 1 - Упражнение 22 решение, что вы думаете? - PullRequest
10 голосов
/ 10 апреля 2009

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

Спасибо

/* Exercise 1-22. Write a program to "fold" long input lines into two or
 * more shorter lines, after the last non-blank character that occurs
 * before then n-th column of input. Make sure your program does something
 * intelligent with very long lines, and if there are no blanks or tabs
 * before the specified column.
 * 
 * ~svr
 *
 * [NOTE: Unfinished, but functional in a generic capacity]
 * Todo:
 * Handling of spaceless lines
 * Handling of lines consisting entirely of whitespace
 */

#include <stdio.h>
#define FOLD 25
#define MAX 200
#define NEWLINE '\n'
#define BLANK ' '
#define DELIM 5
#define TAB '\t'

int
main(void)
{
    int line  = 0, 
        space = 0,
        newls = 0,
            i = 0, 
            c = 0, 
            j = 0;

    char array[MAX] = {0};

    while((c = getchar()) != EOF) {
        ++line;
        if(c == NEWLINE)
            ++newls;
        if((FOLD - line) < DELIM) {
            if(c == BLANK) {
                if(newls > 0) {
                    c = BLANK;
                    newls = 0;
                }
                else
                    c = NEWLINE;
                line = 0;
            }
        }
        array[i++] = c;
    }
    for(line = 0; line < i; line++) {
        if(array[0] == NEWLINE)
            ;
        else
            printf("%c", array[line]);
    }
    return 0;
}

Ответы [ 4 ]

7 голосов
/ 10 апреля 2009

Я уверен, что вы на правильном пути, но некоторые указатели для читабельности:

  • комментируйте свои вещи
  • правильно называйте переменные и, по крайней мере, дайте описание, если вы откажетесь
  • будьте последовательны, некоторые однострочные, если вы используете, а некоторые нет. (imho, всегда используйте {}, чтобы оно было более читабельным)
  • оператор if в последнем цикле for может быть лучше, например

    if(array[0] != NEWLINE)  
    {   
        printf("%c", array[line]); 
    }
2 голосов
/ 10 апреля 2009

Это не хорошо, ИМХО.

Во-первых, он не делает то, о чем вас просили. Вы должны были найти последний пробел после непустого перед границей выходной линии. Ваша программа даже не пытается это сделать удаленно, похоже, она пытается найти первые пробелы после (поля - 5) символов (откуда взялись 5? Что, если все слова имеют 9 букв?). Однако это также не происходит из-за ваших манипуляций с переменной newls. Также это:

for(line = 0; line < i; line++) {
    if(array[0] == NEWLINE)
        ;
    else
        printf("%c", array[line]);
}

, вероятно, неправильно, потому что вы проверяете условие, которое никогда не меняется в цикле.

И, наконец, что не менее важно, хранение всего файла в буфере фиксированного размера не годится по двум причинам:

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

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

  • обрабатывает файл построчно (имеется в виду выходные строки)
  • сохранить строку в буфере, достаточно большом, чтобы вместить наибольшую строку вывода
  • поиск символа, по которому вы будете разбивать, в буфере
  • затем распечатайте его (подсказка: вы можете завершить строку с помощью '\ 0' и распечатать с помощью printf("%s", ...)), скопировать то, что вы не распечатали, в начало буфера, продолжить с этого
0 голосов
/ 10 апреля 2009

Выглядит (без тестирования), как будто это может работать, но кажется сложным.

Вот какой-то псевдокод для моей первой мысли

const int MAXLINE = ??  — maximum line length parameter
int chrIdx = 0 — index of the current character being considered 
int cand = -1  — "candidate index",  Set to a potential break character
char linebuf[bufsiz]
int lineIdx = 0 — index into the output line
char buffer[bufsiz]   — a character buffer
read input into buffer
for ix = 0 to bufsiz -1
do     
   if buffer[ix] == ' ' then
      cand = ix
   fi
   linebuf[lineIdx] = buffer[ix]
   lineIdx += 1
   if lineIdx >= MAXLINE then
      linebuf[cand] = NULL — end the string
      print linebuf
      do something to move remnants to front of line (memmove?)
   fi
 od

Уже поздно, и у меня просто был пояс, поэтому могут быть недостатки, но он показывает общую идею - загрузить буфер и скопировать содержимое буфера в строковый буфер, отслеживая возможные точки останова. Когда вы приблизитесь к концу, используйте точку останова.

0 голосов
/ 10 апреля 2009

Очевидная проблема состоит в том, что вы статически выделяете массив и никогда не проверяете пределы индекса при доступе к нему. Переполнение буфера в ожидании. На самом деле, вы никогда не сбрасываете переменную i в первом цикле, поэтому я не совсем понимаю, как должна работать программа. Кажется, что вы сохраняете полный ввод в памяти перед печатью, завернутым в слова?

Итак, предложения: объедините два цикла и напечатайте вывод для каждой завершенной строки. Затем вы можете повторно использовать массив для следующей строки.

Да, и лучше имена переменных и некоторые комментарии. Я понятия не имею, что должен делать «DELIM».

...