We’ll be getting our hands dirty with programming very soon (or so to speak) and one common thing we’ll need to do in pretty much every program that we write is to interact with the user via input and output. Input is the data that user will provide and after processing we need to dump the output for the user to see. Input and output (together called I/O operations) is mostly done from two sources:

1. Console (screen, in layman’s term)
2. File

Console is the most widely used source via which I/O operations are performed. So, in this tutorial I’m going to discuss console I/O operations. File I/O operations will be discussed later down the lane.

Console output functions

There are many functions for displaying content on the standard output (i.e., screen) but none work with as much versatality as printf() function. So, printf() is being discussed with great detail. Most of the time you’ll be using printf() only, since it can output any type of data. Other output functions are mostly concerned with character and string type data.

The printf() function

Pretty much all the time we are going to need to print the output of our program to the screen (called console or standard output). So it seems pretty obvious that it is better to know about it first. One very important way of doing that is via the printf function (there are other ways too). Let’s have a detailed look at the printf() function.

C does all its input and output operations using library functions. Library functions are ready-made functions available for us to use and they are declared in the header files. They come packed with the C compiler. Remember that header file we used? The one called stdio.h? Well, I have previously mentioned it but I would like to tell this once again that the function printf() (and also many other functions) is defined in that header file. That is why we include that header file so that the compiler knows what to do when it encounters the printf function. Though it is unnecessary, I’ll nevertheless say it that whenever we want to use the printf() function, we need to include the stdio.h header file.

An analogy will perhaps clear things up a bit. You know many English words but there are words that you don’t know. So what do you do when you encounter a word that you don’t know? You consult a dictionary or google it up, right? Well, the compiler is just like you. It knows some things on its own (like how to do mathematical operations) and there are things that it does not know. So, where does it look for? You have to tell it where to look for things that it does not know by including the proper header file(s). Hope this helps to understand the whole idea behind inclusion of header files.

The printf() function has a general format, which can be written as:

    printf("<format string>", <list of variables>);

The format string is what the printf() will print. It contains the formatted string. What do I mean by formatted string? Consider that printf() knows its job very well. It will print whatever you tell it to. For example, if you write printf (“Hello World”), it will print ‘Hello World’ as it is. But how to tell it to print the values of variables? I have already said that printf() knows its job very well. We have to write placeholders in the format string, which are called format specifiers and pass the actual variables following a comma after the format string (as can be seen from the form of the printf() statement). In the actual output, the placeholders are replaced by the values of the actual variables.

The format specifiers come defined with the printf function. Following is the list of format specifiers, arranged according to the order of their probable usage.

Format Specifier Output Supported Data Type(s)
%d or %i Signed integer short
int
%ld or %li Long signed integer long
%c Character char
unsigned char
%f Float float
%lf Double double
%s String char *
%u Unsigned integer unsigned short
unsigned int
%lu Long unsigned integer unsigned long
%Lf Long double long double
%e or %E Scientific notation of floating point numbers float
double
%g or %G Uses the shorter of %e/%E or %f float
double
%o Signed octal integers short
unsigned short
int
unsigned int
long
%x or %X Signed hexa-decimal integers short
unsigned short
int
unsigned int
long
%p Pointer address void *
%n Nothing
%% The % character

Having learnt about format specifiers, I would like to tell that there is some more formatting that can be done, but we’ll get into that later. The thing that is important to know is that anything written apart from the formatting that we do and also escape sequences (remember it?), will be printed as it is. For example, if we write printf(“There are %d cows\nHere I am!”, 23), we get the following output:

There are 23 cows
Here I am!

