我最近开始通过K&R,第二版学习C。我正在尝试解决练习1-18,该练习具有以下描述:编写程序以从输入的每一行中删除结尾的空白和制表符,并删除整个空白行。
这是我的尝试(使用MAXLINE=10
调试程序)
#include <stdio.h>
#define MAXLINE 10 /*maximum input line size*/
int getline(char[],int);
int main()
{
int len; /*current line length*/
char line[MAXLINE]; /*current input line*/
while ((len = getline(line,MAXLINE))>-1)
if (len>0)
printf("%s",line);
return 0;
}
/*getline:read a line into s without trailing whitespaces, return length*/
int getline(char s[],int lim)
{
int i,c,j;
i=j=0;
while (j<lim-1 && (c=getchar())!=EOF && c!='\n')
{
s[j]=c;
++j;
if (c!='\t' && c!=' ')
i=j;
}
if (c=='\n' && i>0) {
s[i] = c;
++i;
}
s[i] = '\0';
if (c==EOF)
return -1;
return i;
}
因此,基本思想是我不断将读取的字符填充到行中,而且还要跟踪(过去一次)最后一个非跟踪空白字符的位置。然后,我将空字符放在此位置,以为printf("%s",whatever)
实际上会打印任何内容,直到遇到第一个空字符为止。
程序的行为与预期的一样,包含9个或更少的字符(末尾包括\n
)。但是,它会继续打印带有更多字符的输入,我不明白为什么。例如,我的输入为1234567891\n
的程序实际上会打印回1234567891\n
(是的,它甚至会更改行!)。我想念什么?
答案 0 :(得分:0)
当输入为“ 123456789”后跟换行符:
while (j<lim-1 && (c=getchar())!=EOF && c!='\n')
重复九次。在上一次迭代中,c=getchar()
已将'9'
放在c
中,而j
是9。j<lim-1
为假,因为j
为9而lim-1
为10-1,因此循环退出。if (c=='\n' && i>0)
不执行任何操作,因为c
包含'9'
。s[i] = '\0';
附加一个空字符,然后getline
返回到main
。main
打印缓冲区(line
),输出为“ 123456789”。main
再次调用getline
。while (j<lim-1 && (c=getchar())!=EOF && c!='\n')
的第一次迭代中,getchar()
返回了'\n'
,并将其放入c
中。然后,由于c!='\n'
为假,循环终止。i
为0。if (c=='\n' && i>0)
不执行任何操作,因为i>0
为假。s[i] = '\0';
附加一个空字符,然后getline
返回到main
。line
的开头包含一个空字符。 main
打印此内容时,不会打印任何内容。结论:设计有缺陷。 getline
旨在通过在行为空(测试i
期间if (c=='\n' && i>0)
为零)时不添加换行符来完全消除空白行,但在行以及由于缓冲区大小而未完全处理的行的延续。当要求它继续行并且该行恰好以换行符继续时,它将其视为完全空白的行并禁止添加换行。
一种补救方法是在getline
中添加一个参数,以告知它是要换行还是继续行,然后适当地修改测试if (c=='\n' && i>0)
设计中的另一个缺陷是,如果一行由于缓冲区已满而在getline
停止处理的行之前包含空格和/或制表符,则它们将丢失,因为getline
会写一个空字符,以标记分行的非空白部分的结尾并返回到main
,从而省去了挂起的空白和/或制表符,因为以后的行继续包含非空白字符。
答案 1 :(得分:-2)
我不知道这是否是完整答案,但是我认为您需要:
char line[MAXLINE+1].. this
这是因为您正在读取10,但是您的数组需要一个额外的空间来容纳null。
此外,我将尝试总体上提高代码的可读性。可能将某些事情分解为功能,将某些事情作为单独的步骤进行。当您早已忘记了代码应做的事情时,您会在6个月内感谢自己。