Does C have a "foreach" loop construct?

Almost all languages have a foreach loop or something similar. Does C have one? Can you post some example code?

198785 次浏览

There is no foreach in C.

You can use a for loop to loop through the data but the length needs to be know or the data needs to be terminated by a know value (eg. null).

char* nullTerm;
nullTerm = "Loop through my characters";


for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}

C has 'for' and 'while' keywords. If a foreach statement in a language like C# looks like this ...

foreach (Element element in collection)
{
}

... then the equivalent of this foreach statement in C might be be like:

for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}

C doesn't have a foreach, but macros are frequently used to emulate that:

#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)

And can be used like

for_each_item(i, processes) {
i->wakeup();
}

Iteration over an array is also possible:

#define foreach(item, array) \
for(int keep = 1, \
count = 0,\
size = sizeof (array) / sizeof *(array); \
keep && count != size; \
keep = !keep, count++) \
for(item = (array) + count; keep; keep = !keep)

And can be used like

int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}

Edit: In case you are also interested in C++ solutions, C++ has a native for-each syntax called "range based for"

Here is a full program example of a for-each macro in C99:

#include <stdio.h>


typedef struct list_node list_node;
struct list_node {
list_node *next;
void *data;
};


#define FOR_EACH(item, list) \
for (list_node *(item) = (list); (item); (item) = (item)->next)


int
main(int argc, char *argv[])
{
list_node list[] = {
{ .next = &list[1], .data = "test 1" },
{ .next = &list[2], .data = "test 2" },
{ .next = NULL,     .data = "test 3" }
};


FOR_EACH(item, list)
puts((char *) item->data);


return 0;
}

This is a fairly old question, but I though I should post this. It is a foreach loop for GNU C99.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


#define FOREACH_COMP(INDEX, ARRAY, ARRAY_TYPE, SIZE) \
__extension__ \
({ \
bool ret = 0; \
if (__builtin_types_compatible_p (const char*, ARRAY_TYPE)) \
ret = INDEX < strlen ((const char*)ARRAY); \
else \
ret = INDEX < SIZE; \
ret; \
})


#define FOREACH_ELEM(INDEX, ARRAY, TYPE) \
__extension__ \
({ \
TYPE *tmp_array_ = ARRAY; \
&tmp_array_[INDEX]; \
})


#define FOREACH(VAR, ARRAY) \
for (void *array_ = (void*)(ARRAY); array_; array_ = 0) \
for (size_t i_ = 0; i_ && array_ && FOREACH_COMP (i_, array_, \
__typeof__ (ARRAY), \
sizeof (ARRAY) / sizeof ((ARRAY)[0])); \
i_++) \
for (bool b_ = 1; b_; (b_) ? array_ = 0 : 0, b_ = 0) \
for (VAR = FOREACH_ELEM (i_, array_, __typeof__ ((ARRAY)[0])); b_; b_ = 0)


/* example's */
int
main (int argc, char **argv)
{
int array[10];
/* initialize the array */
int i = 0;
FOREACH (int *x, array)
{
*x = i;
++i;
}


char *str = "hello, world!";
FOREACH (char *c, str)
printf ("%c\n", *c);


return EXIT_SUCCESS;
}

This code has been tested to work with gcc, icc and clang on GNU/Linux.

Eric's answer doesn't work when you're using "break" or "continue".

This can be fixed by rewriting the first line:

Original line (reformatted):

for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)

Fixed:

for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)

If you compare it to Johannes' loop, you'll see that he's actually doing the same, just a bit more complicated and uglier.

Here's a simple one, single for loop:

#define FOREACH(type, array, size) do { \
type it = array[0]; \
for(int i = 0; i < size; i++, it = array[i])
#define ENDFOR  } while(0);


int array[] = { 1, 2, 3, 4, 5 };


FOREACH(int, array, 5)
{
printf("element: %d. index: %d\n", it, i);
}
ENDFOR

Gives you access to the index should you want it (i) and the current item we're iterating over (it). Note you might have naming issues when nesting loops, you can make the item and index names be parameters to the macro.

Edit: Here's a modified version of the accepted answer foreach. Lets you specify the start index, the size so that it works on decayed arrays (pointers), no need for int* and changed count != size to i < size just in case the user accidentally modifies 'i' to be bigger than size and get stuck in an infinite loop.

#define FOREACH(item, array, start, size)\
for(int i = start, keep = 1;\
keep && i < size;\
keep = !keep, i++)\
for (item = array[i]; keep; keep = !keep)


int array[] = { 1, 2, 3, 4, 5 };
FOREACH(int x, array, 2, 5)
printf("index: %d. element: %d\n", i, x);

Output:

index: 2. element: 3
index: 3. element: 4
index: 4. element: 5

Here is what I use when I'm stuck with C. You can't use the same item name twice in the same scope, but that's not really an issue since not all of us get to use nice new compilers :(

#define FOREACH(type, item, array, size) \
size_t X(keep), X(i); \
type item; \
for (X(keep) = 1, X(i) = 0 ; X(i) < (size); X(keep) = !X(keep), X(i)++) \
for (item = (array)[X(i)]; X(keep); X(keep) = 0)


#define _foreach(item, array) FOREACH(__typeof__(array[0]), item, array, length(array))
#define foreach(item_in_array) _foreach(item_in_array)


#define in ,
#define length(array) (sizeof(array) / sizeof((array)[0]))
#define CAT(a, b) CAT_HELPER(a, b) /* Concatenate two symbols for macros! */
#define CAT_HELPER(a, b) a ## b
#define X(name) CAT(__##name, __LINE__) /* unique variable */

Usage:

