Skip to main content

Input/Output (I/O)

The terms input and output refer to data that is given to a program and the information that is provided from the program. We often shorten the terms input/output to the acronym I/O. There are many ways that data for a program can be provided to the program.

It can include:

  • Interactive I/O, information provided by the user of the program in real time. Think keystrokes, mouse movements etc.
  • File I/O and databases

In this section of the notes, we will look at interactive I/O. Later in this course we will look at File I/O.

Example of various forms of I/O

Consider the example of video games.

  • When a user plays the game, the buttons they press, the way the swipe across the screen, the mouse clicks they make.. these are all examples of interactive input. It happens in real time and the game reacts to this input and produces scenes based on that input.
  • The art (the 3D models, the sprites, etc) is an example of file input. The game engine reads this information and renders the art onto the screen. For games where a user can save their progress, the state of the game can be stored into a file. This would be an example of file output.
  • Tracking user information is typically a job of a structured database.

printf()

In C, one way to perform output is to use the printf() statment.

We already saw this in the hello world program. The following line prints the words Hello World to the screen.

printf("Hello World!\n");

The printf() function is made available via the stdio.h header file.

When we use printf(), we must provide

  • a format string
  • zero or more values

In this statement:

printf("Hello World!\n");

the format string is:

"Hello World!\n"

The double quotes("") delimit the string.

The easiest way to think about a format string is that it is essentially a fill-in-the-blanks statment. We express what we want to write between the double quotes. In some cases, if we want to output a value, we use a format code that the printf function fills in.

Example:

%d is the format code for base 10 whole numbers. In this expression:

printf("%d + %d = %d\n", 2, 3, 5);

The format string is:

"%d + %d = %d\n"

Each %d is essentially a blank that we will replace with a value... this format string has 3 format codes. The format codes are filled in using subsequent arguments in the same order as the format codes. The following diagram shows how this works in our example

After the format string there are 3 numbers separated by commas. Each of these numbers will be used to fill in each of the 3 format codes respectively. the 2 goes into the first blank, the 3 into the second blank the 5 into the third blank

The table below shows the data types for the 4 major types that we will look at. There are more format codes than this but we are going to focus on these types:

data typeformat code
int%d
char%c
float%f
double%lf
info

All format codes start with %. so if you ever want to print a % symbol in your output because printf/scanf will think you are trying trying to put in a format code. Thus you can't just use %. You need to use %%.

printf("100%%\n");

The above will print:

100%

Format Code Modifiers

Sometimes we wish our output to look a certain way. Take the example of a double that holds the value of pi (to 10 digits). What do you think the output of the following program will be?

#include <stdio.h>
int main(void)
{
double pi = 3.1415926535;
printf("pi = %lf\n", pi);
return 0;
}

If you compile this program you will end up with the following output:

pi = 3.141593

This is because the default number of decimal places is 6. If we want to change this, we can use a .xlf where x is replaced by the number of decimal places we want.

Try making that change to the program:

#include <stdio.h>
int main(void)
{
double pi = 3.1415926535;
printf("pi = %.8lf\n", pi);
return 0;
}

This will now print pi to 8 decimal places:

pi = 3.14159265

Note that this is not a magic function... I can't get more accurate digits beyond what I used to initialize the pi variable... so if I changed it to 12 decimal places, the output would be:

pi = 3.141592653500

which is not the correct value of pi to 12 digits.

Similarly we can use other modifiers to the format code to do things like do left/right justification, show the sign of the value even when its positive, adjust the width of the field, show a value in different bases and so on. Below is a small table showing the result of certain printf() format codes on the following variables. Note that the bars | | are added to output to better show width formatting, the data is placed between the bars without any spacing:

int a = 15;  //15 is F in base 16 (hex), 17 in base 6 (octo)
double pi = 3.1415926535;
format codedescriptionprintf() statementoutput
%lfstandard double outputprintf("|%lf|\n", pi);
|3.141593|
%dstandard integer outputprintf("|%d|\n", a);
|15|
%.2lfdouble output with 2 decimal placesprintf("|%.2lf|\n", pi);
|3.14|
%6.2lfdouble output with field width of 6 and 2 decimal placesprintf("|%6.2lf|\n", pi);
| 3.14|
%+dinteger output where sign is always shownprintf("|%+d|\n", a);
|+15|
%6dinteger output field with 6, padded with spaces (right justified by default)printf("|%6d|\n", a);
| 15|
%-6dinteger output field with 6, padded with spaces but left justifiedprintf("|%-6d|\n", a);
|15 |
%06dinteger output field with 6, padded with 0'sprintf("|%06d|\n", a);
|000015|
%ointeger printed in octo (base 8)printf("|%o|\n", a);
|17|
%xinteger printed in lower case hex (base 16)printf("|%x|\n", a);
|f|
%Xinteger printed in upper case hex (base 16)printf("|%X|\n", a);
|F|

Try it yourself!

Here is a program that uses the above format codes. Try it out for yourself and change up the format codes to see what you get:

#include <stdio.h>
int main(void)
{
int a = 15; //F in hex, 17 in octo
double pi = 3.1415926535;
printf("%%lf\t|%lf|\n", pi);
printf("%%.2lf\t|%.2lf|\n", pi);
printf("%%6.2lf\t|%6.2lf|\n", pi);
printf("%%d\t|%d|\n", a);
printf("%%+d\t|%+d|\n", a);
printf("%%6d\t|%6d|\n", a);
printf("%%-6d\t|%-6d|\n", a);
printf("%%06d\t|%06d|\n", a);
printf("%%o\t|%o|\n", a);
printf("%%x\t|%x|\n", a);
printf("%%X\t|%X|\n", a);
return 0;
}

scanf()

The scanf() function is used to read information from the user. Similar to printf() the first argument for scanf is a format string. This format string states the expected format of the input. if the format is not part of a format code, the function will expect that sequence of characters to be present in the input and ignore those letters. If the input sequence does not match, scanf() will give up and not store the information.

Consider this program:

#include <stdio.h>
int main (void)
{
int first = 0;
int second = 0; //declare two integers
printf("enter input in the form R#D# where the #'s are numbers: ");
scanf("R%dD%d", &first, &second);
printf("first = %d, second = %d\n", first, second);
return 0;
}

If you were to enter input such as R2D2, it will store 2 into first and second. However if you you entered input like C3PO it will not store anything because the C does not match the expected R at the start of the input. If you entered R2P3, it would store 2 into first but second would remain 0 because the P does not match the expected D after the first number.

Modifiers

The modifiers for format codes in scanf are NOT the same as that of printf. For example precision modifiers do not exist for floating point in scanf(). We will look at these format codes in more details later. For now, it is sufficient to simply match the format code with the data type.