HOWTO · C

For Each Loop in C

Explore the capabilities of the C programming language regarding the foreach loop. This article discusses C's lack of a built-in foreach loop and presents alternative methods for iterating over collections, including for loops, while loops, and custom functions. Gain insights into effective looping techniques that can enhance your C programming skills.

On this page

C has no built-in for-each loop that automatically visits every item in a collection. You can get the same style of iteration with a regular for or while loop, but your code must know where the collection ends. For an array, keep its element count; for a linked list, follow each node’s next pointer until it is null.

Does C have a built-in foreach loop?

No. The C language does not provide a dedicated foreach construct like those in Python or JavaScript. A for-each style loop is still easy to write when the collection and its bounds are clear. With an array, an index loop is a common choice. With a linked list, advance a pointer from node to node.

The key difference from many higher-level languages is that C does not attach a length to an array pointer. Pass the length alongside the pointer when a function needs to process an array. This makes the stopping condition explicit and avoids reading beyond the elements that belong to the collection.

Iterate over an array with a for loop

For an array declared in the same scope, calculate its element count with sizeof array / sizeof array[0]. Then use an index from zero up to, but not including, that count.

The following self-contained program prints each element in order. The length expression is valid here because numbers is still an array in main.

#include <stddef.h>
#include <stdio.h>

int main(void) {
    int numbers[] = {10, 20, 30, 40, 50};
    size_t length = sizeof numbers / sizeof numbers[0];

    for (size_t i = 0; i < length; ++i) {
        printf("%d\n", numbers[i]);
    }

    return 0;
}
10
20
30
40
50

When an array is passed to a function, its parameter is a pointer to the first element; the array size is not carried with it. Consequently, sizeof applied to that parameter gives the pointer size, not the original array’s byte size. Pass a separate element count, such as size_t length, and loop while i < length. The caller can calculate the count before passing the array. For a dynamically allocated array, retain the count from the allocation or from the data structure that owns it.

Use a while loop or traverse a linked list

A while loop works just as well when its condition naturally describes whether another item exists. For an array, initialize an index to zero, continue while it is less than the saved length, and increment it once per iteration. The same bound matters as with a for loop.

A linked list uses a different stopping condition: continue while the current node pointer is not null, process that node, then move to current->next. For example, a node can be declared as struct Node { int value; struct Node *next; };; because current is a pointer to a node, access its fields with ->. The list ends when current becomes NULL. Do not use an array’s sizeof formula for a linked list: nodes are separate objects connected by pointers, and the list has no array length. If the list must be counted, traverse it or maintain a count in the owning structure.

When should you wrap iteration in a function or macro?

A function is useful when several parts of a program perform the same operation on each array element. It can accept an element pointer, a size_t count, and an operation to apply. A callback parameter might have the type void (*visit)(int), with the function calling visit(array[i]) for each valid index. Pass the count explicitly: inside the function, the array parameter is a pointer, so its original size cannot be recovered with sizeof.

A function that accepts a callback can also work with different operations, such as printing or accumulating values. Keep the callback type aligned with the element type and decide whether the callback needs additional context; C callbacks can receive that context through a void * parameter.

A macro can make a loop concise, but it performs textual substitution and can evaluate arguments more than once. It can also hide the bounds and types that make iteration safe. If using one, ensure the bound matches the array and avoid passing expressions with side effects. For reusable code, a function with an explicit length is usually easier to inspect, debug, and maintain.