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

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

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

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

#include  #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中输入一行并按下回车键时,它会自动打印出来。 我应该构建一个行数组,然后在完成后循环并打印它们吗?

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

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

 #include  #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可能更好,但我将此作为练习留给读者。

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

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

如果出现错误或达到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终止该行的位置处的空格,因为在读取该行后您现在知道它的长度。 基本上你会长出字符串然后在它完成成长后将其修剪回来。

这就是我做到的。

 #include  #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++; } 
 #include  #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; }