为什么我的代码打印出空字符?

时间:2019-09-03 20:42:51

标签: c

我最近开始通过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(是的,它甚至会更改行!)。我想念什么?

2 个答案:

答案 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个月内感谢自己。