10

我正在从 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

4 回答 4

7

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

  • 评论你的东西
  • 正确命名变量,如果您拒绝,至少给出描述
  • 因此,一些单行 if 是你使用的,而另一些你不使用。(恕我直言,请始终使用 {} 以使其更具可读性)
  • 最后一个 for 循环中的 if 语句可以更好,比如

    if(array[0] != NEWLINE)  
    {   
        printf("%c", array[line]); 
    }
于 2009-04-10T06:45:05.523 回答
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", ...)),将未打印的内容复制到缓冲区的开头,然后继续
于 2009-04-10T10:38:29.847 回答
0

一个明显的问题是您静态分配“数组”并且在访问它时从不检查索引限制。等待发生的缓冲区溢出。事实上,你从来没有在第一个循环中重置 i 变量,所以我对程序应该如何工作感到有点困惑。似乎您在打印单词包装之前将完整的输入存储在内存中?

因此,建议:将两个循环合并在一起并打印您已完成的每一行的输出。然后您可以将数组重新用于下一行。

哦,还有更好的变量名和一些注释。我不知道'DELIM'应该做什么。

于 2009-04-10T05:58:53.793 回答
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

已经很晚了,我刚拿到一条腰带,所以可能有缺陷,但它显示了总体思路——加载一个缓冲区,并将缓冲区的内容复制到一个行缓冲区,跟踪可能的断点。当你接近尾声时,使用断点。

于 2009-04-10T05:59:58.877 回答