tags:

views:

3766

answers:

7

Almost all languages have a foreach loop (function) or something similar. I wonder if C has one? Can you post some example code?

+4  A: 

No, it doesn't.

chaos
I love all the activity on this answer. I should suggest a "Controversial" badge for having a question that gets at least 10 upvotes and 10 downvotes...
chaos
Try that one: http://stackoverflow.com/questions/1450810/linux-vs-windows-programming/1451589#1451589 ^_^
paercebal
+3  A: 

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.
}
Adam Peck
You should add the initialization of the nullTerm pointer to the beginning of the data set. The OP might be confused about the incomplete for loop.
cschol
Fleshed out the example a little.
Adam Peck
you are changing your original pointer, I would do something like: char* s;s="...";for(char *it=s;it!=NULL;it++){/*it point to the character*/}
hiena
+2  A: 

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 ...
}
ChrisW
You should mention that your example code is not written in C syntax.
cschol
> You should mention that your example code is not written in C syntaxYou're right, thank you: I'll edit the post.
ChrisW
@monjardin-> sure you can just define pointer to function in the struct and there is no problem to make the call like this.
Ilya
+32  A: 

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); \
        count != size; \
        keep=1, 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, boost has it (but C++ itself doesn't have a native for-each loop yet): Boost.ForEach

Johannes Schaub - litb
your foreach implementation is great. never thought about nesting for's.
If you've got the "typeof" operator (gcc extension; pretty common on many other compilers) you can get rid of that "int *". The inner for loop becomes something like "for(typeof((array)+0) item = ..." Then you can call as "foreach( v, values ) ..."
leander
@Johannes Schaub - litb: Why do we need two for loops in the array example? How about this: `#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)` One problem that I can see is that variables count and size live outside the for loop, and might cause a conflict. Is this the reason you use two for loops? [code pasted here(http://pastebin.com/immndpwS )]
Lazer
@eSKay yes consider `if(...) foreach(int *v, values) ...` . If they are outside the loop it expands to `if(...) int count = 0 ...; for(...) ...;` and will break.
Johannes Schaub - litb
@Johannes Schaub - litb: thanks. neat trick!
Lazer
+3  A: 

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;
}
Judge Maygarden
What does the dot do in the `list[]` definition? Couldn't you simply write `next` instead of `.next`?
Rizo
@Rizo No, the dot is a part of the syntax for _C99 designated initializers_. See http://en.wikipedia.org/wiki/C_syntax#Initialization
Judge Maygarden
@Rizo: Note also that that's a really hacky way of building a linked list. It'll do for this demo but *don't* do it that way in practice!
Donal Fellows
@Donal What makes it "hacky"?
Judge Maygarden
@Judge: Well, for one thing it has “surprising” lifetime (if you're working with code which removes elements, chances are you'll crash in `free()`) and for another it has a reference to the value inside its definition. It's really an example of something that's just too damn clever; code's complex enough without purposefully adding cleverness to it. Kernighan's aphorism (http://stackoverflow.com/questions/1103299/help-me-understand-this-brian-kernighan-quote) applies!
Donal Fellows
@Donal: Fair enough. ;)
Judge Maygarden
A: 

For a C++ class with size() and operator[] defined, try:


#define foreach(A,B) \
    for(unsigned i=0,__a=1;i<B.size();i++,__a=1) \
    for(A=B[i];__a;__a=0)

int main(){
    vector v;
    v.push_back(0);
    v.push_back(0);
    v.push_back(2);

    foreach(int k,v){
     cout<<k<<"\n";
    }
}

This might not be the fastest, though.

You bumped a very old question to give an answer in the wrong language... :X
GMan
A: 

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.

Joe D