A short C program with two or three fork() calls can look as if it will create an unmanageable process forest. The trick is to stop reading it as ordinary sequential code. Track which existing processes reach each call, then duplicate only those processes.
Once that habit is fixed, most fork() questions are counting exercises with one classic off-by-one trap.
What fork() returns in the parent and child
A successful fork() creates one child process by duplicating the calling process. Both processes continue from the statement after the call, but they receive different return values:
In the child,
fork()returns0.In the parent, it returns the positive process ID of the child.
On failure, the parent receives
-1, and no child is created. Exam questions normally tell you to assume all calls succeed.
The parent and child have separate address spaces after the fork. Their variables begin with the same values, but a later assignment in one process does not change the other's copy.
If every existing process executes each of n unconditional sequential forks, the total number of processes is 2^n. The number of new child processes is 2^n - 1, because the original process is included in the total. Keep those two requested quantities separate.
The broader process model and state transitions are revised in Operating Systems for GATE.
Worked example 1: three sequential forks
Consider:
fork();
fork();
fork();Start with one process P0.
The first call is reached by one process. It creates one child, giving
2processes.Both processes reach the second call. Each creates a child, giving
2 x 2 = 4processes.All four reach the third call. Each creates a child, giving
4 x 2 = 8processes.
Therefore, the final total is 8, while the number of newly created processes is 8 - 1 = 7. The shortcut gives the same result: 2^3 = 8 total.
Worked example 2: fork() inside a condition
Now trace a call whose return value controls a branch:
int x = 0;
if (fork() == 0) {
x = 1;
fork();
printf("%d ", x);
} else {
printf("%d ", x);
}Call the first fork F1. Its parent P0 receives a positive value, enters the else branch, and prints 0. Its child C1 receives 0, enters the if branch, and sets its private copy of x to 1.
Only C1 reaches the second fork F2. F2 creates child C2. Both C1 and C2 continue after F2 with their inherited value x = 1, so each prints 1.
The final count is therefore 3 processes: P0, C1, and C2. The output multiset is one 0 and two 1 values. Scheduling is nondeterministic, so the order of those three values is not fixed.

Do not apply 2^2 here. The second fork is reached by only one of the two processes created by F1. A process tree makes that restriction visible.
Worked example 3: fork() in a two-iteration loop
Consider a loop with the print after it:
for (int i = 0; i < 2; i++) {
fork();
}
printf("X\n");At i = 0, one process forks, so there are 2. Each process has its own loop variable and continues to i = 1. Both fork, so there are 4. All four leave the loop and execute printf once.
The program prints 4 lines. The formula confirms it: two unconditional iterations give 2^2 = 4 processes, and each performs one print after the loop.
If the print were inside the loop after the fork, the count would be different. There would be 2 executions in the first iteration and 4 in the second, for 2 + 4 = 6 printed lines. Count the processes that actually reach the print, not just the final leaves.
For more variations on this exact topic, use the process creation question set.
The printf buffer trap
Output already sitting in a user-space buffer is copied into the child at fork(). That can make the eventual output count exceed the number of times the source-level printf appears to execute.
printf("A");
fork();If A remains buffered when the fork occurs, both parent and child inherit a copy of that buffer and may later flush it. The visible result can contain A twice even though printf ran once before the fork.
With terminal output, a newline often flushes a line-buffered stream before the fork. Without a newline, the data is more likely to remain buffered. Redirection can change the buffering mode, so newline versus no newline is a clue, not a universal law independent of context.
The GATE-safe approach is to follow the buffering assumption stated in the question. If none is given and the print occurs after the fork, count one execution per process that reaches it. If the print occurs before the fork, check whether the question says the buffer was flushed. Do not silently mix process count with buffered-output count.
How GATE frames fork() questions
The common forms ask for the total processes, new children, times a line is printed, or a variable's value in a parent or child. Conditions, short-circuit operators, loops, wait(), and nested calls control which processes reach the next fork.
For each statement, keep a small table with process name, fork return path, variable values, and next line. Confirm current syllabus and paper instructions on the official GATE portal of the organising IIT. The GATE CS preparation category provides the wider study route without replacing that official source.
The short version
An unconditional fork doubles only the processes that execute it. Sequential unconditional calls give 2^n total processes and 2^n - 1 new ones. In conditions and loops, draw the tree and count the paths reaching each call or print. Treat inherited buffers as a separate issue.
Once the traces make sense, use the GATE Test Series to practise mixed counting questions under exam conditions. Always write whether your number means total processes, children created, or output lines.