int ints[] = {1, 2, 0, 3, 4};
foreach (i in ints) printf("%i", i);
/* can't use the same name in this scope anymore! */
foreach (x in ints) printf("%i", x);

EDIT: Here is an alternative for FOREACH using the c99 syntax to avoid namespace pollution:

#define FOREACH(type, item, array, size) \
for (size_t X(keep) = 1, X(i) = 0; X(i) < (size); X(keep) = 1, X(i)++) \
for (type item = (array)[X(i)]; X(keep); X(keep) = 0)

While C does not have a for each construct, it has always had an idiomatic representation for one past the end of an array (&arr)[1]. This allows you to write a simple idiomatic for each loop as follows:

int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);

If you're planning to work with function pointers

#define lambda(return_type, function_body)\
({ return_type __fn__ function_body __fn__; })


#define array_len(arr) (sizeof(arr)/sizeof(arr[0]))


#define foreachnf(type, item, arr, arr_length, func) {\
void (*action)(type item) = func;\
for (int i = 0; i<arr_length; i++) action(arr[i]);\
}


#define foreachf(type, item, arr, func)\
foreachnf(type, item, arr, array_len(arr), func)


#define foreachn(type, item, arr, arr_length, body)\
foreachnf(type, item, arr, arr_length, lambda(void, (type item) body))


#define foreach(type, item, arr, body)\
foreachn(type, item, arr, array_len(arr), body)

Usage:

int ints[] = { 1, 2, 3, 4, 5 };
foreach(int, i, ints, {
printf("%d\n", i);
});


char* strs[] = { "hi!", "hello!!", "hello world", "just", "testing" };
foreach(char*, s, strs, {
printf("%s\n", s);
});


char** strsp = malloc(sizeof(char*)*2);
strsp[0] = "abcd";
strsp[1] = "efgh";
foreachn(char*, s, strsp, 2, {
printf("%s\n", s);
});


void (*myfun)(int i) = somefunc;
foreachf(int, i, ints, myfun);

But I think this will work only on gcc (not sure).

As you probably already know, there's no "foreach"-style loop in C.

Although there are already tons of great macros provided here to work around this, maybe you'll find this macro useful:

// "length" is the length of the array.
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)

...which can be used with for (as in for each (...)).

Advantages of this approach:

  • item is declared and incremented within the for statement (just like in Python!).
  • Seems to work on any 1-dimensional array
  • All variables created in macro (p, item), aren't visible outside the scope of the loop (since they're declared in the for loop header).

Disadvantages:

  • Doesn't work for multi-dimensional arrays
  • Relies on typeof(), which is a GNU extension, not part of standard C
  • Since it declares variables in the for loop header, it only works in C11 or later.

Just to save you some time, here's how you could test it:

typedef struct {
double x;
double y;
} Point;


int main(void) {
double some_nums[] = {4.2, 4.32, -9.9, 7.0};
for each (element, some_nums, 4)
printf("element = %lf\n", element);


int numbers[] = {4, 2, 99, -3, 54};
// Just demonstrating it can be used like a normal for loop
for each (number, numbers, 5) {
printf("number = %d\n", number);
if (number % 2 == 0)
printf("%d is even.\n", number);
}


char* dictionary[] = {"Hello", "World"};
for each (word, dictionary, 2)
printf("word = '%s'\n", word);


Point points[] = \{\{3.4, 4.2}, {9.9, 6.7}, {-9.8, 7.0}};
for each (point, points, 3)
printf("point = (%lf, %lf)\n", point.x, point.y);


/* Neither p, element, number or word are visible outside the scope of
their respective for loops. Try to see if these printfs work (they shouldn't): */
//printf("*p = %s", *p);
//printf("word = %s", word);


return 0;
}

Seems to work on gcc and clang by default; haven't tested other compilers.

C does not have an implementation of for-each. When parsing an array as a point the receiver does not know how long the array is, thus there is no way to tell when you reach the end of the array. Remember, in C int* is a point to a memory address containing an int. There is no header object containing information about how many integers that are placed in sequence. Thus, the programmer needs to keep track of this.

However, for lists, it is easy to implement something that resembles a for-each loop.

for(Node* node = head; node; node = node.next) {
/* do your magic here */
}

To achieve something similar for arrays you can do one of two things.

  1. use the first element to store the length of the array.
  2. wrap the array in a struct which holds the length and a pointer to the array.

The following is an example of such struct:

typedef struct job_t {
int count;
int* arr;
} arr_t;

I defined foreach using a macro and helper function. It allows for nested cycles (although limited) and the item is only defined in scope of the cycle. The only problem is that the macro contains 2 statements, so no if(...) foreach(...) printf(...);, but I wouldn't recommend doing that with any statement.

You can probably improve it with the gnu typeof macro and the #define in ,, if you want.

#define MAX_FOREACH_NESTING 16


#define foreach(type, item, set) \
helper_foreach_next(NULL, 0, NULL, 0, 1); \
for(type item;helper_foreach_next((char *) array, sizeof(array)/sizeof(array[0]), &item, sizeof(type), 0);)




int helper_foreach_next(char *array, size_t array_size, void *item, size_t item_size, int setup) {
static int nesting = -1;
static size_t indexes[MAX_FOREACH_NESTING] = { 0 };


if(setup) {
nesting++;
return 0;
}
if (indexes[nesting] < array_size) {
memcpy(item, array + indexes[nesting]*item_size, item_size);
indexes[nesting]++;
return 1;
} else {
indexes[nesting] = 0;
nesting--;
return 0;
}
}

You can call it like this:

int array1[] = { 3, 4, 5};


foreach(int, a, array1) {
foreach(int, b, array1) {
printf("%d-%d\n", a, b);
}
}