FirstHack Learn
Log in Sign up free
Lessons in this course 0/6 All courses C Programming From Zero

First year

Progress0 / 6 lessons
  1. 1. What a program actually is
  2. 2. Variables, types and exact sizes
  3. 3. Input and output with printf and scanf
  4. 4. Control flow and loops
  5. 5. Functions and how the call stack works
  6. 6. Arrays and strings in C

Courses › C Programming From Zero

Input and output with printf and scanf

Format specifiers, the ampersand rule, and the scanf traps that break lab programs.

10 min read · Lesson 3 of 6 · Free

printf is a template filler

printf takes a string with holes in it and fills the holes with your values. The holes are the % codes.

C
#include <stdio.h>

int main(void)
{
    int roll = 42;
    float marks = 87.5f;
    char grade = 'A';

    printf("Roll %d scored %.2f and got grade %c\n", roll, marks, grade);
    return 0;
}

Output: Roll 42 scored 87.50 and got grade A

The specifiers you will use constantly:

Specifier Use for
%d int
%u unsigned int
%ld long
%lld long long
%f float or double
%.2f float rounded to 2 decimal places
%c single character
%s string (char array)
%p pointer address
%zu size_t, the result of sizeof
⚠️

The specifier must match the type. printf("%d\n", 3.5); does not print 3 or 4 — it prints garbage, because printf reads 4 bytes as an int from a value that was pushed as 8 bytes of double. There is no type checking here at runtime. Compile with -Wall and gcc will catch most of these for you.

Width and alignment for neat tables

C
#include <stdio.h>

int main(void)
{
    printf("%-10s %5s\n", "Name", "Marks");
    printf("%-10s %5d\n", "Adnan", 91);
    printf("%-10s %5d\n", "Priya", 100);
    return 0;
}

%-10s means "string, at least 10 wide, left aligned". %5d means "int, at least 5 wide, right aligned". Your lab record output suddenly looks professional and it costs nothing.

scanf reads from the keyboard

C
#include <stdio.h>

int main(void)
{
    int age;
    printf("Enter your age: ");
    if (scanf("%d", &age) != 1) {
        printf("That was not a number.\n");
        return 1;
    }
    printf("Next year you will be %d\n", age + 1);
    return 0;
}

Two things here matter more than anything else in this lesson.

The &. scanf has to change your variable. To change something, it needs the address of it. &age means "the address of age". Forget the & and you pass the value of age — some random number — and scanf writes to that address. The usual result is a segmentation fault. This is the single most common C mistake in first year.

The return value. scanf returns how many items it successfully read. If the user types hello when you asked for %d, it returns 0 and age is left untouched with garbage in it. Checking the return value is what separates a program that works in the lab from one that works only when the teacher types nicely.

⚠️

Strings are the exception to the & rule. For char name[50]; you write scanf("%49s", name); with no &, because an array name already gives the address of the first element. Also note the 49: without a width limit, a long input overruns your array and corrupts memory.

The newline trap

This is the bug that makes students think their program is "skipping" an input.

C
#include <stdio.h>

int main(void)
{
    int roll;
    char grade;

    printf("Roll: ");
    scanf("%d", &roll);

    printf("Grade: ");
    scanf(" %c", &grade);      /* note the space before %c */

    printf("Roll %d, grade %c\n", roll, grade);
    return 0;
}

When you type 42 and press Enter, scanf("%d", ...) takes the 42 and leaves the Enter key (a \n character) in the input buffer. The next scanf("%c", ...) happily reads that leftover newline as your grade, and the program never waits for you.

The fix is the single space in " %c". A space in a scanf format string means "skip any whitespace here", including leftover newlines. Only %c and %[ need it — %d, %f and %s skip leading whitespace on their own.

scanf %s stops at a space

C
#include <stdio.h>

int main(void)
{
    char name[50];
    printf("Full name: ");
    scanf("%49s", name);
    printf("Hello, %s\n", name);
    return 0;
}

Type Adnan Hassan and this prints Hello, Adnan. %s stops at the first whitespace. To read a whole line including spaces, use fgets:

C
#include <stdio.h>
#include <string.h>

int main(void)
{
    char name[50];
    printf("Full name: ");
    if (fgets(name, sizeof(name), stdin) != NULL) {
        name[strcspn(name, "\n")] = '\0';   /* chop the newline */
        printf("Hello, %s!\n", name);
    }
    return 0;
}

fgets keeps the newline you pressed, so we cut it off. strcspn(name, "\n") returns the position of the first \n, and we overwrite it with the string terminator.

💡

For competitive programming and lab work, pick one style and stay with it. Mixing scanf and fgets in the same program is where leftover-newline bugs breed. If you need lines, use fgets everywhere and parse with sscanf.

Practice

Write a program that reads a student's roll number, name (with spaces), and three subject marks, then prints a neat aligned table with the total and the average to two decimal places. Check every return value. That one exercise covers most of what this lesson taught.