C Printf, Scanf, and Branching Logic Fundamentals
1. Formatted Output with printf()
The printf() function delivers formatted text to the standard output stream. The 'f' in its name signifies "format," meaning you can control how the output appears. Crucially, printf() does not append a newline automatically; the cursor remains at the end of the printed content. To move to the next line, include the escape sequence \n explicitly.
This function is declared in the standard header <stdio.h>, which must be included in your source file.
#include <stdio.h>
int main() {
printf("Message one,\n message two");
printf("There are %d participants", 3);
return 0;
}
1.1 Format Specifiers (Placeholders)
Placeholders, marked by a percent sign, are substituted with corresponding argument values. Common specifiers include:
%c: character%dor%i: signed decimal integer%f: float/double floating-point (%lffor double inscanf)%s: null-terminated string%xor%X: hexadecimal integer (lowercase/uppercase)%u: unsigned decimal integer%p: pointer address%%: literal percent sign
For length modifiers: %hd (short), %ld (long), %lld (long long), %zd (size_t). Floating-point variants include %e (scientific notation), %g (shortest representation).
The argument list must align exactly: with n placeholders, provide n additional arguments after the format string. Mismatched counts lead to undefined behavior, potentially printing garbage values from the stack.
int main() {
printf("Inventory: %d %s\n", 4, "widgets");
printf("%s contains %d items\n", "The box"); // Missing argument: prints random value for %d
printf("Char: %c\n", 'Z');
printf("Hex for 255: %x\n", 255);
return 0;
}
1.2 Field Width and Precision
Specify a minimum field width between % and the specifier. By default, output is right-aligned; prepend a minus sign - for left alignment. If the value exceeds the specified width, the full value is printed.
int main() {
printf("[%5d]\n", 42); // [ 42]
printf("[%-5d]\n", 42); // [42 ]
printf("[%5d]\n", 10000); // [10000]
return 0;
}
For floating-point values, the default precision is six decimal places. Control this using .precision, e.g., %.2f rounds to two decimal places. Combine width and precision: %8.2f allocates eight characters total, with two digits after the decimal point. Use %*.*f to take width and precision as integer arguments.
int main() {
double val = 3.14159;
printf("%.2f\n", val); // 3.14
printf("%8.2f\n", val); // 3.14
printf("%*.*f\n", 8, 2, val); // 3.14
return 0;
}
Force a sign indicator with +: %+d prints +12 for positive numbers.
Limit string output with %.Ns: outputs at most N characters.
printf("%.5s", "HelloWorld"); // Hello
2. Formatted Input with scanf()
The scanf() function reads formatted input from stdin and assigns converted values to variables through pointers.
#include <stdio.h>
int main() {
int score;
printf("Enter score: ");
scanf("%d", &score);
printf("Recorded: %d\n", score);
return 0;
}
On Microsoft compilers, scanf may trigger security warnings. Disable them globally by adding #define _CRT_SECURE_NO_WARNINGS at the very top of your source file, or insert this line into the newc++file.cpp template file used by Visual Studio to create new projects.
Inside format strings, whitespace characters in scanf match any amount of whitespace (including none) in the input. The function skips leading whitespace for most specifiers, except %c.
int main() {
int x, y;
float f1, f2;
scanf("%d%d%f%f", &x, &y, &f1, &f2);
printf("%d %d %.2f %.2f\n", x, y, f1, f2);
return 0;
}
2.1 Matching Input Correctly
scanf stops reading a field when encountering a character that cannot belong to the current conversion. For instance, with input -13.45e12#, %d captures 13 (sign consumed, stops at .). A subsequent %f consumes .45e12, stopping at #. Floating-point precision limits can cause rounding artifacts.
Literal characters in the format string (like commas) must be present exactly in the input; otherwise, matching fails and subsequent variables remain uninitialized.
int main() {
int a, b;
// Input expected: 22 , 3
scanf("%d , %d", &a, &b);
printf("a=%d b=%d\n", a, b);
return 0;
}
2.2 Understanding the Return Value
scanf returns the number of successfully matched and assigned items. It returns 0 if the first item fails to match. If end-of-file or a read error occurs before any conversion, it returns EOF (typically -1). Press Ctrl+Z (Windows) or Ctrl+D (Unix) followed by Enter to signal EOF.
int main() {
int age, count;
float weight;
int matched = scanf("%d %d %f", &age, &count, &weight);
printf("Matched: %d\n", matched);
return 0;
}
2.3 Key Format Specifiers
%c: character (reads the next character, including whitespace)%d: integer%f: float%lf: double%Lf: long double%s: word (stops at whitespace; appends null terminator; unsafe without length limit)%[set]: scanset (e.g.,%[0-9]reads only digits)
To skip leading whitespace for %c, place a space before the specifier: scanf(" %c", &ch);
%s reads a single word and is inherently unsafe because it can overflow the destination array. To protect against buffer overflows, specify a maximum field width: %9s reads up to 9 characters and automatically appends the null terminator.
#include <stdio.h>
int main() {
char name[10];
printf("Enter name: ");
scanf("%9s", name); // array decays to pointer
printf("Hello, %s\n", name);
return 0;
}
3. Assignment Suppression
When parsing variable-format input (e.g., dates with different separators), use the assignment suppression character *. Place * immediately after the % sign; the matched input is discarded and not assigned to any variable.
int main() {
int yr, mo, dy;
// Input can be 2025/04/08 or 2025-04-08
scanf("%d%*c%d%*c%d", &yr, &mo, &dy);
printf("%04d-%02d-%02d\n", yr, mo, dy);
return 0;
}
4. Control Flow: Branching with if/else
In C, an expression evaluating to zero is false; any non-zero value (including negative numbers) is true.
#include <stdio.h>
int main() {
if (-5) {
printf("Non-zero, so this executes.\n");
}
return 0;
}
Nested if-else and else-if Chaining
A typical age classification can be written with nested blocks or a flattened else if ladder.
int main() {
int age;
scanf("%d", &age);
if (age < 18)
printf("Adolescent\n");
else if (age <= 44)
printf("Young Adult\n");
else if (age <= 59)
printf("Middle-aged\n");
else if (age <= 89)
printf("Senior\n");
else
printf("Longevity\n");
return 0;
}
Statement Blocks and the Dangling else
Without braces {}, if and else govern only the immediately following statement. Always use braces for clarity, especially when nesting. An else always binds to the nearest unmatched if in the same block, regardless of indentation.
This code prints nothing because the else pairs with the inner if(b==2), and the outer if(a==1) never enters its body.
#include <stdio.h>
int main() {
int a = 0, b = 2;
if (a == 1)
if (b == 2)
printf("Alpha\n");
else
printf("Beta\n");
return 0;
}
Proper use of braces eliminates ambiguity and ensures intended logic.
int main() {
int a = 0, b = 2;
if (a == 1) {
if (b == 2)
printf("Alpha\n");
} else {
printf("Beta\n");
}
return 0;
}