Presque toutes les langues ont une foreach
boucle ou quelque chose de similaire. Est-ce que C en a un? Pouvez-vous publier un exemple de code?
foreach
boucle dans un programme C?
Presque toutes les langues ont une foreach
boucle ou quelque chose de similaire. Est-ce que C en a un? Pouvez-vous publier un exemple de code?
foreach
boucle dans un programme C?
Réponses:
C n'a pas de foreach, mais les macros sont fréquemment utilisées pour émuler cela:
#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)
Et peut être utilisé comme
for_each_item(i, processes) {
i->wakeup();
}
L'itération sur un tableau est également possible:
#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)
Et peut être utilisé comme
int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}
Edit: Si vous êtes également intéressé par les solutions C ++, C ++ a une syntaxe native for-each appelée "range based for"
#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)
un problème que je peux voir est que le nombre et la taille des variables vivent en dehors de la boucle for et peuvent provoquer un conflit. Est-ce la raison pour laquelle vous utilisez deux boucles for? [code collé ici ( pastebin.com/immndpwS )]
if(...) foreach(int *v, values) ...
. S'ils sont en dehors de la boucle, il s'agrandit if(...) int count = 0 ...; for(...) ...;
et se cassera.
Voici un exemple de programme complet d'une macro for-each en 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[]
définition? Ne pourriez-vous pas simplement écrire à la next
place de .next
?
free()
) et d'autre part, il a une référence à la valeur dans sa définition. C'est vraiment un exemple de quelque chose qui est tout simplement trop intelligent; le code est assez complexe sans y ajouter intentionnellement de l'intelligence. L'aphorisme de Kernighan ( stackoverflow.com/questions/1103299/… ) s'applique!
Il n'y a pas de foreach dans C.
Vous pouvez utiliser une boucle for pour parcourir les données mais la longueur doit être connue ou les données doivent être terminées par une valeur connue (par exemple, null).
char* nullTerm;
nullTerm = "Loop through my characters";
for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}
Comme vous le savez probablement déjà, il n'y a pas de boucle de style "foreach" dans C.
Bien qu'il existe déjà des tonnes de bonnes macros fournies ici pour contourner ce problème, vous trouverez peut-être cette macro utile:
// "length" is the length of the array.
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)
... qui peut être utilisé avec for
(comme dans for each (...)
).
Avantages de cette approche:
item
est déclaré et incrémenté dans l'instruction for (comme en Python!).p
, item
), ne sont pas visibles en dehors de la portée de la boucle (puisqu'elles sont déclarées dans l'en-tête de la boucle for).Désavantages:
typeof()
, qui est une extension GNU, ne fait pas partie du standard CJuste pour vous faire gagner du temps, voici comment vous pouvez le tester:
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;
}
Semble fonctionner sur gcc et clang par défaut; n'ont pas testé d'autres compilateurs.
C'est une question assez ancienne, mais je pensais que je devrais la poster. C'est une boucle foreach pour 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;
}
Ce code a été testé pour fonctionner avec gcc, icc et clang sous GNU / Linux.
Bien que C n'ait pas de pour chaque construction, il a toujours eu une représentation idiomatique pour un après la fin d'un tableau (&arr)[1]
. Cela vous permet d'écrire une idiomatique simple pour chaque boucle comme suit:
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
(&arr)[1]
ne signifie pas un élément de tableau après la fin du tableau, cela signifie un tableau après la fin du tableau. (&arr)[1]
n'est pas le dernier élément du tableau [0], c'est le tableau [1], qui se désintègre en un pointeur vers le premier élément (du tableau [1]). Je pense que ce serait bien mieux, plus sûr et idiomatique à faire const int* begin = arr; const int* end = arr + sizeof(arr)/sizeof(*arr);
et ensuite for(const int* a = begin; a != end; a++)
.
C a des mots-clés «for» et «while». Si une instruction foreach dans un langage comme C # ressemble à ceci ...
foreach (Element element in collection)
{
}
... alors l'équivalent de cette instruction foreach en C pourrait être comme:
for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}
Voici ce que j'utilise quand je suis coincé avec C.Vous ne pouvez pas utiliser le même nom d'élément deux fois dans la même portée, mais ce n'est pas vraiment un problème car nous ne pouvons pas tous utiliser de nouveaux compilateurs sympas :(
#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 */
Usage:
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: Voici une alternative pour FOREACH
utiliser la syntaxe c99 pour éviter la pollution de l'espace de noms:
#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)])
s'arrêterait une fois que l'élément du tableau avait une valeur de 0. Donc, l'utiliser avec double Array[]
peut ne pas parcourir tous les éléments. On dirait que le test de boucle devrait être l'un ou l'autre: i<n
ou A[i]
. Ajoutez peut-être des exemples de cas d'utilisation pour plus de clarté.
if ( bla ) FOREACH(....) { } else....
FOREACH
qui utilise la syntaxe c99 pour éviter la pollution de l'espace de noms.
La réponse d'Eric ne fonctionne pas lorsque vous utilisez "pause" ou "continuer".
Cela peut être corrigé en réécrivant la première ligne:
Ligne d'origine (reformatée):
for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)
Fixé:
for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)
Si vous le comparez à la boucle de Johannes, vous verrez qu'il fait en fait la même chose, juste un peu plus compliqué et plus laid.
En voici une simple, une seule boucle 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
Vous donne accès à l'index si vous le souhaitez ( i
) et à l'élément actuel sur lequel nous itérons ( it
). Notez que vous pouvez rencontrer des problèmes de dénomination lors de l'imbrication de boucles, vous pouvez faire des noms d'élément et d'index des paramètres de la macro.
Edit: Voici une version modifiée de la réponse acceptée foreach
. Vous permet de spécifier l' start
index, size
afin qu'il fonctionne sur des tableaux décomposés (pointeurs), inutile int*
et changé count != size
en i < size
juste au cas où l'utilisateur modifierait accidentellement `` i '' pour être plus grand que size
et rester coincé dans une boucle infinie.
#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);
Production:
index: 2. element: 3
index: 3. element: 4
index: 4. element: 5
Si vous prévoyez de travailler avec des pointeurs de fonction
#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);
Mais je pense que cela ne fonctionnera que sur gcc (pas sûr).
C n'a pas d'implémentation de for-each
. Lors de l'analyse d'un tableau en tant que point, le récepteur ne sait pas combien de temps dure le tableau, il n'y a donc aucun moyen de savoir quand vous atteignez la fin du tableau. Souvenez-vous qu'en C int*
est un point vers une adresse mémoire contenant un int. Il n'y a pas d'objet d'en-tête contenant des informations sur le nombre d'entiers placés en séquence. Ainsi, le programmeur doit garder une trace de cela.
Cependant, pour les listes, il est facile d'implémenter quelque chose qui ressemble à une for-each
boucle.
for(Node* node = head; node; node = node.next) {
/* do your magic here */
}
Pour obtenir quelque chose de similaire pour les tableaux, vous pouvez effectuer l'une des deux opérations suivantes.
Voici un exemple d'une telle structure:
typedef struct job_t {
int count;
int* arr;
} arr_t;
foreach
" de quoi?