Sep 2, 2016

C Programming #86: stdio - getchar, putchar, fgets, puts

C Programming #86: stdio - getchar, putchar, gets, puts

Following article will go through standard input output (stdio) function such as getchar, putchar. There are several others which are covered in subsequent articles.


getchar

/* Reads the next character from standard input and 
   returns it as an unsigned char cast to an int, 
   or EOF on end of file or error. */
int getchar(void);

There are several examples of it already covered in previous articles. Couple of other variation of the above function are

/* It is same as getc but instead of stdio it reads 
   from stream*/
int fgetc(FILE *stream);
/* getc() is equivalent to fgetc() and it is implemented 
   as a macro */
int getc(FILE *stream);
/* pushes c back to stream, cast to unsigned char, 
   where  it  is  available  for  subsequent  read  operations. */
int ungetc(int c, FILE *stream);

Some notes are

  • fgetc(stdin); call is same as getchar()
  • getc is macro which can be re-defined to something more intelligent if the programmer wishes to
  • fgetc and getchar are function with addresses and can be passed to other function as argument.

FILE stream would be covered in future articles, where same function could be used to read from the file.

#include <stdio.h>
int main()
{
   int ch;

   printf("putting 'a' into stdio using ungetc\n");
   ungetc('a', stdin);
   ch = getchar();
   printf("o/p of getchar is %c\n", ch);

   return 0;
}
putting 'a' into stdio using ungetc
o/p of getchar is a

putchar

/* putchar writes the character c, cast to an unsigned char
   to stdout */
int putchar(int c);

Some other variations are

/* Same as putchar but puts it to stream instead */
int fputc(int c, FILE *stream);
/* Same as fputc but is implemented as macro */
int putc(int c, FILE *stream);

Notes

  • fputc('c', stdout) is same as putchar('c')

puts

/* writes the string s and a trailing newline to stdout.*/
int puts(const char *s);
/* fputs() writes the string s to stream, 
   without its terminating null byte ('\0').*/
int fputs(const char *s, FILE *stream);

gets

char *gets(char *s);

If you see the linux man pages of gets it is strongly written as - Never use this function. Reason why it should be used is it can easily cause buffer over-flow. Following is the only place where gets is used, to demo why it is dangerous.

#include <stdio.h>
int main()
{
   char buf[5];
   int i;
   ungetc('\n', stdin);
   ungetc('\0', stdin);
   for(i = 0; i < 100; i++) {
      ungetc('a', stdin);
   }
   gets(buf);
   return 0;
}

stack smashing detected *: ./a.out terminated Aborted (core dumped)

In above program i am purposefully putting 100 'a' into stdin stream using ungetc. buf is just 5 bytes long and when gets is called called it try to put 100 'a' on to buf which can hold just 5 'a' But gets doesnot care and continues writing which will cause stack corruption. That is exactly the run-time error that we got. HENCE NEVER USE gets. Instead of it use the safer version called ~fgets

/* reads in at most one less than size characters 
   from stream and stores them into the buffer pointed 
   to by s. Reading stops after an EOF or a newline.  
   If a newline is read, it is stored into the buffer.  
   A terminating null byte ('\0') is stored after the
    last character in the buffer. */
char *fgets(char *s, int size, FILE *stream);

We could write the above program safely as below

#include <stdio.h>
int main()
{
   char buf[5];
   int i;
   ungetc('\n', stdin);
   ungetc('\0', stdin);
   for(i = 0; i < 100; i++) {
      ungetc('a', stdin);
   }
   fgets(buf, 5, stdin);
   puts(buf);
   return 0;
}

No comments :

Post a Comment