See that apart from %d and \n, everything else has been printed as it is. Now let’s look at some of the properties of printf() function.

  • What happens when the number of variables supplied do not match the number of format specifiers? To answer this let me tell you that C is like that lenient parent who only warns you when you are about to do something wrong, but does not scold you or stop you from doing that anyway. When you do not pass the required number of variables, C only gives you a warning but the program runs nonetheless.

    When the number of variables passed is more than the number of format specifiers written, the extra variables are not printed predictably. But when the number of variables passed is less than that of format specifiers written, some garbage value (any random value) is printed in place of those extra format specifiers. Easy enough?

  • What happens when the format of the variables supplied do not match those of the format specifiers? Let me tell you that you never wanna do this. This behaviour is compiler-dependent and is unpredictable. So, it is better to just supply the correct format specifiers to match the variables unless you want the program to behave differently than you wrote it to (and I don’t know why anyone would want to do that!).

  • printf() can not only print values of variables, it can also print the result of an expression. An example of a valid expression will be (32+5) and thus printf (“%d”, 32+5) is totally perfect and it will print the value 11 (you know why!).

  • Not only can we print expressions using printf(), but also we can initialize variables within printf() although declaration within printf() is not valid. For example, int a; printf(“%d”, a=2); is totally valid but printf(“%d”, int a=2) is not.

  • Onto some more formatting with printf() now! While printing floating-point numbers, we can limit the number of decimal places to be printed. For that we just need to write %.nf as the format specifier where n represents the number of digits after the decimal places. For example, printf (“%.3f”, 12.36485) will give output 12.365. Notice that the last digit has been rounded up. Also, if you specify more number of decimal places to be printed than the precision supported by that data type for your compiler, the extra digits will be printed as 0.

  • Finally one interesting property that I learnt while I was doing the “research” for this tutorial is that even printf() has a return value. It returns the number of characters it has printed on successful completion of the task, otherwise a negative number is returned. For example, printf(“%d”, printf (“5”)); will output 51. This is because within the outer printf() we want to print an integer and its value is determined by printf(“5”) which means printf(“5”) is being replaced by some integer. That integer is what the printf() returns.

    If it is getting complicated, let me simplify. Let us suppose the main() function has asked printf() to do its job (i.e., print something) and like a good boy printf() does its job and reports to main like “Sir, I have completed my job and I have printed some n number of characters” so that main knows exactly how many characters printf() has printed. In our case, the inner printf() is called by the outer printf(), so it reports to the outer printf() after doing its job (which is printing 5). After printing 5, it reports 1 to the outer printf() (since 5 is only 1 character). Now the outer printf() has its integer value as 1. So it prints 1 and reports that value to main(). Hence, we get the output 51 (5 for the inner printf() and 1 for the outer one).

All the properties seen for printf() have been illustrated in the following program.

#include <stdio.h>

int main () {

    // When number of format specifiers do not match the number of arguments passed
    printf("%d %d\n", 1, 2, 3);
    printf("%d %d\n", 1);

    // When format of format specifiers do not match the format of arguments passed
    printf("%f\n", 12);
    printf("%d\n", 12.6);

    // We can initialise variables but we can't declare them in printf()
    int a = 2, c;
    printf("%d %d\n", a += 2, c = 5);

    // Some formatting with floating point numbers
    printf("%.5f\n", (float)22/7);
    printf("%.30f\n", (float)22/7);

    // printf() has a return value
    printf("%d\n", printf ("There are 24 characters\n"));

    return 0;
}

The output of the above program will look something like this.

1 2
1 1216722816
0.000000
1
4 5
3 2 3 3
3.14286
3.142857074737548828125000000000
There are 24 characters
24

Some of the numbers may vary because of the compiler-dependent nature of some the output, but you will have a similar output.

The putc() function

The C library function putc() writes a character (an unsigned char) to the specified stream and advances the position indicator for the stream. It is declared as follows:

int putc(int char, FILE *stream)

To simplify things – The stream can be stdout (the standard output) or any file pointer (When we open a file in C, it is handled by file pointers. Don’t worry, all in good time!). What putc() does is it writes any character you tell it to write to wherever you tell it to write to and after writing it also advances the cursor position such that the next character is written after it and not overwritten. Seems trivial, but it’s important.

The return value of this function is the character written as an unsigned char cast to an int. For example, putc('5', stdout); will output 5 to the screen and return 53 (integer value of ‘5’, remember?).

The putchar() function

The C library function putchar() writes a character (an unsigned char) specified by its sole argument to stdout. It is equivalent to putc(), with the second argument as stdout. It has been declared as follows:

int putchar(int char)

The return value is also same as that of putc().

Console input functions

Well, though printing the output of our program is the most needed thing in all our programs, yet there’s one more thing that we’ll need to do in most of our programs and that is taking user input. One way of doing that is the library function scanf(). Let’s see what scanf() has to offer.

