K & R Chapter 1 - Упражнение 22, как вы думаете?

Я изучаю C из k & r как первый язык, и я просто хотел спросить, если вы считаете, что это упражнение было решено правильным способом, я знаю, что он, вероятно, не настолько полно, d like, но мне нужны взгляды, поэтому я бы знал, что я правильно изучаю 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;
}

Ответ 1

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

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

    if(array[0] != NEWLINE)  
    {   
        printf("%c", array[line]); 
    }

Ответ 2

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

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

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

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Здесь некоторый псевдокод для моей первой мысли

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

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