Fast alle Sprachen haben eine foreachSchleife oder ähnliches. Hat C einen? Können Sie einen Beispielcode posten?
foreachSchleife in ein C-Programm zu schreiben ?
Fast alle Sprachen haben eine foreachSchleife oder ähnliches. Hat C einen? Können Sie einen Beispielcode posten?
foreachSchleife in ein C-Programm zu schreiben ?
Antworten:
C hat kein foreach, aber Makros werden häufig verwendet, um Folgendes zu emulieren:
#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)
Und kann wie verwendet werden
for_each_item(i, processes) {
i->wakeup();
}
Eine Iteration über ein Array ist ebenfalls möglich:
#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)
Und kann wie verwendet werden
int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}
Bearbeiten: Falls Sie auch an C ++ - Lösungen interessiert sind, verfügt C ++ über eine native Syntax für jede Syntax namens "range based for".
#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)Ein Problem, das ich sehen kann, ist, dass die Anzahl und Größe der Variablen außerhalb der for-Schleife liegen und einen Konflikt verursachen können. Verwenden Sie deshalb zwei for-Schleifen? [Code hier eingefügt ( pastebin.com/immndpwS )]
if(...) foreach(int *v, values) .... Wenn sie sich außerhalb der Schleife befinden, dehnt sie sich aus if(...) int count = 0 ...; for(...) ...;und bricht ab.
Hier ist ein vollständiges Programmbeispiel für jedes Makro 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;
}
list[]Definition? Könntest du nicht einfach schreiben nextstatt .next?
free()), und zum anderen verweist es auf den Wert in seiner Definition. Es ist wirklich ein Beispiel für etwas, das einfach zu schlau ist. Code ist komplex genug, ohne ihm absichtlich Klugheit zu verleihen. Kernighans Aphorismus ( stackoverflow.com/questions/1103299/… ) gilt!
Es gibt kein foreach in C.
Sie können eine for-Schleife verwenden, um die Daten zu durchlaufen, aber die Länge muss bekannt sein oder die Daten müssen durch einen bekannten Wert (z. B. null) abgeschlossen werden.
char* nullTerm;
nullTerm = "Loop through my characters";
for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}
Wie Sie wahrscheinlich bereits wissen, gibt es in C keine Schleife im "foreach" -Stil.
Obwohl hier bereits unzählige großartige Makros bereitgestellt werden, um dies zu umgehen, finden Sie dieses Makro möglicherweise nützlich:
// "length" is the length of the array.
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)
... die mit for(wie in for each (...)) verwendet werden können.
Vorteile dieses Ansatzes:
item wird innerhalb der for-Anweisung deklariert und inkrementiert (genau wie in Python!).p, item) erstellten Variablen sind außerhalb des Bereichs der Schleife nicht sichtbar (da sie im for-Schleifenheader deklariert sind).Nachteile:
typeof()eine GNU-Erweiterung, die nicht Teil von Standard C istUm Ihnen Zeit zu sparen, können Sie dies folgendermaßen testen:
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;
}
Scheint standardmäßig mit gcc und clang zu arbeiten; habe andere Compiler nicht getestet.
Dies ist eine ziemlich alte Frage, aber ich denke, ich sollte dies posten. Es ist eine foreach-Schleife für 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;
}
Dieser Code wurde getestet, um mit gcc, icc und clang unter GNU / Linux zu funktionieren.
Während C nicht für jedes Konstrukt ein hat, hatte es immer eine idiomatische Darstellung für eines nach dem Ende eines Arrays (&arr)[1]. Auf diese Weise können Sie für jede Schleife wie folgt eine einfache Redewendung schreiben:
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
(&arr)[1]bedeutet nicht, dass ein Array-Element nach dem Ende des Arrays liegt, sondern dass ein Array nach dem Ende des Arrays liegt. (&arr)[1]ist nicht das letzte Element des Arrays [0], sondern das Array [1], das in einen Zeiger auf das erste Element (des Arrays [1]) zerfällt. Ich glaube, es wäre viel besser, sicherer und idiomatischer const int* begin = arr; const int* end = arr + sizeof(arr)/sizeof(*arr);und dann for(const int* a = begin; a != end; a++).
C hat die Schlüsselwörter 'for' und 'while'. Wenn eine foreach-Anweisung in einer Sprache wie C # so aussieht ...
foreach (Element element in collection)
{
}
... dann könnte das Äquivalent dieser foreach-Anweisung in C wie folgt lauten:
for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}
Folgendes verwende ich, wenn ich bei C stecke. Sie können nicht denselben Elementnamen zweimal im selben Bereich verwenden, aber das ist kein wirkliches Problem, da nicht alle von uns nette neue Compiler verwenden können :(
#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 */
Verwendung:
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);
BEARBEITEN: Hier ist eine Alternative zur FOREACHVerwendung der c99-Syntax, um eine Verschmutzung des Namespace zu vermeiden:
#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)
VAR(i) < (size) && (item = array[VAR(i)])würde aufhören, sobald das Array-Element den Wert 0 hat. Wenn Sie dies also mit verwenden, werden double Array[]möglicherweise nicht alle Elemente durchlaufen. Scheint, als sollte der Schleifentest der eine oder andere sein: i<noder A[i]. Fügen Sie zur Verdeutlichung möglicherweise Anwendungsbeispiele hinzu.
if ( bla ) FOREACH(....) { } else....
FOREACH, die die c99-Syntax verwendet, um eine Verschmutzung des Namespace zu vermeiden.
Erics Antwort funktioniert nicht, wenn Sie "break" oder "continue" verwenden.
Dies kann durch Umschreiben der ersten Zeile behoben werden:
Originalzeile (neu formatiert):
for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)
Fest:
for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)
Wenn Sie es mit Johannes 'Schleife vergleichen, werden Sie sehen, dass er tatsächlich dasselbe tut, nur ein bisschen komplizierter und hässlicher.
Hier ist eine einfache Single-for-Schleife:
#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
Ermöglicht Ihnen den Zugriff auf den Index, falls Sie ihn möchten ( i) und das aktuelle Element, über das wir iterieren ( it). Beachten Sie, dass beim Verschachteln von Schleifen möglicherweise Namensprobleme auftreten. Sie können festlegen, dass die Element- und Indexnamen Parameter für das Makro sind.
Bearbeiten: Hier ist eine modifizierte Version der akzeptierten Antwort foreach. Hiermit können Sie den startIndex angeben , sizedamit er auf verfallenen Arrays (Zeigern) funktioniert, ohne dass dies erforderlich ist int*und geändert wird count != size, i < sizefalls der Benutzer versehentlich 'i' so ändert, dass es größer als ist sizeund in einer Endlosschleife stecken bleibt.
#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);
Ausgabe:
index: 2. element: 3
index: 3. element: 4
index: 4. element: 5
Wenn Sie mit Funktionszeigern arbeiten möchten
#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)
Verwendung:
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);
Aber ich denke, das wird nur auf gcc funktionieren (nicht sicher).
C hat keine Implementierung von for-each. Wenn Sie ein Array als Punkt analysieren, weiß der Empfänger nicht, wie lang das Array ist. Daher können Sie nicht feststellen, wann Sie das Ende des Arrays erreichen. Denken Sie daran, in C.int* ein Punkt auf eine Speicheradresse steht, die ein int enthält. Es gibt kein Header-Objekt, das Informationen darüber enthält, wie viele Ganzzahlen nacheinander platziert werden. Daher muss der Programmierer dies verfolgen.
Für Listen ist es jedoch einfach, etwas zu implementieren, das einer for-eachSchleife ähnelt .
for(Node* node = head; node; node = node.next) {
/* do your magic here */
}
Um etwas Ähnliches für Arrays zu erreichen, können Sie eines von zwei Dingen tun.
Das Folgende ist ein Beispiel für eine solche Struktur:
typedef struct job_t {
int count;
int* arr;
} arr_t;
foreach" von was?