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