ほとんどすべての言語には、foreach
ループまたは類似のものがあります。Cは持っていますか?サンプルコードを投稿できますか?
12 に答える
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++ には「range based for」と呼ばれるネイティブの 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.
}
C には for each 構造はありませんが、配列の末尾の 1 つを超える慣用的な表現が常にあり(&arr)[1]
ます。これにより、次のようにループごとに簡単な慣用句を書くことができます。
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
これはかなり古い質問ですが、これを投稿する必要があります。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 で行き詰まったときに使用するものです。同じスコープで同じアイテム名を 2 回使用することはできませんが、私たち全員が優れた新しいコンパイラを使用できるわけではないので、それは実際には問題ではありません :(
#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)
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 ...
}
「ブレーク」または「続行」を使用している場合、エリックの答えは機能しません。
これは、最初の行を書き直すことで修正できます。
元の行(再フォーマット):
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)
ヨハネスのループと比較すると、彼が実際に同じことをしていることがわかりますが、もう少し複雑で醜いです。
これは単純なもので、単一の for ループです。
#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
。ループをネストするときに名前付けの問題が発生する可能性があることに注意してください。アイテムとインデックスの名前をマクロのパラメーターにすることができます。
編集:これは、受け入れられた回答の修正版ですforeach
。start
インデックスを指定してsize
、減衰した配列 (ポインター) で機能するようにします。ユーザーが誤って 'i' をより大きく変更して無限ループに陥った場合に備えてint*
変更count != size
する必要はありません。i < size
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