programing

C에 "foreach"루프 구조가 있습니까?

nasanasas 2020. 8. 20. 18:56
반응형

C에 "foreach"루프 구조가 있습니까?


거의 모든 언어에는 foreach루프 또는 유사한 것이 있습니다. C에 하나가 있습니까? 예제 코드를 게시 할 수 있습니까?


C에는 foreach가 없지만 매크로는이를 에뮬레이션하는 데 자주 사용됩니다.

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

그리고 같이 사용할 수 있습니다

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

배열에 대한 반복도 가능합니다.

#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)

그리고 같이 사용할 수 있습니다

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

편집 : C ++ 솔루션에도 관심이있는 경우 C ++에는 "범위 기반"이라는 기본 for-each 구문이 있습니다.


다음은 C99의 for-each 매크로에 대한 전체 프로그램 예제입니다.

#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;
}

C에는 foreach가 없습니다.

for 루프를 사용하여 데이터를 반복 할 수 있지만 길이를 알고 있거나 데이터를 알고있는 값 (예 : null)으로 종료해야합니다.

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

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

이것은 상당히 오래된 질문이지만 나는 이것을 게시해야합니다. GNU C99의 foreach 루프입니다.

#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;
}

이 코드는 GNU / Linux에서 gcc, icc 및 clang과 함께 작동하도록 테스트되었습니다.


이미 알고 있듯이 C에는 "foreach"스타일의 루프가 없습니다.

이 문제를 해결하기 위해 여기에 이미 많은 훌륭한 매크로가 제공되어 있지만이 매크로가 유용 할 것입니다.

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

... for(에서 같이 for each (...)) 와 함께 사용할 수 있습니다 .

이 접근 방식의 장점 :

  • item for 문 내에서 선언되고 증가합니다 (Python에서와 마찬가지로!).
  • 모든 1 차원 배열에서 작동하는 것 같습니다.
  • 매크로 ( p, item) 에서 생성 된 모든 변수 는 루프 범위 밖에서 보이지 않습니다 (for 루프 헤더에서 선언 되었기 때문에).

단점 :

  • 다차원 배열에서는 작동하지 않습니다.
  • 표준 C의 일부가 아닌typeof() gcc 확장 인 에 의존합니다 .
  • for 루프 헤더에서 변수를 선언하므로 C11 이상에서만 작동합니다.

시간을 절약하기 위해 다음과 같이 테스트 할 수 있습니다.

typedef struct _point {
    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;
}

gcc 및 clang에서 작동하는 것 같습니다. 다른 컴파일러에 대해서는 확실하지 않습니다.


C에는 각 구성에 대한 a가 없지만 항상 배열의 끝을 지나서 하나에 대한 관용적 표현이 (&arr)[1]있습니다. 이를 통해 다음과 같이 각 루프에 대한 간단한 관용어를 작성할 수 있습니다.

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

C에는 'for'및 'while'키워드가 있습니다. C #과 같은 언어의 foreach 문이 다음과 같은 경우 ...

foreach (Element element in collection)
{
}

... C에서이 foreach 문에 해당하는 내용은 다음과 같습니다.

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

다음은 내가 C를 사용할 때 사용하는 것입니다. 같은 범위에서 동일한 항목 이름을 두 번 사용할 수는 없지만 우리 모두가 멋진 새 컴파일러를 사용하는 것은 아니기 때문에 실제로 문제가되지는 않습니다.

#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 */

용법:

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);

편집 : 다음은 FOREACH네임 스페이스 오염을 피하기 위해 c99 구문을 사용 하는 대안입니다 .

#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)

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

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).


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;

참고URL : https://stackoverflow.com/questions/400951/does-c-have-a-foreach-loop-construct

반응형