Does C have a “foreach” loop construct?

前端 未结 12 2165
情书的邮戳
情书的邮戳 2020-12-02 03:49

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

相关标签:
12条回答
  • 2020-12-02 04:18

    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
    
    0 讨论(0)
  • 2020-12-02 04:19

    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.
    }
    
    0 讨论(0)
  • 2020-12-02 04:25

    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;
    }
    
    0 讨论(0)
  • 2020-12-02 04:27

    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);
    
    0 讨论(0)
  • 2020-12-02 04:29

    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.

    0 讨论(0)
  • 2020-12-02 04:31

    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.

    0 讨论(0)
提交回复
热议问题