Обучение c: К&Р 1-22: "фолд". Это решение очень громоздкое?


Это упражнение дало мне некоторые неприятности, но я думаю, я нашел решение здесь, что соответствует спецификации. Однако это очень долго по сравнению с тем что я смотрю на решения страницы clc-wiki.net.

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

Если кто-то достаточно любезен, чтобы иметь терпение, чтобы прочитать это, я действительно ценю ваши мысли. Это может быть короче? Есть ли какие-то явные повторы?

#include <stdio.h>

#define FOLD 20

int getline( char s[], int max );
int does_line_have_blanks( char line[], int len );
int locate_last_space ( char line[], int len );
int find_split( char line[], int len, int offset);
int mark_split_and_clean_trailing_spaces( char line[], int len, int spacecount );
int print_with_split( char s[], int split_pos );

int main()
{
  int len, i, split_pos, offset;
  char line[FOLD+1];

  len = split_pos = 0;
  for ( i = 0; i < FOLD+1; ++i )
    line[i] = 0;
  offset = 0; /*keeps track of characters that overflow the split so next buffer may be shortened accordingly*/

  while ( ( len = getline(line, (FOLD+1) - offset) ) > 0 ) {

    split_pos = find_split ( line, len, offset );

    offset = print_with_split( line, split_pos );

    /* clean out buffer*/
    for ( i = 0; i < FOLD+1; ++i )
      line[i] = '\0';
  }
  return 0;
}

int getline ( char s[], int max ) /* doesn't add newlines as K&R's does */
{
  int i, c;

  for (i = 0 ; i < max-1 && (c = getchar()) != EOF && c != '\n'; i++ )
    s[i] = c;
  s[i] = '\0';

  return i;
}

int find_split( char line[], int len, int offset ) {

    int i, split_pos, blanks;

    i = split_pos = 0;

    /*make sure there are blanks - if not the line will be printed as-is*/ 
    blanks = does_line_have_blanks( line, len );

    if ( len < FOLD-offset || blanks != 1 ) {
      split_pos = len; /* hit a newline or EOF - split at end of input */
    } else {
      split_pos = locate_last_space( line, len );
    }
    return split_pos;
}

int does_line_have_blanks( char line[], int len ) {

  int i, blanks;

  i = blanks = 0;

  for ( i = 0; i < len; ++i )  { /*len is at null char in line*/
    if (line[i] == ' ' )
      blanks= 1;
  }
  return blanks;
}

int locate_last_space ( char line[], int len ) {

  int i, inspace, spacecount, split_pos;

  inspace = spacecount = split_pos = 0;

  for ( i = 0; i < len; ++i ) {
    if ( line[i] == ' ' ) {
      inspace = 1;
      ++spacecount;
    } else {
      inspace = 0;
      if ( spacecount > 0 ) { /*if we leave inspace state, split on the preceding char */
        spacecount = 0;
        split_pos = i -1;
      }
    }
  }

  if ( inspace == 1 ) { /* and if we left in a space... */
    split_pos = mark_split_and_clean_trailing_spaces( line, len, spacecount );
  }

  return split_pos;
}

int mark_split_and_clean_trailing_spaces( char line[], int len, int spacecount ) {

  int split_pos, i;

  split_pos = i = 0;

  split_pos = len - spacecount; /*... split where it started */
  for ( i = split_pos + 1; i < len; ++i ) { /*nullify trailing spaces as per instructions*/
    line[i] = '\0';
  } 

  return split_pos;
}

int print_with_split( char line[], int split_pos ) {

   int i, offset;

   offset = 0;

   for ( i = 0; i < split_pos; ++i ) {
      putchar(line[i]);
    }
    putchar('\n');
    for ( i = (split_pos + 1 ); line[i] != '\0'; ++i) /*miss out the space we split on*/ {
      ++offset; /* extra chars on next line, so buffer will be smaller */
      putchar(line[i]);
    }

    return offset;
}

Редактировать добавлено возвращаемый тип для функции main()



475
4
c
задан 25 сентября 2011 в 12:09 Источник Поделиться
Комментарии
2 ответа

Вы должны знать, что вы повторно писать функции в стандартной библиотеке.
Это все правильно, если вы учитесь, и я хотел бы призвать вас продолжать это делать (это отличный способ, чтобы учиться), но вот несколько мыслей из этого угла:

Гэтлину - это в основном , чем fgets.

locate_last_space - это то, что strrchr(стр ' ') нет. (Обратите внимание на дополнительную Р здесь означает "поиск наоборот")

does_line_have_space - вы можете использовать функции strchr(стр ' ') как логическое выражение. (Если результат ненулевой, то он имеет этот символ.)

find_split - это кажется немного излишним для вызова does_line_have_space до locate_last_space. Вы можете использовать результат strrchr(стр, ' ') , чтобы определить, что есть пространство (результат ненулевой) и пространстве (используя результат как указатель).

В качестве точки стиль я бы сказал, что это было бы более "C-подобный" говорить с точки зрения арифметики указателей, а не взаимозачетами. (т. е. принять результат strrchr, что-то делать с этим указателем, а не думать с точки зрения "дайте мне смещение ближайшего космоса".)

1
ответ дан 27 сентября 2011 в 06:09 Источник Поделиться

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

Таким образом, основной цикл, что выйдет что-то вроде этого:

while (getword(buffer, max_len)!=EOF) {
if (current_length + strlen(buffer) > max_len) {
print("\n");
current_length = 0;
}
print(buffer);
current_length += strlen(buffer);
}

2
ответ дан 25 сентября 2011 в 03:09 Источник Поделиться