I SEMESTER · C PROGRAMMING · UNIT 02
Read input.
Control the flow.
Work with values. Make decisions.
Understand every iteration.
UNIT 02 · 01
Tell C what to read. Choose how to display it.
printf() writes formatted output to standard output. scanf() converts input from standard input and stores it in objects. Both are declared in <stdio.h>. Their first argument is a format string (also called a control string): ordinary characters plus conversion specifications beginning with %.
printf("Roll: %d, marks: %.2f\n", roll, marks);
scanf("%d %lf", &roll, &marks);In printf, pass values. In scanf, pass addresses of objects with the correct types. The & operator supplies an address; a character array already converts to a pointer to its first element. A mismatched conversion and argument can cause undefined behaviour.
| Conversion | printf argument / effect | scanf destination |
|---|---|---|
%d | int, signed decimal | int * |
%u | unsigned int, unsigned decimal | unsigned int * |
%f | double, fixed-point display | float * |
%lf | Use %f for double in the C90 examples here | double * |
%c | int containing a character | char * |
%s | Pointer to a null-terminated character sequence | char array with enough space; stops at whitespace |
%% | Print one literal %; consumes no argument | Match a literal %; makes no assignment |
Width, precision and successful input
%6duses a minimum width of six characters;%06dpads with zeros. Width does not cut off a longer result.%.2fdisplays two digits after the decimal point.%8.2fcombines width and precision;%-8.2faligns left.scanfreturns the number of successful assignments. Check it before using the variables:if (scanf("%d %lf", &roll, &marks) != 2).- For
char name[20], usescanf("%19s", name)to leave room for the final null character. This reads one word, not a full name with spaces. - Most conversions skip leading whitespace.
%cdoes not. Use" %c"to skip whitespace before reading a non-whitespace character. - Whitespace in a scanf format matches any amount of input whitespace. A trailing
\ncan keep interactive input waiting for another non-whitespace character; it is not a command to read exactly one newline.
EXPLORE THE CONCEPT
See the padding and precision
42
An integer without extra padding.
Dots in this demonstration represent spaces so you can see the field width.
#include <stdio.h>
int main(void)
{
int roll;
double marks;
if (scanf("%d %lf", &roll, &marks) != 2) {
puts("Enter a roll number and marks.");
return 1;
}
printf("Roll: %03d\n", roll);
printf("Marks: %.2f\n", marks);
printf("Completion: 100%%\n");
return 0;
}
Roll: 007
Marks: 85.50
Completion: 100%
#include <stdio.h>
int main(void)
{
int count;
char code;
if (scanf("%d", &count) != 1 || scanf(" %c", &code) != 1) {
puts("Enter a count and a character.");
return 1;
}
/* The space before %c skips whitespace, including newline. */
printf("Count = %d\nCode = %c\n", count, code);
return 0;
}
Count = 4
Code = A
Escape sequences
An escape sequence represents a character within a string or character constant. It is interpreted by C before the library handles the string. %% is a printf conversion, not a backslash escape.
| Sequence | Meaning |
|---|---|
\n | Newline |
\t | Horizontal tab; display depends on tab stops |
\b | Backspace; terminal behaviour varies |
\r | Carriage return; terminal behaviour varies |
\\ | Backslash |
\" | Double quote |
\' | Single quote |
\0 | Null character, value zero; ends a C string, not a printed digit 0 |
UNIT 02 · 02
One character. One line.
“Unformatted” I/O transfers characters or strings without conversion specifications. These functions also belong to <stdio.h>.
| Function | What it does | Remember |
|---|---|---|
getchar() | Reads the next character from stdin | Returns int: a character value or EOF. Store it in int before testing EOF. |
putchar(ch) | Writes one character to stdout | Returns the written character as int, or EOF on failure. |
puts(text) | Writes a string to stdout | Adds a newline; does not print the terminating null character. |
gets(buffer) | Legacy input of a line, without its newline | Has no buffer-size argument. It cannot prevent overflow and was removed from C11. |
fgets(buffer, size, stdin) | Reads at most size − 1 characters and appends a null character on success | May retain the newline. A long line can remain partly unread; NULL indicates failure/end before any characters. |
Recognize gets() in the syllabus
The historical call is gets(buffer);. Explain its purpose in an exam, then state its lack of bounds checking. For runnable programs use fgets(buffer, sizeof buffer, stdin). Checking its return value is still necessary. Removing the newline is a separate step.
#include <stdio.h>
int main(void)
{
int ch = getchar();
if (ch == EOF) {
puts("No character was supplied.");
return 1;
}
printf("Character: ");
putchar(ch);
putchar('\n');
return 0;
}
Character: A
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[40];
if (fgets(line, sizeof line, stdin) == NULL) {
puts("No line was supplied.");
return 1;
}
/* Remove the newline if fgets stored one. */
line[strcspn(line, "\n")] = '\0';
puts("You typed:");
puts(line);
return 0;
}
You typed:
BCA study desk
UNIT 02 · 03
Calculate a value. Test a condition.
Operators act on operands to produce values. Integer and floating-point operands can produce different results even with the same operator.
| Family | Operators | Example and result |
|---|---|---|
| Arithmetic | + − * / % | 7 / 2 → 3; 7 % 2 → 1; 7.0 / 2 → 3.5 |
| Relational / equality | < <= > >= == != | 8 > 2 → 1; 8 == 2 → 0 |
| Logical | && || ! | (8 > 2) && (2 > 0) → 1 |
Conditions treat zero as false and any nonzero value as true. Relational, equality and logical operators return int values 0 or 1. The remainder operator % requires integer operands. Division or remainder by zero is undefined; signed overflow is also undefined. For integer division, C99 and later truncate toward zero; C90 had implementation-defined rounding when a operand was negative. Our introductory arithmetic example uses nonnegative values.
Short-circuit evaluation
&& evaluates its right operand only if its left operand is true. || evaluates its right operand only if its left operand is false. This allows a guard such as b != 0 && a / b > 2. Bitwise & and | do not provide this guard.
#include <stdio.h>
int main(void)
{
int a, b;
if (scanf("%d %d", &a, &b) != 2 || a < 0 || a > 100 || b < 1 || b > 100) {
puts("Enter a from 0 to 100 and b from 1 to 100.");
return 1;
}
printf("Add = %d\n", a + b);
printf("Subtract = %d\n", a - b);
printf("Multiply = %d\n", a * b);
printf("Integer division = %d\n", a / b);
printf("Remainder = %d\n", a % b);
printf("Floating division = %.2f\n", (double)a / b);
return 0;
}
Add = 9
Subtract = 5
Multiply = 14
Integer division = 3
Remainder = 1
Floating division = 3.50
#include <stdio.h>
int main(void)
{
int a, b;
if (scanf("%d %d", &a, &b) != 2 || a < 0 || a > 100 || b < 0 || b > 100) {
puts("Enter two integers from 0 to 100.");
return 1;
}
printf("a > b: %d\n", a > b);
printf("a == b: %d\n", a == b);
printf("Both positive: %d\n", a > 0 && b > 0);
printf("At least one positive: %d\n", a > 0 || b > 0);
printf("a is zero: %d\n", !a);
/* If b is zero, && skips a / b. */
printf("Safe quotient exceeds 2: %d\n", b != 0 && a / b > 2);
return 0;
}
a > b: 1
a == b: 0
Both positive: 1
At least one positive: 1
a is zero: 0
Safe quotient exceeds 2: 1
UNIT 02 · 04
Change the variable. Track the result.
= stores a value; == compares values. Compound assignment combines an operation and assignment: x += 3 adds three to x. More generally, the left operand of a compound assignment is evaluated once, which matters when it is a complex expression.
| Operator | Simple-variable meaning |
|---|---|
+= -= *= /= %= | Add, subtract, multiply, divide or take remainder, then assign |
&= |= ^= | Apply a bitwise operation, then assign |
<<= >>= | Shift, then assign |
#include <stdio.h>
int main(void)
{
int x = 5;
printf("Start: %d\n", x);
x += 3; printf("After += 3: %d\n", x);
x *= 2; printf("After *= 2: %d\n", x);
x -= 1; printf("After -= 1: %d\n", x);
x /= 3; printf("After /= 3: %d\n", x);
x %= 2; printf("After %%= 2: %d\n", x);
return 0;
}
Start: 5
After += 3: 8
After *= 2: 16
After -= 1: 15
After /= 3: 5
After %= 2: 1
Prefix and postfix
Both ++ and -- change a modifiable operand by one. Prefix produces the updated value; postfix produces the old value and updates the operand. When used as a statement by itself, ++x; and x++; have the same final effect on x.
EXPLORE THE CONCEPT
One update at a time
Postfix produces the old value, then x becomes 6.
#include <stdio.h>
int main(void)
{
int x = 5, value;
value = x++;
printf("Postfix: old = %d, x = %d\n", value, x);
value = ++x;
printf("Prefix: new = %d, x = %d\n", value, x);
value = x--;
printf("Post-decrement: old = %d, x = %d\n", value, x);
value = --x;
printf("Pre-decrement: new = %d, x = %d\n", value, x);
return 0;
}
Postfix: old = 5, x = 6
Prefix: new = 7, x = 7
Post-decrement: old = 7, x = 6
Pre-decrement: new = 5, x = 5
Avoid unsequenced updates
Do not predict a fixed answer for expressions such as i++ + ++i or printf("%d %d", i++, i++). They modify the same scalar object without the required sequencing and have undefined behaviour. Put updates in separate statements when learning or writing clear code.
UNIT 02 · 05
Look at the individual bits.
Bitwise operators work with integer operands. & keeps a bit when both inputs have it; | keeps it when either has it; ^ keeps it when the inputs differ. ~ complements bits, while << and >> shift positions.
EXPLORE THE CONCEPT
Explore the low eight bits
This visualizer displays the low eight bits. C’s unsigned int can be wider than eight bits. Shifts show the full decimal result as well as its low eight bits.
Use unsigned operands for simple bit operations. A shift count must be nonnegative and less than the width of the promoted left operand. Signed left shifts can be undefined; right-shifting a negative signed value is implementation-defined in the C versions covered here. The example masks a complement with 255U to display only the low eight bits.
#include <stdio.h>
int main(void)
{
unsigned int a, b;
if (scanf("%u %u", &a, &b) != 2 || a > 255U || b > 255U) {
puts("Enter two unsigned values from 0 to 255.");
return 1;
}
printf("AND = %u\n", a & b);
printf("OR = %u\n", a | b);
printf("XOR = %u\n", a ^ b);
printf("NOT a (low 8 bits) = %u\n", (~a) & 255U);
printf("Left shift by 1 = %u\n", a << 1);
printf("Right shift by 1 = %u\n", a >> 1);
return 0;
}
AND = 8
OR = 14
XOR = 6
NOT a (low 8 bits) = 243
Left shift by 1 = 24
Right shift by 1 = 6
UNIT 02 · 06
Select, convert and inspect.
The conditional operator has three operands: condition ? value_if_true : value_if_false. It evaluates the condition and only the selected second or third operand. Compatible operand types determine the result type; it is an expression, so its value can be assigned or printed.
#include <stdio.h>
int main(void)
{
int a, b, maximum;
if (scanf("%d %d", &a, &b) != 2) {
puts("Enter two integers.");
return 1;
}
maximum = a > b ? a : b;
printf("Maximum = %d\n", maximum);
return 0;
}
Maximum = 20
| Operator / construct | Purpose | Example |
|---|---|---|
sizeof | Size in bytes; result type is size_t. For ordinary non-VLA operands it does not evaluate the operand. | sizeof x; no universal fixed size for int |
Cast (type) | Explicit type conversion | (double)5 / 2 → 2.5 |
Address & | Address of an object | p = &x |
Indirection * | Access the object pointed to | *p; pointer must be valid |
Comma , | Evaluate left, then right; produce right operand’s value | (x = 6, x + 2) → 8 |
Subscript [] / call () | Array element access / function call | a[0], printf(...) |
Member . / -> | Structure member / member through a structure pointer | student.roll, p->roll (later topics) |
A comma between function arguments or declarations is a separator, not the comma operator. Parentheses around (x = 6, x + 2) group a comma expression. Pointer, array and structure operations will be developed in later units.
#include <stdio.h>
int main(void)
{
int x = 4, y;
int *p = &x;
y = (x = 6, x + 2);
printf("x = %d, y = %d, *p = %d\n", x, y, *p);
printf("Object has storage: %d\n", sizeof x > 0);
printf("Floating division = %.1f\n", (double)5 / 2);
return 0;
}
x = 6, y = 8, *p = 6
Object has storage: 1
Floating division = 2.5
UNIT 02 · 07
Group correctly before you calculate.
Precedence decides how different operators group. Associativity decides grouping when operators share a precedence level. Parentheses explicitly group a subexpression. The table lists C90 operators from higher to lower precedence; context distinguishes unary * from multiplication and unary & from bitwise AND.
| Level | Operators | Associativity |
|---|---|---|
| 1 · highest | () [] . -> postfix ++ -- | Left to right |
| 2 | prefix ++ -- + − ! ~ (type) * & sizeof | Right to left |
| 3 | * / % | Left to right |
| 4 | + − | Left to right |
| 5 | << >> | Left to right |
| 6 | < <= > >= | Left to right |
| 7 | == != | Left to right |
| 8 | & | Left to right |
| 9 | ^ | Left to right |
| 10 | | | Left to right |
| 11 | && | Left to right |
| 12 | || | Left to right |
| 13 | ?: | Right to left |
| 14 | = += -= *= /= %= <<= >>= &= ^= |= | Right to left |
| 15 · lowest | , | Left to right |
2 + 3 * 4 groups as 2 + (3 * 4). 10 - 3 - 2 groups as (10 - 3) - 2. a = b = 7 groups as a = (b = 7), setting both to seven.
Grouping is not execution order
Precedence does not specify which operand is evaluated first. C does not generally guarantee left-to-right evaluation of function arguments or arithmetic operands. Logical AND/OR, the conditional operator and the comma operator provide specific sequencing rules. Use separate statements for side effects.
EXPLORE THE CONCEPT
Walk through an expression
These are guided examples of C expression rules. Use the C playground to compile your own expressions.
UNIT 02 · 08
Choose the next path.
An if executes its body when an expression compares unequal to zero. An if-else selects one of two bodies. An else if ladder tests conditions in order and takes the first true branch. Nest an if inside another branch when a second decision depends on the first.
if (condition) {
/* true branch */
} else {
/* false branch */
}
if (marks >= 80) grade = 'A';
else if (marks >= 60) grade = 'B';
else if (marks >= 40) grade = 'C';
else grade = 'F';Without braces, an else belongs to the nearest unmatched if. Braces make the intended nesting explicit. A semicolon immediately after if (condition); makes its body an empty statement, a common logic error.
EXPLORE THE CONCEPT
Follow the grade ladder
- marks ≥ 80 → A
- otherwise, marks ≥ 60 → B
- otherwise, marks ≥ 40 → C
- otherwise → F
These grade thresholds are illustrative, not an official university grading scheme.
#include <stdio.h>
int main(void)
{
int marks;
char grade;
if (scanf("%d", &marks) != 1 || marks < 0 || marks > 100) {
puts("Enter marks from 0 to 100.");
return 1;
}
/* Illustrative thresholds, not a university grading policy. */
if (marks >= 80) grade = 'A';
else if (marks >= 60) grade = 'B';
else if (marks >= 40) grade = 'C';
else grade = 'F';
printf("Grade = %c\n", grade);
return 0;
}
Grade = B
UNIT 02 · 09
Select a case. Leave or skip a step.
switch evaluates an integer expression and transfers control to a matching case label. Labels use unique integer constant expressions, such as case 1: or case 'A':. A default label handles unmatched values and is optional.
A switch does not automatically stop at the next label. Execution falls through unless a jump such as break or return exits. Cases cannot directly match string values or floating-point values. For ranges, use an if-else ladder.
#include <stdio.h>
int main(void)
{
int choice;
if (scanf("%d", &choice) != 1) {
puts("Enter an integer menu choice.");
return 1;
}
switch (choice) {
case 1: puts("Open the notes"); break;
case 2: puts("Open the lab"); break;
case 3: puts("Open the revision questions"); break;
default: puts("Unknown choice"); break;
}
return 0;
}
Open the lab
| Statement | Effect | Typical use |
|---|---|---|
break; | Exits the innermost enclosing loop or switch | Stop a search or end a case |
continue; | Skips the rest of the current loop iteration | Ignore an unwanted item; in for, the update expression still runs |
goto label; | Jumps to a named label within the same function | A forward error exit in a small example; structured loops are clearer for repetition |
In a while or do-while loop, continue moves to the condition check; ensure the loop’s state still advances. A break inside a switch nested in a loop leaves the switch, not the surrounding loop. A label has the syntax label: and, in C90, must precede a statement.
#include <stdio.h>
int main(void)
{
int i, sum = 0;
printf("Accepted:");
for (i = 1; i <= 7; i++) {
if (i == 3) continue;
if (i > 5) break;
printf(" %d", i);
sum += i;
}
printf("\nSum = %d\n", sum);
return 0;
}
Accepted: 1 2 4 5
Sum = 12
#include <stdio.h>
int main(void)
{
int value;
if (scanf("%d", &value) != 1) goto invalid;
if (value <= 0) goto invalid;
printf("Accepted positive value: %d\n", value);
return 0;
invalid:
puts("A positive integer is required.");
return 1;
}
Accepted positive value: 4
UNIT 02 · 10
Repeat with a clear stopping condition.
| Loop | Syntax | When the condition is tested |
|---|---|---|
| while | while (condition) { body; } | Before each iteration; the body can run zero times |
| do-while | do { body; } while (condition); | After each iteration; the body runs at least once |
| for | for (initialization; condition; update) { body; } | Initialization once, then condition → body → update → condition |
Choose a while when repetition depends on a changing condition, a do-while when one attempt must occur, and a for when initialization, test and update fit naturally together. These are conventions, not restrictions. A for can omit its condition to make it always true; every loop still needs a reachable way to finish when the task requires one.
EXPLORE THE CONCEPT
Trace the same sum with three loops
This trace follows the unguarded loops in the example. Try N = 0: while and for sum to 0; do-while executes once and sums to 1. To implement a mathematical sum for N = 0 with do-while, guard the loop with if (n > 0).
#include <stdio.h>
int main(void)
{
int n, i, sum;
if (scanf("%d", &n) != 1 || n < 0 || n > 10) {
puts("Enter n from 0 to 10.");
return 1;
}
i = 1; sum = 0;
while (i <= n) { sum += i; i++; }
printf("while sum = %d\n", sum);
i = 1; sum = 0;
do { sum += i; i++; } while (i <= n);
printf("do-while sum = %d\n", sum);
sum = 0;
for (i = 1; i <= n; i++) { sum += i; }
printf("for sum = %d\n", sum);
return 0;
}
while sum = 6
do-while sum = 6
for sum = 6
Nested loops
A nested loop places one loop inside another. For each outer iteration, the inner loop starts again when its initialization is reached. A rectangular grid with R rows and C columns visits R × C positions; a triangle with N rows prints 1 + 2 + … + N stars. In the triangle program, row is the outer counter and column is the inner counter.
EXPLORE THE CONCEPT
Build a triangle, one star at a time
Ready to print.
row = 1, column = 1
#include <stdio.h>
int main(void)
{
int rows, row, column;
if (scanf("%d", &rows) != 1 || rows < 1 || rows > 6) {
puts("Enter rows from 1 to 6.");
return 1;
}
for (row = 1; row <= rows; row++) {
for (column = 1; column <= row; column++) {
putchar('*');
}
putchar('\n');
}
return 0;
}
*
**
***
A quick loop checklist
- Initialize every counter and accumulator before reading it.
- Check boundary values: zero iterations, one iteration, and the last iteration.
- Update the state on every repeating path, including paths using continue.
- Use
<versus<=deliberately; dry-run the final counter value. - Do not place an unintended semicolon after a loop header.
UNIT 02 · 11
Edit it. Run it. Explain it.
Choose an example and load it into the embedded C compiler. Select I/O inside the compiler, check the sample STDIN, and press Run. Change the input or edit the source to explore a different case.
Load the compiler when you’re ready to practise.
Your C workspace
Edit real C code and see real compiler output.
Compiler provided by OneCompiler. Opening the editor connects to that service; code and input you run are processed there. If the embed is unavailable, open the C compiler in a new tab and paste the source below.
View / copy the selected source
#include <stdio.h>
int main(void)
{
int roll;
double marks;
if (scanf("%d %lf", &roll, &marks) != 2) {
puts("Enter a roll number and marks.");
return 1;
}
printf("Roll: %03d\n", roll);
printf("Marks: %.2f\n", marks);
printf("Completion: 100%%\n");
return 0;
}
Experiments to try
- Arithmetic: compare inputs
7 2and8 2. Explain the integer quotient and remainder. - Logical: use
8 0. Why does the guarded division remain safe? - Grade: test 39, 40, 59, 60, 79 and 80. Explain each boundary.
- Switch: try choice 9, then remove one break and inspect fall-through.
- Loops: use N = 0 and N = 1. Add a guard to the do-while version and compare.
- Nested loops: change the inner condition from
column <= rowtocolumn <= rowsto print a square.
UNIT 02 · 12
Finish with a self-check.
Written exam practice
- Explain printf and scanf with control strings, field width, precision and suitable examples.
- Describe escape sequences and distinguish formatted and unformatted I/O.
- Explain getchar, putchar, gets and puts; show a bounded replacement for gets.
- Classify C operators and explain integer division, logical short-circuiting and bitwise operations.
- Distinguish prefix and postfix increment with a dry run of separate statements.
- Explain precedence and associativity; evaluate a parenthesized arithmetic expression.
- Write an if-else ladder and a switch program; explain fall-through and break.
- Compare goto, break and continue with their scope and effects.
- Compare while, do-while and for using N = 0 and N = 3 as test cases.
- Write a nested-loop triangle program and trace row and column values.
Build a complete answer
Give the definition, syntax and a small example. State the types and input assumptions. Show the result or dry run, and explain a boundary case. For loops, include initialization, condition, update and the stopping state. For library input, include the destination capacity and return-value check.
UNIT 02 · 13
Read alongside your textbook.
E. Balagurusamy, Programming in ANSI C, Eighth Edition, McGraw Hill Education (India) Private Limited. ISBN 9789353165130.
Use your copy for the chapters on operators and expressions, input/output, decision making and looping. These original notes and programs follow the supplied Unit 2 syllabus; they do not reproduce the book’s chapter text or claim page-by-page correspondence. Runnable examples use portable C90 syntax, with later-standard differences identified where relevant.