Quasi tutte le lingue hanno un foreach
ciclo o qualcosa di simile. C ne ha uno? Puoi pubblicare un codice di esempio?
foreach
ciclo in un programma C?
Quasi tutte le lingue hanno un foreach
ciclo o qualcosa di simile. C ne ha uno? Puoi pubblicare un codice di esempio?
foreach
ciclo in un programma C?
Risposte:
C non ha un foreach, ma le macro vengono spesso utilizzate per emularlo:
#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)
E può essere usato come
for_each_item(i, processes) {
i->wakeup();
}
È anche possibile l'iterazione su un array:
#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)
E può essere usato come
int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}
Modifica: nel caso in cui sei interessato anche alle soluzioni C ++, C ++ ha una sintassi nativa per ogni chiamata "basata su intervallo per"
#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)
un problema che posso vedere è che le variabili count e size vivono al di fuori del ciclo for e potrebbero causare un conflitto. È questo il motivo per cui usi due cicli for? [codice incollato qui ( pastebin.com/immndpwS )]
if(...) foreach(int *v, values) ...
. Se sono al di fuori del ciclo, si espande if(...) int count = 0 ...; for(...) ...;
e si romperà.
Ecco un esempio di programma completo di una macro for-each 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[]
definizione? Non potresti semplicemente scrivere next
invece di .next
?
free()
) e per un altro ha un riferimento al valore all'interno della sua definizione. È davvero un esempio di qualcosa che è troppo dannatamente intelligente; il codice è abbastanza complesso senza aggiungervi intenzionalmente intelligenza. Si applica l'aforisma di Kernighan ( stackoverflow.com/questions/1103299/… )!
Non c'è foreach in C.
È possibile utilizzare un ciclo for per scorrere i dati, ma la lunghezza deve essere nota oppure i dati devono essere terminati da un valore noto (es. Null).
char* nullTerm;
nullTerm = "Loop through my characters";
for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}
Come probabilmente già saprai, non esiste un ciclo in stile "foreach" in C.
Sebbene ci siano già tonnellate di ottime macro fornite qui per aggirare questo problema, forse troverai utile questa macro:
// "length" is the length of the array.
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)
... che può essere utilizzato con for
(come in for each (...)
).
Vantaggi di questo approccio:
item
viene dichiarato e incrementato all'interno dell'istruzione for (proprio come in Python!).p
, item
), non sono visibili al di fuori dell'ambito del ciclo (poiché sono dichiarate nell'intestazione del ciclo for).svantaggi:
typeof()
, che è un'estensione GNU, no parte dello standard CSolo per farti risparmiare un po 'di tempo, ecco come potresti testarlo:
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;
}
Sembra funzionare su gcc e clang per impostazione predefinita; non hanno testato altri compilatori.
Questa è una domanda abbastanza vecchia, ma ho pensato di pubblicarla. È un ciclo foreach per 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;
}
Questo codice è stato testato per funzionare con gcc, icc e clang su GNU / Linux.
Sebbene C non abbia un costrutto per ogni, ha sempre avuto una rappresentazione idiomatica per uno oltre la fine di un array (&arr)[1]
. Ciò ti consente di scrivere un semplice idiomatico per ogni ciclo come segue:
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
(&arr)[1]
non significa un elemento dell'array oltre la fine dell'array, significa un array oltre la fine dell'array. (&arr)[1]
non è l'ultimo elemento dell'array [0], è l'array [1], che decade in un puntatore al primo elemento (dell'array [1]). Credo che sarebbe molto meglio, più sicuro e idiomatico da fare const int* begin = arr; const int* end = arr + sizeof(arr)/sizeof(*arr);
e poi for(const int* a = begin; a != end; a++)
.
C contiene le parole chiave "for" e "while". Se un'istruzione foreach in un linguaggio come C # ha questo aspetto ...
foreach (Element element in collection)
{
}
... quindi l'equivalente di questa istruzione foreach in C potrebbe essere come:
for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}
Ecco cosa uso quando sono bloccato con C.Non puoi usare lo stesso nome di elemento due volte nello stesso ambito, ma non è davvero un problema poiché non tutti noi possiamo usare nuovi compilatori carini :(
#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 */
Uso:
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);
EDIT: ecco un'alternativa per l' FOREACH
utilizzo della sintassi c99 per evitare l'inquinamento dello spazio dei nomi:
#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)])
si fermerebbe una volta che l'elemento dell'array aveva un valore di 0. Quindi l'uso di questo con double Array[]
potrebbe non iterare su tutti gli elementi. Sembra che il test del ciclo dovrebbe essere uno o l'altro: i<n
o A[i]
. Forse aggiungi casi d'uso di esempio per chiarezza.
if ( bla ) FOREACH(....) { } else....
FOREACH
che utilizza la sintassi c99 per evitare l'inquinamento dello spazio dei nomi.
La risposta di Eric non funziona quando usi "interrompi" o "continua".
Questo può essere risolto riscrivendo la prima riga:
Riga originale (riformattata):
for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)
Fisso:
for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)
Se lo confronti con il loop di Johannes, vedrai che in realtà sta facendo lo stesso, solo un po 'più complicato e più brutto.
Eccone uno semplice, ciclo for singolo:
#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
Ti dà accesso all'indice se lo desideri ( i
) e l'elemento corrente su cui stiamo iterando (it
). Tieni presente che potresti avere problemi di denominazione durante la nidificazione dei loop, puoi fare in modo che i nomi degli elementi e degli indici siano parametri della macro.
Modifica: ecco una versione modificata della risposta accettata foreach
. Consente di specificare l' start
indice, in size
modo che funzioni su array decaduti (puntatori), non è necessario int*
e modificato count != size
in i < size
solo nel caso in cui l'utente modifichi accidentalmente 'i' per essere più grande di size
e rimanere bloccato in un ciclo infinito.
#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);
Produzione:
index: 2. element: 3
index: 3. element: 4
index: 4. element: 5
Se hai intenzione di lavorare con i puntatori a funzione
#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)
Uso:
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);
Ma penso che funzionerà solo su gcc (non sono sicuro).
C non ha un'implementazione di for-each
. Quando si analizza un array come un punto, il ricevitore non sa quanto è lungo l'array, quindi non c'è modo di sapere quando si raggiunge la fine dell'array. Ricorda, in Cint*
è un punto a un indirizzo di memoria contenente un int. Non esiste alcun oggetto di intestazione contenente informazioni su quanti numeri interi vengono inseriti in sequenza. Pertanto, il programmatore deve tenerne traccia.
Tuttavia, per gli elenchi, è facile implementare qualcosa che assomigli a un for-each
ciclo.
for(Node* node = head; node; node = node.next) {
/* do your magic here */
}
Per ottenere qualcosa di simile per gli array puoi fare una delle due cose.
Il seguente è un esempio di tale struttura:
typedef struct job_t {
int count;
int* arr;
} arr_t;
foreach
" di cosa?