Kernighan 和 Ritchie C 练习 1-18

Kernighan and Ritchie C exercise 1-18

我试图完成 K&R 书中本练习要求的任务:

Write a program to remove trailing blanks and tabs from each line of input, and to delete entirely blank lines.

第一个任务我还想着怎么实现,第二个任务我有这个想法:

#include <stdio.h>

#define MAXLINE 1000
#define IN 1
#define OUT 1
 
int blank1(char s[], int len){
    int i;
    int c=0;
    for (i=0; i<len;i++){
    if(s[i] == ' ' | s[i] == '\t')
        c++;
    }
    if (c==(len-1))
        return 1;
    else
        return 0;
}

int get_line1(char s[], int lim){
    int c,i;

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

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

     s[i] = '[=10=]';
     return i;
}

int main() {
    char line[MAXLINE];     
    int len;
    int j=1;
    int  i;
    
    while(j){
        len=get_line1(line,MAXLINE);
        if ((blank1(line,len)) == 0) {
        printf("%s", line);
        }

        if (getchar() == EOF){
            j=0;
        }
    }
}

函数 blank1 将字符串 s[] 和字符串的长度 len.

作为输入

然后它会循环所有字符串并在每次遇到空白或制表符时增加计数器 i。如果字符串完全由空格或制表符组成,比如\t\t\t\n[=17=],那么i的值将等于字符串长度的值-1(可以说是字符串的长度不包括字符 \n 的字符串)。如果字符串完全为空,则返回1,否则返回0。所以这样如果blank(string,string's length) returns 1,我们就知道它是一个完全空的字符串,我们可以避免打印它,因为练习请求。

问题是这个程序在某些输出中删掉了第一个字母。例如:

Once upon a time\n
There was a little monkey\n
That\n

打印出来的是:

Once upon a time
here was a little monke
hat

我无法理解为什么会出现这种截断。

编辑:

#include <stdio.h>

#define MAXLINE 1000
#define IN 1
#define OUT 1

int blank1(char s[], int len){
    int i;
    int c=0;
    for (i=0; i<len;i++){
        if(s[i] == ' ' | s[i] == '\t')
            c++;
    }
    if (c==(len-1))
        return 1;
    else
        return 0;
}

int get_line1(char s[], int lim){
    int c,i;

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

    if (c==EOF)
        return -1;  /////

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

    s[i] = '[=13=]';
    return i;
}

int main() {
    char line[MAXLINE];
    char verso[MAXLINE];
    char longest[MAXLINE];
    int len;
    int j=1;
    int  i;
    
    while(j){
        len=get_line1(line,MAXLINE);
        if (len==-1){            ///////////
            j=0;
        }       
        else if ((blank1(line,len)) == 0) {
            printf("%s", line);
        }
    }
}

getchar() == EOF in main 正在从每一行中吞下你的第一个字符(在第一行之后)。你最好只在一个地方调用 getchar

对您当前的实现造成最小改动的一种可能性是将唯一的 getchar 调用保留在 get_line1 和 return -1get_line1 中,如果在那里读取 EOF,然后在 main 中处理,而不是在 main.

中调用 getchar

请勿在 main 中使用函数完成类似任务。

char *skipLeadingBlanks(char *str)
{
    char *wrk = str;

    while((*wrk && *wrk != '\n') && (*wrk == ' ' || *wrk == '\t')) *wrk++;
    memmove(str, wrk, strlen(wrk) + 1);
    return str;
}

int main(void)
{
    char str[1024];

    while(fgets(str, sizeof(str), stdin))
    {
        skipLeadingBlanks(str);
        if(!*str || *str == '\n') continue;  //empty line
        printf("%s",str);
    }
}

https://godbolt.org/z/hxW5zP5Mx