这个小C程序是否满足K& R练习?

时间:2010-08-12 13:00:13

标签: c kernighan-and-ritchie

我正在参加K& R的练习1-18

  

编写程序以从每行输入中删除尾随空白和制表符,并删除完全空行。

这是我到目前为止所提出的

#include <stdio.h>

#define MAXLINE 1000

int getline(char line[], int maxline);
void copy(char to[], char from[]);

int main () {

    int len;
    char line[MAXLINE];

    while (getline(line, MAXLINE) > 0) {
            printf("%s", line);
    }
    return 0;
}


int getline(char s[], int lim) {
    int c, i, lastNonBlankIndex;
    lastNonBlankIndex = 0;

    for (i=0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) {

        if (c != ' ' && c != '\t') {
            lastNonBlankIndex = i + 1;

        } 

        s[i] = c;
    }

    if (i != lastNonBlankIndex) {
        i = lastNonBlankIndex;
        c = '\n';
    }

    if (c == '\n') {
        s[i] = c;   
        ++i;
    }
    s[i] = '\0';
    return i;
}

第二部分听起来很难,因为如果线只有空格或标签,我不确定应该返回什么。毕竟,如果我返回0,它将停止getline()通话。这是我应该设置#define的地方,例如ALL_BLANKS

无论如何,对于实际的主要问题,这是从行中删除尾随空白和制表符的正确方法吗?我通过了几个输入,似乎工作。但是,如果我将带有换行符的文本复制并粘贴到CL中,它们会显示在一起。当我在CL中输入一行并按下回车键时,它会自动打印出来。我应该构建一个行数组,然后在完成后循环并打印它们吗?

5 个答案:

答案 0 :(得分:5)

您的代码看起来是正确的,但我认为如果您将行读取stdin并剥离尾随空格行(解耦)分开会更好。然后你可以使用书中未经修改的getline(代码重用),并且不会在返回0时停止。

如果您对其他解决方案感兴趣,CLC-wiki有一个几乎完整的K&R2 solutions列表。

#include <stdio.h>
#define MAXLINE 1024

int getline(char s[], int lim);

main()
{
    int i, len;
    char line[MAXLINE];

    while ((len = getline(line, MAXLINE)) > 0) {
        i = len - 2;
        while (i >= 0 && (line[i] == ' ' || line[i] == '\t'))
            --i;
        if (i >= 0) {
            line[i+1] = '\n';
            line[i+2] = '\0';
            printf("%s", line);
        }
    }
    return 0;
}

这是我前段时间写的第1类解决方案。 getline与本书第28页相同。将空格移除到单独的函数rstrip中可能更好,但我将此作为练习留给读者。

答案 1 :(得分:0)

您的基本设计是合理的。如你所做的那样,在你构建它之后立即打印剥离的线条会更好,这样你的程序一次只需要在内存中保留一行,而不是整个文件。

您的代码存在一个小问题:它没有实现问题的第二部分(“完全删除空行”)。那是因为你总是在字符串末尾添加'\n'。这很容易修复,但请记住,您必须向调用者返回非零值,因为空行不表示文件的结尾。

答案 2 :(得分:0)

如果出现错误或达到EOF,

getline应返回-1(一般为负值)。然后你的循环条件可以检查它返回一些>= 0并仍然允许0长度行。

for (i=0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) {

我几乎从不在循环条件中包含赋值。我宁愿添加10行代码来解决这个问题,因为它很难阅读。我特别避免在复杂的条件下使用它们。

int i = 0;

while (i < lim) {
   c = getchar();
   if (c == EOF || c == '\n') {
       break;
   }
   line[i] = (char)c;
   i++;
}
line[i] = '\0'; // Null terminate the string

此代码应该为您阅读。我会将行的读取与删除尾随的空格分开。您可以非常轻松地从字符串的末尾向后工作,以删除我在null终止该行的位置处的空格,因为在读取该行后您现在知道它的长度。基本上你会长出字符串,然后在它完成成长后将其修剪回来。

答案 3 :(得分:0)

这就是我做到的。

#include <stdio.h>
#define MAXLINE 1000

#define IN 1
#define OUT 0

int state = OUT;

int getline(char s[], int lim);
void copy(char to[], char from[]);

int main(void)
{
int lenght;
int max = 0;
char line[MAXLINE];
char longest[MAXLINE];

while ((lenght = getline(line, MAXLINE)) > 0)
    if (lenght > max)
    {
        max = lenght;
        copy(longest, line);
    }
if (max > 0)
    printf("\n%s\n", longest);

    return 0;

    }
   int getline(char s[], int lim)
   {
   int i, c;
   for (i = 0; i < lim - 1 && ((c = getchar()) != EOF) && (c != '\n'); i++)
   {


    if (state == IN && c != ' ' && c != '\t')
    {
        s[i] = ' ';
        i++;
        state = OUT;
    }
    if (s[0] == ' ')
    {
        s[0] = '\b';
    }


    s[i] = c;


    if (c == ' ' || c == '\t')
    {
        i--;
        state = IN;
    }
}
if (c == '\n')
{
    s[i] = c;
    i++;
}
s[i] = '\0';

return i;
 }

void copy(char to[], char from[])
{
int i = 0;
while ((to[i] = from[i]) != '\0')
    i++;
}

答案 4 :(得分:-1)

#include <stdio.h>

#define MAXLINE 1000

size_t getline(char *s,size_t lim)
{
  if( fgets(s,lim,stdin) )
  {
    while( *s && strchr(" \t\n",s[strlen(s)-1]) )
      s[strlen(s)-1]=0;
    return strlen(s);
  }
  return 0;
}

main()
{
    int len;
    char line[MAXLINE];

    while (getline(line,sizeof line)) {
            printf("%s", line);
    }
    return 0;
}