varstatus index funciona ejemplo como c foreach

index - ¿C tiene una construcción de bucle "foreach"?



c:foreach jsf (12)

Aquí hay un ejemplo completo del programa de una macro para cada uno 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; }

Casi todos los idiomas tienen un ciclo foreach o algo similar. ¿C tiene uno? ¿Puedes publicar un código de ejemplo?


Aquí hay un simple, solo para el bucle:

#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

Te da acceso al índice si lo deseas ( i ) y el elemento actual sobre el que estamos iterando ( it ). Tenga en cuenta que puede tener problemas de nomenclatura al anidar bucles, puede hacer que el elemento y los nombres de índice sean parámetros de la macro.

Editar: Aquí hay una versión modificada de la respuesta aceptada foreach . Permite especificar el índice de start , el size para que funcione en matrices decaídas (punteros), sin necesidad de int* y count != size cambiado count != size en i < size solo en caso de que el usuario modifique accidentalmente ''i'' para que sea más grande que el size y quedar atrapado en 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);

Salida:

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


C no tiene un foreach, pero las macros se utilizan con frecuencia para emular eso:

#define for_each_item(item, list) / for(T * item = list->head; item != NULL; item = item->next)

Y se puede usar como

for_each_item(i, processes) { i->wakeup(); }

La iteración sobre una matriz también es posible:

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

Y se puede usar como

int values[] = { 1, 2, 3 }; foreach(int *v, values) { printf("value: %d/n", *v); }

Editar: en caso de que también esté interesado en las soluciones de C ++, C ++ tiene una sintaxis nativa para cada una llamada "rango basado en"


C no tiene una implementación de for-each . Al analizar una matriz como un punto, el receptor no sabe por cuánto tiempo está la matriz, por lo tanto, no hay forma de saber cuándo se llega al final de la matriz. Recuerde, en C int* es un punto a una dirección de memoria que contiene un int. No hay ningún objeto de encabezado que contenga información sobre cuántos enteros se colocan en secuencia. Por lo tanto, el programador necesita realizar un seguimiento de esto.

Sin embargo, para las listas, es fácil implementar algo que se asemeja a un bucle for-each .

for(Node* node = head; node; node = node.next) { /* do your magic here */ }

Para lograr algo similar para las matrices, puede hacer una de estas dos cosas.

  1. use el primer elemento para almacenar la longitud de la matriz.
  2. envuelva la matriz en una estructura que contenga la longitud y un puntero a la matriz.

El siguiente es un ejemplo de tal estructura:

typedef struct job_t { int count; int* arr; } arr_t;


C tiene palabras clave ''para'' y ''while''. Si una declaración foreach en un idioma como C # se ve así ...

foreach (Element element in collection) { }

... entonces el equivalente de esta declaración foreach en C podría ser como:

for ( Element* element = GetFirstElement(&collection); element != 0; element = GetNextElement(&collection, element) ) { //TODO: do something with this element instance ... }


Como probablemente ya sepa, no existe un ciclo de estilo "foreach" en C.

Aunque ya hay toneladas de grandes macros proporcionadas aquí para solucionar este problema, tal vez le resulte útil esta 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)

... que se puede usar con for (como en for each (...) ).

Ventajas de este enfoque:

  • el artículo se declara y se incrementa dentro de la declaración for (¡como en Python!).
  • Parece que funciona en cualquier matriz de 1 dimensión
  • Todas las variables creadas en macro (p, elemento) no son visibles fuera del alcance del bucle (ya que están declaradas en el encabezado for del bucle).

Desventajas:

  • No funciona para matrices multidimensionales
  • Se basa en typeof() , que es una extensión de gcc; NO parte de la norma C
  • Como declara variables en el encabezado de bucle for, solo funciona en C11 o posterior.

Solo para ahorrar algo de tiempo, he aquí cómo puedes probarlo:

typedef struct _point { 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; }

Parece que funciona en gcc y clang; no estoy seguro acerca de otros compiladores.


Esta es una pregunta bastante antigua, pero pensé que debería publicar esto. Es un ciclo foreach para 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; }

Este código ha sido probado para funcionar con gcc, icc y clang en GNU / Linux.


Esto es lo que uso cuando estoy atrapado con C. No se puede usar el mismo nombre dos veces en el mismo ámbito, pero eso no es realmente un problema ya que no todos usamos buenos compiladores nuevos :(

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


Mientras que C no tiene un para cada construcción, siempre ha tenido una representación idiomática para un pasado del final de una matriz (&arr)[1] . Esto le permite escribir un idiomático simple para cada ciclo de la siguiente manera:

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


No hay foreach en C.

Puede usar un bucle for para recorrer los datos, pero la longitud debe conocerse o los datos deben terminarse por un valor conocido (por ejemplo, nulo).

char* nullTerm; nullTerm = "Loop through my characters"; for(;nullTerm != NULL;nullTerm++) { //nullTerm will now point to the next character. }


Si está planeando trabajar con punteros de función

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

Pero creo que esto solo funcionará en gcc (no estoy seguro).


La respuesta de Eric no funciona cuando estás usando "break" o "continue".

Esto se puede solucionar reescribiendo la primera línea:

Línea original (formateada):

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

Fijo:

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

Si lo comparas con el bucle de Johannes, verás que en realidad está haciendo lo mismo, solo que un poco más complicado y feo.