0

I was trying to complete the task requested by this exercise from the K&R book:

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

I still have to figure out how to implement the first task, but I have this idea for the second one:

#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;
        }
    }
}

The function blank1 takes as input a string s[] and the string's length len.

Then it cycles for all the string and increases the counter i every time it hits a blank or tab. If the string is completely made of blank or tab, such as \t\t\t\n\0, then the value of i will be the same value of the length of the string - 1 (so to speak, the length of the string excluding the character \n). If the string is completely blank, then 1 will be returned, otherwise 0. So in this way if blank(string,string's length) returns 1, we know it is a wholly blank string and we can avoid printing it, as the exercise requests.

The problem is that with some outputs this program cuts the first letter. For instance with:

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

What is printed is:

Once upon a time
here was a little monke
hat

I can't manage to get why this truncation occurs.

EDIT:

#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);
        }
    }
}
Yun
  • 3,056
  • 6
  • 9
  • 28
PwNzDust
  • 271
  • 2
  • 9

2 Answers2

1

getchar() == EOF in main is swallowing your first character from each line (after the first). You are better off calling getchar in only one place.

One possibility that causes minimal churn to your current implementation is to keep the only getchar call inside get_line1 and return -1 from get_line1 if a EOF is read there, to then be handled inside main, instead of the call to getchar inside main.

SamBob
  • 849
  • 6
  • 17
  • 1
    Thanks a lot. I edited the code, now it should work properly. if the character read at getchar inside get_line1 is EOF, then -1 is returned and if -1 is read n the while-loop then j=0 and this allow the program to exit that loop. – PwNzDust Oct 12 '21 at 09:54
  • 1
    what i do not yet understand is why the getchar() in the main swalled the first character of every line after the first one. Is there a simple explaination behind this? – PwNzDust Oct 12 '21 at 09:55
  • 1
    Characters you type into the terminal go an a queue (the `stdin` buffer). The `getchar` function pops (reads and deletes) a character off that queue (waiting for there to be something on the queue if it was empty) https://stackoverflow.com/questions/14068346/what-is-the-standard-input-buffer – SamBob Oct 12 '21 at 10:24
  • 1
    So in your example: If you type `Once upon a time\nTh` into the terminal the `getchar` calls in `get_line1` would read `Once upon a time\n` and remove them from the queue. Then the `getchar` in main would read `T`, and remove it from the queue. You don't assign it to a variable so its forgotten after comparison. The next call to getchar would wait for the following char (`h`) – SamBob Oct 12 '21 at 10:24
  • thanks, it was very clear – PwNzDust Oct 12 '21 at 14:45
  • 1
    I'm glad! Would you be able to accept this answer please? https://stackoverflow.com/help/someone-answers – SamBob Oct 13 '21 at 09:19
0

Do not program in main use functions for similar tasks.

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

0___________
  • 60,014
  • 4
  • 34
  • 74