The scanf() function

It is the counterpart of printf(). The scanf() function is used to read formatted input from the stdin or standard input, i.e., input expected from the keyboard. The format of scanf is as given below.

scanf("<input format>", <matching variables with preceding &>);

The input format contains one or more of these three: whitespace characters, non-whitespace characters and format specifiers. We know about format specifiers. We do not usually need non-whitespace characters. We need whitespace characters (space, horizontal tab or newline) when there are more than one items to be taken as input. We have to separate more than one arguments by putting whitespace characters in-between and the same whitespace characters should be present while entering the input. We can also separate it by some non-whitespace character like comma. This separator is often called delimiter. For example, if we write scanf (“%d %d”, &a, &b) in our program, then the input for the two numbers should be like “32 23” (notice how they are space separated as in the input format.

See the & sign before all the variables we pass to the scanf function other than the input format string? & (ampersand) is the ‘address of’ operator i.e., it gives the memory location of the variable we use it on. We need to pass the address of the variables to scanf(). Time for an analogy! Let’s say you have to go to some place which is called by multiple names. You’ll need an address to reach that particular place. scanf() also requires the address of the variables to store the value into. So, it is mandatory to use the & operator before the variable names.

Do not use wrong format specifiers with scanf() as it is undefined behaviour and since we are dealing with memory locations here, there may be catastrophic consequences (I mean your program may crash). Also it is not a good idea to mismatch the number of format specifiers and the number of variables.

Like printf(), scanf() also has a return value. If successful, the total number of items written is returned, otherwise a negative number is returned. There is a difference between the return values of printf() and scanf(). printf(“%d”, 23) will return 2 as two characters 2 and 3 are printed whereas scanf (“%d”, &a) [here, a is some integer variable which has been previously defined] returns 1 on entering the same value 23. This is because scanf returns the number of items written which is only 1 integer, 23, in this case.

A program demonstrating the difference in the return value of scanf() and printf() is given below.

#include <stdio.h>

int main () {
	int a, s, p;
	s = scanf("%d", &a);
	p = printf("%d", a);
	printf("\nReturn value of scanf = %d", s);
	printf("\nReturn value of printf = %d\n", p);
	return 0;
}

The output of the above program will be as follows.

23
23
Return value of scanf : 1
Return value of printf: 2

Note that the first line is the input to scanf(), the return value of which is printed on the third line and the second line is the output of printf(), the return value of which we are printing on the fourth line. Using the same value 23, we get return value of 1 from scanf() but 2 from printf() since 23 is only one item (integer) to scanf() where it is 2 characters to printf() (2 and 3).

The getc() function

The C library function getc() gets the next character (an unsigned char) from the specified stream (can be stdin or file pointer) and advances the position indicator for the stream. The declaration of the function is as follows:

int getc(FILE *stream)

This function returns the character read as an unsigned char cast to an int. The following program demonstrates the usage of getc() function;

#include <stdio.h>

int main() {
	int i;
	char c;
	i = getc(stdin);
	c = (char)i;
	printf("%d %c\n", i, c);
	return 0;
}

The output of the program will be “5 53”, guess why!

The getc() function waits till you hit the Return key and picks the first character from the stream, while advancing the cursor to the next position. If there is a character in the input buffer (buffer is the place where data is stored temporarily), the function doesn’t wait for Return key, it rather picks the first character from the buffer (Try to do this on your own to grasp what the hell I am talking about!).

The getchar() function

Like its counterpart, the getchar() function is also similar to to getc() with stdin as its argument.Following is the declaration for getchar() function.

int getchar(void)

It functions in a similar way to getc(). So, I’ll leave it to you to play with this function.

We have now learnt a lot about the input and output functions, rather console input and output functions specifically. There are other input and output functions, but most of the time you’ll be finding yourself fiddling with printf() and scanf() only. For the time being, the functions discussed above should be enough. Other input and output functions will be discussed as and when required.

We will continue our journey forward with Decision Control Instructions next. And with this, we are now in the domain of programming and this is the most fun part. So, keep reading and stay tuned! Don’t forget to solve the Basic Input and Output problems in the Practice section after completing this tutorial.