Declaring Multiple Variables in a “for” Loop Initialization Clause
Tags: c, cpp
Published: 2024-03-13 14:54:15

---
title: Declaring Multiple Variables in a “for” Loop Initialization Clause
published: true
description: How to declare multiple variables in a for-loop initialization clause.
tags: #c #cpp
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-03-13 13:34 +0000
---

## Introduction

As you know, the syntax of the `for` statement in C and C++ is:

&nbsp;&nbsp;&nbsp;&nbsp;`for (` _init-clause_ `;` _condition-expr_ `;` _iteration-expr_ `)`

where:

+ _init-clause_ is used to initialize (prepare for) the start of the loop;
+ _condition-expr_ is evaluated before each iteration: if zero, the loop exits;
+ _iteration-expr_ is evaluated after each iteration.

All are optional; if _condition-expr_ is omitted, it’s as if it were `1`, hence:

```c
for (;;) {  // forever
  // ...
}
```

loops forever (presumably to be exited by one of `break`, `return`, `goto`, `exit()`, [`longjmp()`](https://dev.to/pauljlucas/setjmp-longjmp-and-exception-handling-in-c-1h7h), `abort()`, or in C++, `throw`).

> C++ also has [range-based `for` loops](https://en.cppreference.com/w/cpp/language/range-for), but that’s a story for another time.

Originally, the _init-clause_ could be only a statement or expression; starting in [C99](https://en.wikipedia.org/wiki/C99), it could alternatively be a declaration:

```c
for ( unsigned i = 0; i < m; ++i ) {
```

which is nice because it limits the scope of the variable(s) declared to the loop body. Multiple variables may also be declared:

```c
for ( unsigned i = 0, j = 0; i < m && j < n; ++i, ++j ) {
```

> The _iteration-expr_ may use the [comma operator](https://en.cppreference.com/w/c/language/operator_other#Comma_operator) to evaluate more than one sub-expression.  (Actually, _any_ expression may use the comma operator to evaluate more than one sub-expression.)

But what if you want to declare more than one variable where the types are different? You can’t. Instead, you’re forced to declare variables of different types outside the loop:

```c
size_t i = 0;
for ( node_t *p = list->head; p->data; ++i, p = p->next ) {
```

Or so I thought. As I [commented](https://dev.to/pauljlucas/software-career-advice-15d):

> Even in a relatively small language like C, I’m still learning new techniques even though I’ve been using C for over 35 years.

It turns out you _can_ declare more than one variable where the types are different in the _init-clause_.

## The Trick

The trick is to use a local, anonymous `struct`:

```c
for ( struct { size_t i; node_t *p; } loop = { 0, list->head };
      loop.p->data; ++loop.i, loop.p = loop.p->next ) {
```

> Of course, you can name `loop` anything you want; `iter` or `it` are reasonable alternatives.

Granted, it looks weird and it’s somewhat ugly to have to refer to `loop` — but you can do it. One place it’s likely more useful is if the loop is part of a [macro](https://dev.to/pauljlucas/cc-preprocessor-macros-fh5) where the ugliness would be hidden.

But just because you can do it, _should_ you? That’s debatable. After all, it’s not _so_ terrible that variables of different types are declared outside the loop.  It’s a trade-off with how important it is that all the variables are limited to the scope of the loop.  In C, this typically isn’t that important.

In C++, however, if at least one of the loop variables is of a type that has a destructor and it’s important that it runs as soon as the loop terminates, then that might justify the use of the `struct`.  Of course C++ has [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding) that can be used instead:

```cpp
for ( auto [i, p] = std::make_tuple( 0, list->head );
      p->data; ++i, p = p->next ) {
```

## Conclusion

The `struct` trick certainly isn’t that significant, perhaps not even enough to justify the existence of this article. But I do think it’s clever and perhaps even useful in limited cases, so I thought it worth passing on since I’ve never encountered it in over 35 years of programming in C.