Skip to Content
Course content

16: Input and Output with printf and scanf

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, your programs have mostly been static—you define some variables, do some math, and print a result. But software is useless if it can't talk to the user. In C, printf and scanf are your primary tools for this, but there's a massive gap between using them to pass a homework assignment and using them in a way that won't crash the moment a user hits the wrong key.

The Temptation of the Simple Scan

If you look at most beginner tutorials, they'll show you a very direct way to get data. Let's say we're building a simple user profile tool where we need a name and an age. The naive approach looks something like this:

char name[20];
int age;

printf("Enter your name: ");
scanf("%s", name);
printf("Enter your age: ");
scanf("%d", &age);

On the surface, this is clean. It's readable. If you type "Alice" and "25", it works perfectly. I'll admit, it's tempting to leave it here because it feels intuitive. But in a production environment, this code is a liability. You're essentially trusting the user to be a perfect operator, and in my experience, users are the most unpredictable part of any system.

Where the Naive Approach Breaks

There are two main ways the code above will blow up in your face. First, look at scanf("%s", name). We've allocated 20 bytes for the name. What happens if a user enters a name that is 30 characters long? C doesn't stop them. scanf will happily keep writing data past the end of your array, overwriting other variables or crashing the program with a segmentation fault. This is a classic buffer overflow, and it's exactly how many security vulnerabilities are born.

Then there's the type mismatch. What happens if I ask for your age, and you type "twenty-five" instead of "25"? scanf("%d", &age) will fail to match the integer format. Here is the kicker: it doesn't just fail and move on. The "twenty-five" stays sitting in the input buffer. If you have another scanf call coming up, it will try to read that same "twenty-five" again, fail again, and you'll likely end up in an infinite loop or with garbage data in your variables.

Writing Code That Doesn't Trust the User

To fix this, we need to be defensive. First, we tell scanf exactly how much room we have. By adding a width specifier, we prevent the buffer overflow. Second, we actually check the return value of scanf. Most people ignore this, but scanf returns the number of items successfully matched and assigned. If it returns 0, it means the input didn't match the format you expected.

Here is how I would actually write that profile input logic:

char name[20];
int age;

printf("Enter your name: ");
// Limit input to 19 chars to leave room for the null terminator
scanf("%19s", name); 

printf("Enter your age: ");
if (scanf("%d", &age) != 1) {
    printf("That's not a valid number. I'll assume you're timeless.\n");
    age = 0; 
    // Note: In a real app, you'd want to clear the buffer here
}

By using %19s, we've closed the security hole. By checking if the return value is 1, we've ensured that age actually contains a value provided by the user, rather than whatever random junk happened to be in memory at the time.

The Cost of Safety

Is this more verbose? Yes. Does it require you to think about buffer sizes and return codes? Absolutely. But that's the trade-off of working in C. You don't have a runtime environment catching these errors for you. You are the safety net. When you're writing a quick prototype, the naive way is fine, but the moment your code touches a keyboard or a network socket, you have to assume the input is malicious or mistaken. I'd rather spend an extra ten seconds writing an if statement than spend three hours debugging a random crash in a production build.




📋 Practical Task

Exercise: Robust Budget Tracker Input

Build a small program that asks the user for two pieces of information: a category name (string) and a spending amount (float). Your program must implement the following safety requirements:

  • The category name should be stored in a buffer of 15 characters, and scanf must be restricted to prevent overflows.
  • The program must check if the spending amount was entered as a valid number. If the user enters text instead of a number, the program should print an error message "Invalid amount entered" and set the amount to 0.0.
  • Finally, print a summary like: "Category: [name], Spent: $[amount]".
Rating
0 0

There are no comments for now.

to be the first to leave a comment.