2

I am writing a program that copies input to output character by character on Linux terminal. The code is as follows (from Dennis Ritchie's C book)

#include <stdio.h>
/* copy input to output; 2nd version*/

main()
{
   int c;
   while ((c = getchar()) != EOF)
      putchar(c);
}

The program and its execution works fine. But I want a slight modification.

The output appears on terminal for each new line character (when I press enter). I want to delay the output till I signal the end of file by pressing Ctrl + D. What modifications I have to do for the program in-order to delay my output on terminal.

Sample output I am getting is as follows:

abcd (enter)
abcd
llefn;elnf(enter)
llefn;elnf
(ctrl+d)

Sample output I wants to get is as follows:

abcd(enter)
llefn;elnf(ctrl+d)
abcd
llefn;elnf
chqrlie
  • 131,814
  • 10
  • 121
  • 189
hanugm
  • 1,127
  • 3
  • 13
  • 44
  • 2
    Put the characters into a buffer and display the whole buffer and the end. There are no other options AFAIK – Jabberwocky Aug 09 '17 at 12:54
  • 1
    A fix that doesn't require changing the program is to write your input to a text file and then redirect that to your program as input, e.g. `a.out < input.txt`. That has the advantage that you don't have to retype the input when you test your program. – M Oehm Aug 09 '17 at 12:55
  • @MOehm Yeah, it is working fine without any extra space, but is it possible to do stuff using terminal itself? – hanugm Aug 09 '17 at 12:58
  • 2
    This has to do with buffering. Check this: https://stackoverflow.com/q/1798511/1254880 – Tarc Aug 09 '17 at 13:01

4 Answers4

2

You need to store these character's to buffer, control indexes where are you writing and when you receive EOF just print that buffer via printf.

If you cant solve it you can inspire here

#include <stdio.h>

#define BUFFER_SIZE 1024

int main()
{
    int c, i = 0;
    char buffer[BUFFER_SIZE];

    while ((c = getchar()) != EOF)
    {
        if (i < BUFFER_SIZE - 1)
        {
            buffer[i] = c;
            i++;
        }
        else
        {
            buffer[BUFFER_SIZE - 1] = '\0';
            printf("%s", buffer);
            i = 0;
        }
    }

    buffer[i] = '\0';
    printf("%s", buffer);

    return 0;
}
kocica
  • 6,412
  • 2
  • 14
  • 35
2

An easy, albeit sloppy and partial solution is to configure stdout to fully buffered with a large buffer:

#include <stdio.h>

int main(void) {
    int c;

    setvbuf(stdout, NULL, _IOFBF, 32767);
    while ((c = getchar()) != EOF) {
        putchar(c);
    }
    return 0;
}

Notes:

  • On a 32- or 64-bit system, you could make the buffer ridiculously large.
  • Passing NULL to setvbuf lets it allocate the buffer with malloc().
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • You can start with a big `size_t` value and divide by 2 until it is successful :D – Antti Haapala -- Слава Україні Aug 09 '17 at 13:10
  • @AnttiHaapala: yes, I could write `for (size_t size = ~(size_t)0 >> 1; size; size >>= 1) { if (!setvbuf(stdout, NULL, _IOFBF, size) break; }` but that would be too cryptic for the OP's skill level. – chqrlie Aug 09 '17 at 13:14
  • What about if you dont know how big buffer you need but need program to be efficient ? Allocating amount of bytes doesnt sound very efficient. :-) – kocica Aug 09 '17 at 13:57
  • Buffering the output is just a quick fix that does not provide a full solution to the OP's problem. Since it is unlikely he/she would input more than 32K bytes by hand in the terminal, it fits the purpose, but a complete solution would require allocating and reallocating a buffer as input keeps coming and potentially using a temporary file on disk if input exceeds available memory... – chqrlie Aug 09 '17 at 14:03
1

As already mentioned in the comments: put the characters into a buffer and display the whole buffer at the end:

 #include <stdio.h>

 #define BUF_SIZE 1024

 int main()
 {
      char str[BUF_SIZE]; // the buffer
      int c, i = 0;

      while (i < BUF_SIZE-1 && (c = getchar()) != EOF)
         str[i++] = (char) c;

      str[i] = '\0';

      printf("%s\n", str); // display the contents of the buffer
 }
JFMR
  • 23,265
  • 4
  • 52
  • 76
1

You could set buffer to stdout with setvbuf(3).

#include <stdio.h>
main()
{
        int c;
        char buf[BUFSIZ];
        setvbuf(stdout,buf,_IOFBF,BUFSIZ);
        while ((c=getchar())!=EOF)
                putchar(c);
}

The key here is the fully buffered mode specified with the _IOFBF constant. The size of the buffer is set to BUFSIZ which usually equals 8192.

As was correctly pointed in the comments by Jonathan Leffler the limited size of the buffer may cause the program to suddenly spit out its contents garbling the terminal. To avoid that one could track the utilization of the buffer and extend its size when it gets filled.

Dima Chubarov
  • 16,199
  • 6
  • 40
  • 76
  • 1
    That's okay if the file is smaller than the buffer size. Files are sometimes big. – Jonathan Leffler Aug 09 '17 at 13:09
  • 1
    I guess the world may have changed. Classically, `BUFSIZ` was usually 512. Even 8192 isn't all that big, though it's much bigger than I tend to think of. – Jonathan Leffler Aug 09 '17 at 13:18
  • @JonathanLeffler since 1996 BUFSIZ in GNU/linux is 8192. Should be enough for interactive input from the terminal in most cases. I agree, to correctly implement the spec, we need to grow the buffer dynamically. – Dima Chubarov Aug 09 '17 at 13:29
  • 1
    Note: per C11 "`BUFSIZ` shall be at least 256". Smaller values occur these days in many an embedded processor. – chux - Reinstate Monica Aug 09 '17 at 17:20