The C Programming Language, Ch.1 Exercise 1.10 (Getchar and Putchar)
Asked Answered
S

9

9

I've been working on this for 2 hours and I am stuck... I found the answer online, but that isn't going to help me learn the concept that I'm obviously missing.

Prompt: Write a program to copy its input to its output, replacing each tab by \t , each backspace by \b , and each backslash by \\ . This makes tabs and backspaces visible in an unambiguous way.

Here's what I came up with, it doesn't replace a tab or \ with the indicated putchar, it just adds it in front of it.(I didn't do backspace because I can't really input a backspace...):

This is how I read the code. What am I missing?:

"There is some integer c. c is equal to the input. When the input is not equal to end of file proceed. If input is tab then the output \t. If input is \ then output \\. Output the input to console."

int c;

while((c=getchar())!=EOF)
{
    if(c=='\t')
        {
            putchar('\\');
            putchar('t');
        }

    if(c=='\\')
        {
            putchar('\\');
            putchar('\\');
        }
    putchar(c);
}
Shornick answered 7/4, 2014 at 4:5 Comment(1)
"If input is tab then the output \t. If input is \ then output \\. Output the input to console" -- and what if more than one of those happens?Costard
E
8

Your main problem is that you are outputting the character regardless of the fact that you may have already output its translation. Those if statements will do what you expect but, in their present form, they simply drop through to the next statement.

Hence you'd be looking for something more like this:

while ((c = getchar()) != EOF) {
    // Detect/translate special characters.

    if (c == '\t') {
        putchar ('\\');
        putchar ('t');
        continue;              // Go get next character.
    }

    if (c == '\b') {
        putchar ('\\');
        putchar ('b');
        continue;              // Go get next character.
    }

    if (c == '\\') {
        putchar ('\\');
        putchar ('\\');
        continue;              // Go get next character.
    }

    // Non-special, just echo it.

    putchar (c);
}

Another possibility, shorter and more succinct would be:

while ((c = getchar()) != EOF) {
    // Detect/translate special characters, otherwise output as is.

    switch (c) {
        case '\t': putchar ('\\'); putchar ('t');  break;
        case '\b': putchar ('\\'); putchar ('b');  break;
        case '\\': putchar ('\\'); putchar ('\\'); break;
        default:   putchar (c);
    }
}
Endoplasm answered 7/4, 2014 at 4:9 Comment(5)
or instead of so many continue you can also use else if instead of ifArnett
THANK YOU! You are my hero.Shornick
@theharshest, I prefer a consistent group of conditions at the start than the possibility of indent-hell :-) In any case, I'd probably implement it with the (new) switch variant myself).Endoplasm
Hi. The backspace though doesn't work. I have my variant with if else and I copied and compiled your 2 versions from above. I thought I would type some char and then hit backspace a couple of time then see \b instead of the canceled chars. Any hint?Nickerson
@vincent: if you're running with the standard input stream (i.e., in cooked rather than raw mode), it will be capturing backspaces and managing them be "erasing" the previous character, and the characters will be delivered as a batch when you hit ENTER. Your code will therefore never see the backspace. Suggest you use something like printf 'a\b' | your_program to test this. For example, printf 'a\b' | xxd gives 6108 (the a and the backspace).Endoplasm
E
5

I know im late to the party, but this question pops up in chapter one before else, case, continue, and functions are introduced.

Here is a working solution to exercise 1-10 that involves only concepts introduced up to the point of the exercise. You need to keep track of whether an escaped character was found and then display the copied character only if one was not found.

#include <stdio.h>

int main() {

  int input;

  while((input = getchar()) != EOF){

    int escaped = 0;

    if(input == '\t'){
        putchar('\\');
        putchar('t');
        escaped = 1;
    }

    if(input == '\b'){
        putchar('\\');
        putchar('b');
        escaped = 1;
    }

    if(input == '\\'){
        putchar('\\');
        putchar('\\');
        escaped = 1;
    }

    if(escaped == 0){
      putchar(input);
    }
  }
}
Evetteevey answered 14/11, 2017 at 6:56 Comment(0)
C
1

There are many ways to implement this and paxdiablo gave a couple of good ones. Here's one that illustrates the DRY principle via functional decomposition:

void putesc(char c)
{
    putchar('\\');
    putchar(c);
}

