【问题标题】:Kernighan and Ritchie C exercise 1-18Kernighan 和 Ritchie C 练习 1-18
【发布时间】:2021-10-12 09:18:37
【问题描述】:

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

编写一个程序来删除每行输入的尾随空格和制表符,并删除整个空白行。

我仍然要弄清楚如何实现第一个任务,但我对第二个任务有这样的想法:

#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] = '\0';
     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\0,那么i的值将是字符串长度的相同值——1(可以说是字符串不包括字符的长度) \n)。如果字符串完全为空,则返回 1,否则返回 0。这样如果blank(string,string's length) 返回 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] = '\0';
    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);
        }
    }
}

【问题讨论】:

  • 很好的尝试-它关闭了! main 中的 getchar() == EOF 吞下了换行符的第一个字符!
  • | 是按位或。也许您正在寻找||,逻辑或。在这种情况下它仍然可以工作,但代码看起来很奇怪。
  • @Lundin,谢谢,我只是输入了错误的符号

标签: c kernighan-and-ritchie


【解决方案1】:

main 中的getchar() == EOF 正在吞下每行中的第一个字符(在第一个字符之后)。你最好只在一个地方打电话给getchar

对当前实现造成最小流失的一种可能性是将唯一的getchar 调用保留在get_line1 中,如果在get_line1 中读取-1,则从get_line1 返回EOF,然后在@ 中处理987654331@,而不是在main 中调用getchar

【讨论】:

  • 非常感谢。我编辑了代码,现在它应该可以正常工作了。如果在 get_line1 中的 getchar 读取的字符是 EOF,则返回 -1,如果在 while 循环中读取 -1,则 j=0,这允许程序退出该循环。
  • 我还不明白为什么主中的 getchar() 在第一行之后将每行的第一个字符都覆盖了。这背后有简单的解释吗?
  • 您在终端中输入的字符进入队列(stdin 缓冲区)。 getchar 函数从该队列中弹出(读取和删除)一个字符(如果队列为空,则等待队列中有某些内容)stackoverflow.com/questions/14068346/…
  • 所以在你的例子中:如果你在终端中输入Once upon a time\nThgetcharget_line1 中的调用将读取Once upon a time\n 并将它们从队列中删除。然后 main 中的 getchar 将读取 T,并将其从队列中删除。您不会将其分配给变量,因此在比较后会忘记它。对 getchar 的下一次调用将等待以下字符 (h)
  • 我很高兴!请问您能接受这个答案吗? stackoverflow.com/help/someone-answers
【解决方案2】:

不要在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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    相关资源
    最近更新 更多