Hello! Welcome back.
In our last lesson, we delved into C's primitive data types and the critical concept of portability. You learned that types like int don't have a fixed size, which can lead to bugs, and that <stdint.h> provides a modern solution with fixed-width types.
This lesson builds directly on that foundation. Now that you know how C stores data, we'll learn how to interact with it. We will focus on two of the most fundamental functions in C: printf for displaying formatted output to the console, and its counterpart, scanf, for reading formatted input from the user. Mastering these functions is essential for building interactive command-line programs, which are a cornerstone of systems programming.
By the end of this lesson, you will be able to use printf and scanf to handle formatted console input and output, a skill you'll use in nearly every C program you write.
A Deeper Look at printf: Formatted Output
You've already used printf to display simple text and the results of the sizeof operator. Now, let's explore its full power. The 'f' in printf stands for 'formatted', meaning you can control how your data is displayed.
This is done using format specifiers inside the string argument. A format specifier is a placeholder that begins with % and tells printf to expect an additional argument and how to format it.
Common format specifiers include:
%dor%i: For signed integers (int).%f: For floating-point numbers (float,double).%c: For a single character (char).%s: For a string (which in C is an array of characters).%%: To print a literal%character.
You can also use escape sequences to print special characters that are not visible, like \n for a newline and \t for a tab.
printf Basics | C Programming Tutorial
This video from Portfolio Courses provides a great walkthrough of printf, starting from the basics and moving to more advanced formatting. It will solidify your understanding of format specifiers and escape sequences.
Watch from the beginning to 11:12. The first part (up to 04:27) covers basic text output and common escape sequences. The second part (from 04:15 to 11:12) introduces format specifiers for different data types and demonstrates how to print variables and even the results of expressions.
Controlling Width and Precision
One of the most powerful features of printf is its ability to control the alignment and precision of the output. This is particularly useful for creating tidy, table-like displays, which might feel familiar given your background in data analysis.
- Width: You can specify a minimum width for your output. For example,
%10dwill print an integer in a field that is at least 10 characters wide. By default, it's right-aligned. You can left-align it by adding a minus sign:%-10d. - Precision: For floating-point numbers, you can control the number of digits after the decimal point. For example,
%.2fwill print afloatordoublewith exactly two decimal places.
You can combine these: %10.2f will print a floating-point number in a 10-character wide field with 2 decimal places.
printf Basics | C Programming Tutorial
Let's continue with the same video to see how to use width and precision.
Now, watch from 10:59 to 16:36. This section covers width, left-alignment, and precision for formatting numbers, which is perfect for creating clean, tabular output.
For quick reference, here are some useful resources that summarize format specifiers, escape sequences, and width/precision options.
Formatted Input/Output in C Programming
This article from WsCube Tech provides handy tables that summarize the concepts we've just covered. They can serve as a great cheat sheet.
Skim through the sections titled "Format Specifiers in C", "Width and Precision in Formatted Input/Output in C", and "Escape Sequences in Formatted Output in C". Focus on the tables, which are excellent for quick lookups.
Reading User Input with scanf
Now for the other side of I/O: getting input from the user. The scanf function is the counterpart to printf. It reads data from the console, interprets it according to a format string, and stores the values into variables.
The syntax looks similar to printf, but with one crucial difference: you must pass the memory address of the variables you want to fill. You do this using the address-of operator, &.
int age;
printf("Enter your age: ");
scanf("%d", &age); // Note the &age, not just age
This is a fundamental concept in C that touches on pointers (which we'll cover in the next module). For now, think of it this way:
printfonly needs a copy of the value to display it.scanfneeds to know where the variable lives in memory so it can go to that location and place the new value there. The&operator provides that address.
Input and Output: Printf and Scanf - C Programming Tutorial 06
This video from mycodeschool gives a clear introduction to scanf and provides an excellent conceptual explanation for why the & operator is necessary.
Please watch these three segments: Introduction to scanf (05:28 - 08:21): This introduces the basic syntax for reading an integer. Using Prompts (11:08 - 11:52): This short clip shows the good practice of using printf to prompt the user before a scanf call. Why the Ampersand (&)? (11:52 - 15:35): This is the most important part. It explains the concept of passing an address so that the function can modify the original variable. This is a perfect primer for our upcoming module on pointers.
Common scanf Hazards and How to Avoid Them
Unlike its counterparts in languages like Python or Java, scanf can be tricky and is a common source of bugs for beginners. Understanding its behavior and pitfalls is key to writing robust code.
Hazard 1: The Leftover Newline
When you use scanf("%d", &num) and the user types 42 followed by Enter, scanf reads the 4 and 2, converts them to an integer, and stops. The newline character (\n) from the Enter key is left sitting in the input buffer. If your next I/O call expects to read a character or a line of text, it might read this leftover newline immediately, causing your program to skip ahead unexpectedly.
The Fix: A common trick is to put a space before the %c specifier in the next scanf call (e.g., scanf(" %c", &my_char);). The leading space tells scanf to skip any and all whitespace characters (including newlines) before it reads the actual character.
Hazard 2: Buffer Overflow with %s
When you use scanf("%s", name), it reads characters into the name array until it encounters whitespace. It does not check if there's enough space in the array. If the user types a word that is longer than your array can hold, scanf will happily write past the end of the array, corrupting other parts of your program's memory. This is a classic security vulnerability called a buffer overflow.
The Fix: Always specify a width limit that is one less than your array size to leave room for the null terminator. For example, if you have char name[20];, use scanf("%19s", name);.
Hazard 3: Ignoring the Return Value
scanf returns the number of items it successfully read and assigned. If you expect two inputs (scanf("%d %f", ...)), the return value should be 2. If the user enters invalid data (e.g., "hello" for an integer), the conversion will fail, and the return value will be less than expected. If you don't check this, your program will continue executing with uninitialized or stale data in your variables.
The Fix: Always check the return value of scanf to confirm that the input was valid.
int items_read = scanf("%d", &age);
if (items_read != 1) {
// Handle the error, e.g., print a message and exit
printf("Invalid input. Please enter a number.\n");
return 1; // Exit with an error code
}
Input Handling With scanf and fgets in C
This article provides a professional-level look at these common scanf hazards. It clearly explains the problems and their solutions.
Read the section titled "Common scanf Hazards". It covers the three issues we just discussed: buffer overflows, leftover newlines, and checking the return value. The explanations are concise and the code examples are clear.
Practical Exercise
Let's combine everything you've learned.
- Create a new C file named
user_info.c. - Write a program that asks the user for the following information:
- Their first name (as a single word).
- Their age.
- Their favorite single character.
- Their GPA (as a floating-point number).
- Use
printfto create clear prompts for the user. - Use
scanfto read their inputs. Remember to:- Use the correct format specifiers (
%s,%d,%c,%for%lf). Notice the space before%c! - Use the
&operator correctly for the variables. - Add a width limit to your
%sto prevent buffer overflows (e.g., if you havechar name[50], use"%49s").
- Use the correct format specifiers (
- After reading all the inputs, print a formatted summary message. For example:
--- User Profile ---
Name: John
Age: 25
Favorite Initial: J
GPA: 3.80
Compile and run your program. Try giving it both valid and invalid input (e.g., text for age) to see how it behaves. Try removing the space before %c to see the "leftover newline" problem in action.
Conclusion
In this lesson, we took a comprehensive look at formatted console I/O in C. These functions are simple on the surface but have important nuances related to C's low-level memory model.
Key Takeaways:
printfuses format specifiers (%d,%f, etc.) and escape sequences (\n,\t) to produce formatted output. You can control width and precision for clean, aligned text.scanfreads formatted input and requires the address-of operator (&) to know where in memory to store the data.scanfis powerful but requires careful handling. Always consider potential buffer overflows (with%s), the leftover newline problem (especially before%c), and the importance of checking its return value to validate input.
In our next lesson, we will officially introduce arrays. You'll learn how to declare and manipulate fixed-size lists of data. This will pave the way for a deeper understanding of strings in C, which are simply arrays of characters, and give more context to the scanf buffer overflow issue we discussed today.