void ioloop(void)
{
      for (int c;;)
          switch (c = getchar())
          {
               case EOF:  return;
               case '\t': putesc('t'); break;
               case '\b': putesc('b'); break;
               case '\\': putesc(c); break;
               default:   putchar(c); break;
          }
 }
Costard answered 7/4, 2014 at 6:6 Comment(0)
S
1

Adding another solution! It's handy for us newbies to enrich us, seeing variety of solutions.

#include <stdio.h>

/* a program to copy its input to its output, replacing tab by \t,
    backspace by \b, backslash by \\  */
    
/* need double backslash to output a single backslash */

int main(){
    
    int c;          /*  to store next character from getchar() */
        
    while((c = getchar()) != EOF){
        if( c != '\t' && c != '\b' && c != '\\')        /* print all characters except special one's */
            putchar(c);                             
            
        else{
            if(c == '\t'){          /* replacing tab by \t */
                putchar('\\');
                putchar('t');
                }
            
            if(c == '\b'){          /* replace backspace by \b */ 
                putchar('\\');
                putchar('b');
                }
                
            if(c == '\\'){          /* replace backslash by \\ */
                putchar('\\');
                putchar('\\');
                }       
        }
        
    }

}
Sufism answered 20/7, 2021 at 16:20 Comment(0)
T
1

I'm a rookie. But considering only what they taught until to that point, I came up with this answer.

#include <stdio.h>

main() 
{
    int c;

    c = getchar();

    while (c != EOF) {
        if (c == '\t') {
            putchar('\\');
            putchar('t');
        }
        else if (c == '\b') {
            putchar('\\');
            putchar('b');
        }
        else if (c == '\\') {
            putchar('\\');
            putchar('\\');
        }
        else {
            putchar(c);
        }  
        c = getchar();  
    }
}
Tamra answered 20/2, 2022 at 9:32 Comment(0)
A
0

You are very close. Simply change the second "putchar()" in each block into an assignment statement and you have the correct output.

int c;

while((c=getchar())!=EOF)
{
    if(c=='\t')
        {
            putchar('\\');
            c = 't';
        }

    if(c=='\\')
        {
            putchar('\\');
            c = '\\';
        }
    putchar(c);
}
Anceline answered 17/10, 2019 at 6:1 Comment(0)
B
0
    #include <stdio.h>

    int main(int argc, const char * argv[]) {
    
        int c;
        int tab = 't';
        int backspace = 'b';
        int backslash = '\\';

        while((c = getchar()) != EOF){

            if (c == '\t'){
                putchar('\\');
                putchar(tab);
            }
            else if(c == '\b'){
                putchar('\\');
                putchar(backspace);
            }
            else if(c == '\\'){
                putchar('\\');
                putchar(backslash);
            }
            else{  // All other characters EXCLUDING "tab, backspace and backslash"
                  // will always be printed.
                putchar(c);
            }
        }

       return 0;
   }
Bowstring answered 15/10, 2022 at 13:41 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Xanthin
T
0
        int c;

    printf("Replace tabs, backspaces and backslashes with escape sequences while typing text\n");
    printf("Press Enter to stop:\n");

    struct termios oldt, newt;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);

    while ((c = getchar()) != EOF && (c != '\n'))
    {
        switch (c)
        {
        case '\t':
            printf("\\t");
            break;
        case 127:  // ASCII value for backspace
            printf("\\b");
            break;
        case '\\':
            printf("\\\\");
            break;
        default:
            putchar(c);
        }
    }

    printf("\nThank you for trying it out!\n");

    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 

    return 0;
Tradesman answered 13/1 at 13:59 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Xanthin
I
-2

Just before the exercise, the book mentions ASCII code and not more advanced statements. In consequence, I think the solution was oriented to use ASCII.

    int c;
    while ( (c = getchar()) != EOF ){
        //92 is the ASCII code for the backslash \
        if ( c == '\t'){
            putchar(92);
            putchar('t');
        }else if ( c == '\\' ) {
            putchar(92);
            putchar(92);
        }else if ( c == '\b' ) {
            putchar(92);
            putchar('b');
        }else{
            putchar(c);
        }
    }
Ichinomiya answered 21/3, 2018 at 5:2 Comment(1)
The book also said that using 'A' instead of 65 is better and more useful for programmer reading the code.Upsweep

© 2022 - 2024 — McMap. All rights reserved.