C是否有一个“foreach”循环结构?

几乎所有的语言都有一个foreach循环或类似的东西。 C有吗? 你可以发布一些示例代码?

C没有foreach,但macros经常用来模拟:

 #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 ++解决scheme感兴趣,C ++有一个本地的每个语法称为“基于范围”

下面是C99中每个macros的完整程序示例:

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

此代码已经过testing,可以在GNU / Linux上使用gcc,icc和clang。

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对每个构造都没有a,但是对于一个数组的末尾(&arr)[1]它总是有一个惯用的表示。 这使您可以为每个循环编写一个简单的惯用语句,如下所示:

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

当你使用“break”或“continue”时, Eric的回答不起作用。

这可以通过重写第一行来解决:

原始行(重新格式化):

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

固定:

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

如果你把它和Johannes的循环比较,你会发现他实际上也在做同样的事情,只是更复杂一些而已。

这里是一个简单的单循环:

 #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 

您可以访问索引( i )和我们正在迭代的当前项目( it )。 请注意,在嵌套循环时可能会遇到命名问题,您可以将项目和索引名称作为macros的参数。

编辑:这是一个接受的答案foreach的修改版本。 让你指定start索引, size以便它在腐烂的数组(指针)上工作,不需要int*和改变count != sizei < size ,以防用户意外地修改'i'大于size并陷入无限循环。

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

输出:

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

这里是我用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); 

如果你打算使用函数指针

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

用法:

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

但我认为这将只对gcc(不知道)。

你可能已经知道,C中没有“for each”风格的循环。

虽然已经有很多伟大的macros提供了解决这个问题,也许你会发现这个macros有用。

 // "size" refers to the number of elements in the array #define foreach(item, array, size) \ for (typeof(*array) *p = array, item = *p; p != array+size; p = p+1, item = *p) 

这种方法的优点:

  • item在for语句中声明并增加; (就像在Python中一样!)。
  • 适用于任何types的数组。
  • 在macros(p,item)中创build的所有variables在循环范围之外是不可见的(因为它们是在循环中声明的)。

缺点:

  • 依赖于typeof()运算符,这是一个gcc扩展; 不是标准C的一部分
  • 如果已经声明了item和p,则会发生variables名冲突。
  • 由于它在for循环头文件中声明了variables,它只能在C11或更高版本中使用。

为了节省时间,下面介绍如何testing它:

 int main(void) { double some_nums[] = {4.2, 4.32, -9.9, 7.0}; foreach (element, some_nums, 4) { printf("element = %lf\n", element); } int numbers[] = {4, 2, 99, -3, 54}; foreach (number, numbers, 5) { printf("number = %d\n", number); } char *dictionary[] = {"Hello", "World"}; foreach (word, dictionary, 2) { printf("word = '%s'\n", word); } // 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; } 

似乎在海湾合作委员会和叮当工作; 不确定其他编译器。