Quase todas as linguagens possuem um foreach
loop ou algo semelhante. C tem um? Você pode postar algum código de exemplo?
foreach
loop em um programa C?
Quase todas as linguagens possuem um foreach
loop ou algo semelhante. C tem um? Você pode postar algum código de exemplo?
foreach
loop em um programa C?
Respostas:
C não tem um foreach, mas as macros são freqüentemente usadas para emular que:
#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)
E pode ser usado como
for_each_item(i, processes) {
i->wakeup();
}
A iteração sobre uma matriz também é possível:
#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 pode ser usado como
int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}
Editar: caso você também esteja interessado em soluções C ++, C ++ tem uma sintaxe nativa para cada chamada "intervalo baseado em"
#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)
um problema que posso ver é que a contagem e o tamanho das variáveis residem fora do loop for e podem causar um conflito. É este o motivo de você usar dois loops for? [código colado aqui ( pastebin.com/immndpwS )]
if(...) foreach(int *v, values) ...
. Se eles estiverem fora do loop, ele se expandirá if(...) int count = 0 ...; for(...) ...;
e será interrompido.
Aqui está um exemplo de programa completo de uma macro para cada em 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[]
definição? Você não poderia simplesmente escrever em next
vez de .next
?
free()
) e por outro tem uma referência ao valor dentro de sua definição. É realmente um exemplo de algo que é muito inteligente; o código é complexo o suficiente sem adicionar inteligência propositalmente a ele. O aforismo de Kernighan ( stackoverflow.com/questions/1103299/… ) se aplica!
Não há foreach em C.
Você pode usar um loop for para percorrer os dados, mas o comprimento precisa ser conhecido ou os dados precisam ser encerrados por um valor conhecido (por exemplo, nulo).
char* nullTerm;
nullTerm = "Loop through my characters";
for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}
Como você provavelmente já sabe, não há loop no estilo "foreach" em C.
Embora já existam muitas macros excelentes fornecidas aqui para contornar isso, talvez você ache esta macro útil:
// "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 pode ser usado com for
(como em for each (...)
).
Vantagens desta abordagem:
item
é declarado e incrementado dentro da instrução for (assim como no Python!).p
, item
) não são visíveis fora do escopo do loop (já que são declaradas no cabeçalho do loop for).Desvantagens:
typeof()
, que é uma extensão GNU, não faz parte do padrão CSó para economizar seu tempo, veja como você pode testá-lo:
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;
}
Parece funcionar no gcc e clang por padrão; não testei outros compiladores.
Esta é uma pergunta bastante antiga, mas eu pensei que deveria postar isto. É um loop 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 foi testado para funcionar com gcc, icc e clang no GNU / Linux.
Embora C não tenha um para cada construção, sempre teve uma representação idiomática para um após o final de um array (&arr)[1]
. Isso permite que você escreva uma linguagem idiomática simples para cada loop da seguinte maneira:
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
(&arr)[1]
não significa um item do array após o final do array, significa um array após o final do array. (&arr)[1]
não é o último item da matriz [0], é a matriz [1], que se transforma em um ponteiro para o primeiro elemento (da matriz [1]). Eu acredito que seria muito melhor, mais seguro e idiomático de fazer const int* begin = arr; const int* end = arr + sizeof(arr)/sizeof(*arr);
e então for(const int* a = begin; a != end; a++)
.
C tem palavras-chave 'para' e 'enquanto'. Se uma instrução foreach em uma linguagem como C # for assim ...
foreach (Element element in collection)
{
}
... então o equivalente a esta instrução foreach em C pode ser como:
for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}
Aqui está o que eu uso quando estou preso com C. Você não pode usar o mesmo nome de item duas vezes no mesmo escopo, mas isso não é realmente um problema, pois nem todos nós conseguimos usar novos compiladores legais :(
#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: Aqui está uma alternativa para FOREACH
usar a sintaxe c99 para evitar poluição do namespace:
#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)])
iria parar quando o elemento da matriz tivesse um valor 0. Portanto, usar isso com double Array[]
pode não iterar por todos os elementos. Parece que o teste de loop deve ser um ou outro: i<n
ou A[i]
. Talvez adicione casos de uso de amostra para maior clareza.
if ( bla ) FOREACH(....) { } else....
FOREACH
que usa a sintaxe c99 para evitar poluição do namespace.
A resposta de Eric não funciona quando você está usando "break" ou "continue".
Isso pode ser corrigido reescrevendo a primeira linha:
Linha original (reformatada):
for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)
Fixo:
for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)
Se você comparar com o loop de Johannes, verá que ele está realmente fazendo o mesmo, só que um pouco mais complicado e feio.
Aqui está um simples, único loop 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
Fornece acesso ao índice, caso você queira ( i
) e ao item atual sobre o qual estamos iterando ( it
). Observe que você pode ter problemas de nomenclatura ao aninhar loops, você pode fazer com que os nomes dos itens e índices sejam parâmetros para a macro.
Editar: aqui está uma versão modificada da resposta aceita foreach
. Permite que você especifique o start
índice, o size
para que funcione em matrizes decadentes (ponteiros), sem necessidade de int*
e alterado count != size
para i < size
apenas no caso de o usuário modificar acidentalmente 'i' para ser maior que size
e ficar preso em um loop 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);
Resultado:
index: 2. element: 3
index: 3. element: 4
index: 4. element: 5
Se você está planejando trabalhar com ponteiros de função
#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);
Mas acho que isso funcionará apenas no gcc (não tenho certeza).
C não tem uma implementação de for-each
. Ao analisar um array como um ponto, o receptor não sabe o tamanho do array, portanto, não há como saber quando você chega ao final do array. Lembre-se, em C int*
é um ponto para um endereço de memória contendo um int. Não há nenhum objeto de cabeçalho contendo informações sobre quantos inteiros são colocados em sequência. Portanto, o programador precisa acompanhar isso.
No entanto, para listas, é fácil implementar algo que se pareça com um for-each
loop.
for(Node* node = head; node; node = node.next) {
/* do your magic here */
}
Para obter algo semelhante para arrays, você pode fazer uma das duas coisas.
A seguir está um exemplo de tal estrutura:
typedef struct job_t {
int count;
int* arr;
} arr_t;
foreach
" de quê?