Thread: Exercise 1-18 from "The C programming language 2nd edition"

  1. #1
    Registered User
    Join Date
    Feb 2018
    Posts
    7

    Question Exercise 1-18 from "The C programming language 2nd edition"

    Hello everyone.
    I'm trying to understand why my program wont work correctly.
    At this point I'm blocked.
    Exercise asking:
    "Write a program to remove trailing blanks and tabs from each line of input, and to delete entirely blank lines."

    What I'm observing is:
    If I put some characters followed by trailing blanks (or tabs) I get a nice result (or I think so?).
    But when I'm writing only characters the result is always a line with minus one character.

    My system: Debian 64bit as virtual machine.

    Here is the code:

    Code:
    #include <stdio.h>
    
    #define MAXLINE 1000    /* maximum input line size */
    
    int remove_blanks_from_input(char line[], int maxline);
    
    /* print longest input line */
    int main()
    {
        char line[MAXLINE];
        int status;
    
        while ((status = remove_blanks_from_input(line, MAXLINE)) > 0) {
            if (status != 1) {
                printf("%s", line);
            }
        }
    
        if (status < -1)
            printf("%s", line);
        
        if (status == 0) printf("Check the test conditions in 'remove_blanks_from_input' funtion.\n");
    
        return 0;
    }
    
    /* remove_blanks_from_input: remove trailing blanks and tabs and delete entirely blank lines */
    int remove_blanks_from_input(char s[], int lim)
    {
        int c, i, j, blanks_count = 0;
    
        for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i) {
            // use a limited size buffer character array s[]. If size of the input line is bigger that buffer_size - 1 stop copying. Last index is for null character.
            if (i < lim - 1) {
                j = i;
                s[j] = c;
            }
            
            // count current blanks string
            if (c == ' ' || c == '\t') ++blanks_count;
            else blanks_count = 0;
        }
        
        
        // If number of characters in the incoming line (not including '\n') is equal to number of blanks encountered, consider line empty.
        // 
        if ((i - blanks_count) == 0 && c == EOF) 
            return -1;
        else if ((i - blanks_count) == 0) 
            return 1;
            
        // If number of blanks in current blanks string is less than the length of the incoming chracter array => there is some printable characters in it.
        else if ((i - blanks_count) <= j && c == EOF) {
            s[i - blanks_count + 1] = '\0';
            return -2;
        }
        else if ((i - blanks_count) <= j) {
            if (j < lim - 2) {
                s[i - blanks_count + 1] = '\n';
                s[i - blanks_count + 2] = '\0';
                return 2;
            }
            else {
                // the element at index 'lim - 2' will be lost (replaced by '\n')
                s[i - blanks_count] = '\n';
                s[i - blanks_count + 1] = '\0';
                return 2;
            }
        }
        
        // If length of the incoming character array minus length of the current blanks string is >= lenght of the buffer character array minus 1.
        else if ((i - blanks_count) > j && c == EOF) {
            s[++j]  = '\0';
            return -2;
        }
        else if ((i - blanks_count) > j) {
            // the elemnts at indexes 'lim - 2' including and further will be lost
            s[j] = '\n';
            s[++j] = '\0';
            return 2;
        }
        else return 0;    // if status code is 0. Probably some of the test conditions are wrong
    }
    Thanks for your answer. I hope code is clear enough to understand.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I propose that your algorithm is too complicated. Consider that you only need to remove trailing blanks, and this is arguably true even if the line is empty save for the blanks. Therefore, a simpler algorithm would be:
    Code:
    search from the end of the line to find the last non-blank character
    if no such character is found
        set the string to be an empty string
    else
        set the character after the last non-blank character to be a null character
    By searching from the end (i.e., first find the null character that terminates the string... or if you use fgets instead of reading character by character this could be the newline character that you then replace with a null character), the first non-blank character encountered is therefore the last non-blank character in the string. What you have to be careful about is to avoid accessing the array out of bounds from the front in the event all the characters are blank, but as long as you think about loop indices carefully that should be fine.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    He already has a reasonable way of determining where any terminal run of spaces starts.

    What is complicating the function is that it's trying to do too much. There's no reason for it to signal if the line is blank or not. The main function can determine if the line is empty or not by checking the first char.

    There's also no reason to try to signal the EOF condition at the same time that you're returning valid data. The getchar will return EOF next time it's executed, too, so just leave the EOF detection until then.
    Code:
    // main
        while (trim(line, size))
            if (line[0] != '\0')
                printf("%s\n", line);
    
    // trim
        for (i = 0; i < size-1 && (c = getchar()) != EOF && c != '\n'; ++i) {
            s[i] = c;
            if (c == ' ' || c == '\t') ++blanks_count;
            else blanks_count = 0;
        }
        if (c == EOF && i == 0)
            return 0;
        s[i - blanks_count] = '\0';
        return 1;
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #4
    Registered User
    Join Date
    Feb 2018
    Posts
    7
    Quote Originally Posted by john.c View Post
    He already has a reasonable way of determining where any terminal run of spaces starts.

    What is complicating the function is that it's trying to do too much. There's no reason for it to signal if the line is blank or not. The main function can determine if the line is empty or not by checking the first char.

    There's also no reason to try to signal the EOF condition at the same time that you're returning valid data. The getchar will return EOF next time it's executed, too, so just leave the EOF detection until then.
    Code:
    // main
        while (trim(line, size))
            if (line[0] != '\0')
                printf("%s\n", line);
    
    // trim
        for (i = 0; i < size-1 && (c = getchar()) != EOF && c != '\n'; ++i) {
            s[i] = c;
            if (c == ' ' || c == '\t') ++blanks_count;
            else blanks_count = 0;
        }
        if (c == EOF && i == 0)
            return 0;
        s[i - blanks_count] = '\0';
        return 1;
    Thanks.
    This version is less complicated and elegant. I will try not to create a super trim program at this moment anyway.
    How I understand if 'i' is equal to zero we should exit 'while' loop. So if we type on the terminal enter this will produce a sting containing only '\n' and the value of 'i' will be zero (and as consequence 'return 0' from trim routine). But program does not exit the 'while' loop.
    Edit. I forgot that there is an '&&' with 'EOF'. It's clear.
    Last edited by abuser; 02-08-2018 at 12:10 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 02-29-2016, 10:45 AM
  2. Stuck on Chapt. 1.10 "The C Programming Language"
    By RAkron in forum C Programming
    Replies: 14
    Last Post: 08-15-2015, 03:05 PM
  3. Replies: 4
    Last Post: 11-19-2011, 07:57 PM
  4. Question about the book "The C Programming Language"
    By caduardo21 in forum C Programming
    Replies: 4
    Last Post: 05-15-2005, 01:22 PM
  5. Replies: 7
    Last Post: 08-28-2003, 10:15 PM

Tags for this Thread