K& R第1章 - 练习22解决方案,你怎么看?

时间:2009-04-10 05:02:39

标签: c kr-c

我从k& r学习C作为第一语言,我只是想问,如果你认为这个练习是以正确的方式解决的,我知道它可能不像你那么完整。我喜欢,但我想要观点,所以我知道我正在学习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 个答案:

答案 0 :(得分:7)

我确信你在严谨的轨道上,但有一些可读性的指针:

  • 评论你的东西
  • 正确命名变量,至少在拒绝时给出说明
  • 因此,如果您使用某些单行,而有些则不使用。 (imho,总是使用{}所以它更具可读性)
  • 最后一个for循环中的if语句可以更好,比如

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

答案 1 :(得分: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", ...)打印),将未打印的内容复制到缓冲区的开头,从那里开始

答案 2 :(得分:0)

一个明显的问题是你静态分配'array'并且在访问它时从不检查索引限制。缓冲区溢出等待发生。事实上,你永远不会在第一个循环中重置i变量,所以我对程序应该如何工作感到困惑。看来你是在将完整的输入存储在内存中,然后再将其打印成文字包裹?

所以,建议:将两个循环合并在一起并打印已完成的每一行的输出。然后你可以重新使用数组作为下一行。

哦,更好的变量名称和一些评论。我不知道'DELIM'应该做什么。

答案 3 :(得分:0)

它看起来(没有测试)就像它可以工作,但它似乎有点复杂。

这是我第一次想到的伪代码

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

已经很晚了,我只是有一个皮带,所以可能存在缺陷,但它显示了一般的想法 - 加载缓冲区,并将缓冲区的内容复制到行缓冲区,跟踪可能的断点。当你接近结束时,使用断点。