In a singly linked list (SLL), traversal means visiting each node from head until next is NULL. Below: iterative traversal (loop) and recursive traversal to print node values. Time O(n); iterative space O(1), recursive space O(n) for the call stack.
1) Iterative traversal (C)
Use a pointer cur that starts at head and moves with cur = cur->next until cur == NULL.
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
/* Walk the list and print each data value */
void traverse_iterative(struct Node *head)
{
struct Node *cur = head;
while (cur != NULL) {
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
int main(void)
{
struct Node *n1 = malloc(sizeof(struct Node));
struct Node *n2 = malloc(sizeof(struct Node));
struct Node *n3 = malloc(sizeof(struct Node));
if (!n1 || !n2 || !n3) return 1;
n1->data = 10; n1->next = n2;
n2->data = 20; n2->next = n3;
n3->data = 30; n3->next = NULL;
struct Node *head = n1;
traverse_iterative(head); /* output: 10 20 30 */
free(n1); free(n2); free(n3);
return 0;
}
Program output
Running the program prints the three values on one line, then a newline:
10 20 30
Step-by-step execution
Step
cur points to
cur != NULL?
Action
Output
Next cur
Initial
head (node n1)
Yes
Print cur->data
10
cur = n1->next (n2)
2
n2
Yes
Print cur->data
20
cur = n2->next (n3)
3
n3
Yes
Print cur->data
30
cur = n3->next (NULL)
4
NULL
No
Exit loop
(none)
Loop ends
After loop
—
—
printf("\n")
newline
Function returns
Memory layout (example addresses)
Variable
Address (example)
data
next
Points to
n1
0x1000
10
0x2000
n2
n2
0x2000
20
0x3000
n3
n3
0x3000
30
NULL (0x0)
nowhere
Function call trace (iterative loop)
Line executed
cur value
State
struct Node *cur = head;
points to n1
Initialization
while (cur != NULL)
n1 (0x1000)
Condition true
printf("%d ", cur->data);
n1
Prints 10
cur = cur->next;
n2 (0x2000)
Move to next node
while (cur != NULL)
n2 (0x2000)
Condition true
printf("%d ", cur->data);
n2
Prints 20
cur = cur->next;
n3 (0x3000)
Move to next node
while (cur != NULL)
n3 (0x3000)
Condition true
printf("%d ", cur->data);
n3
Prints 30
cur = cur->next;
NULL (0x0)
Move past last node
while (cur != NULL)
NULL
Condition false, exit loop
printf("\n");
—
Prints newline
Key observations
Aspect
Explanation
Order preserved
Output follows insertion order: 10, then 20, then 30.
Spaces between numbers
The format "%d " prints a space after each integer.
Newline
printf("\n") moves the cursor to the next line after the loop.
List unchanged
Traversal only reads nodes; cur is temporary and does not modify the list.
Critical points
What
Why
Check allocations
if (!n1 || !n2 || !n3) return 1; avoids using failed malloc results.
Last next == NULL
Acts as the sentinel so the loop stops after the last node.
free() every node
Releases heap memory and prevents leaks (here, three free calls).
No use-after-free here
Traversal finishes before free; do not dereference nodes after freeing.
In short, the program prints the three data values 10, 20, and 30 on one line with spaces between them, then ends the line with a newline.
2) Recursive traversal — display SLL values (C)
Base case: empty list (p == NULL). Otherwise print current node, then recurse on p->next. This prints in forward order (same as the loop above).
The recursive program prints the same line as the iterative version, then a newline from main:
10 20 30
Recursive function call stack
Call #
p points to
p == NULL?
Action
Output
Next action
1
n1 (data = 10)
No
printfp->data
10
Call display_recursive(n1->next)
2
n2 (data = 20)
No
printfp->data
20
Call display_recursive(n2->next)
3
n3 (data = 30)
No
printfp->data
30
Call display_recursive(n3->next)
4
NULL
Yes
return; (base case)
(none)
Unwind to caller of call #3
Complete call stack trace (with recursion depth)
Step
Depth
Function / phase
p value
Operation
Accumulated output
1
0
display_recursive(n1)
n1 (0x1000)
Check p != NULL
""
2
0
display_recursive(n1)
n1
Print 10
"10 "
3
1
display_recursive(n2)
n2 (0x2000)
Check p != NULL
"10 "
4
1
display_recursive(n2)
n2
Print 20
"10 20 "
5
2
display_recursive(n3)
n3 (0x3000)
Check p != NULL
"10 20 "
6
2
display_recursive(n3)
n3
Print 30
"10 20 30 "
7
3
display_recursive(NULL)
NULL
Check p == NULL
"10 20 30 "
8
3
display_recursive(NULL)
NULL
return; (no print)
"10 20 30 "
9
2
Return to call on n3
—
Function ends
"10 20 30 "
10
1
Return to call on n2
—
Function ends
"10 20 30 "
11
0
Return to call on n1
—
Function ends
"10 20 30 "
12
—
printf("\n") in main
—
Print newline
line ends
Memory layout (same list as iterative example)
Node
Address
data
next
Points to
n1
0x1000
10
0x2000
n2
n2
0x2000
20
0x3000
n3
n3
0x3000
30
NULL (0x0)
nowhere
Visual call tree
Recursive calls: print then display_recursive(p->next) until base case.Activation records on the call stack as recursion deepens (conceptual).
Timing: when prints happen
Phase
t1
t2
t3
t4
t5
Call stack (concept)
disp(n1)
disp(n1)→disp(n2)
…disp(n3)
…disp(NULL)
Unwinding returns
Action
Print 10
Print 20
Print 30
Base case: no print
Return through levels
Output so far
10
10 20
10 20 30
10 20 30
10 20 30
Recursive vs iterative
Aspect
Recursive (display_recursive)
Iterative (traverse_iterative)
Extra memory
O(n) call stack (here, 3 frames deep)
O(1) (one cur pointer)
Risk
Stack overflow if the list is extremely long
No recursion stack growth
Style
Compact, matches recursive definitions
Straightforward loop
Output order
Forward: 10 → 20 → 30
Forward: 10 → 20 → 30
Stop condition
if (p == NULL) return;
while (cur != NULL)
When it prints
Before each recursive call (pre-order walk)
Each loop iteration
Key observations (recursive)
Point
Explanation
Print before recurse
Prints the current node, then visits p->next (pre-order style for this print function).
Base case
When p == NULL, return without printing—stops deeper calls.
Same line as iterative
Both approaches emit 10 20 30 for this list.
Newline in main
printf("\n") after display_recursive(n1) finishes adds the line break.
void is enough
No return value is needed because the function only prints.
Important: Recursion is fine for small lists (like three nodes). For very large lists, deep recursion can exhaust the call stack; the iterative version is usually safer when the length is unknown or huge.
Reverse-order display (without reversing the list) swaps the two lines inside display_recursive: recurse first, then printf—that is covered in the reverse-traversal topic.
3) FAQ: Is void valid when the function uses return?
Is void valid here when I have a return keyword in the function?
Answer: Yes, void is correct here. This is a typical recursive routine that walks the list and prints each node’s data without returning a value to the caller.
Why void fits
The function does work, not a computed result. It prints (a side effect). It does not need to return a value. Recursive calls drive the walk, not an accumulated return value.
The base case uses bare return; (not returnexpression). That simply exits the function and returns nothing—which matches a void return type:
if (p == NULL)
return; /* exit; no value */
If you used a non-void type (e.g. int)
You could write something like this, but it is awkward and misleading for “print only”:
int display_recursive(struct Node *p) /* misleading for this job */
{
if (p == NULL)
return 0;
printf("%d ", p->data);
return display_recursive(p->next);
}
The return value is not needed for printing.
Callers may wrongly assume they should use the returned int.
It adds complexity without benefit for this pattern.