Hemen hemen tüm dillerde bir foreachdöngü veya benzer bir şey vardır. C'nin var mı? Örnek bir kod gönderebilir misin?
foreachBir C programında döngü yazmayı denemek ne kadar zor olurdu ?
Hemen hemen tüm dillerde bir foreachdöngü veya benzer bir şey vardır. C'nin var mı? Örnek bir kod gönderebilir misin?
foreachBir C programında döngü yazmayı denemek ne kadar zor olurdu ?
Yanıtlar:
C'nin bir foreach'i yoktur, ancak makrolar bunu taklit etmek için sıklıkla kullanılır:
#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)
Ve gibi kullanılabilir
for_each_item(i, processes) {
i->wakeup();
}
Bir dizi üzerinde yineleme de mümkündür:
#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)
Ve gibi kullanılabilir
int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}
Düzenleme: C ++ çözümleriyle de ilgileniyorsanız, C ++ her biri için "aralık tabanlı" adlı yerel bir sözdizimine sahiptir.
#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)Görebildiğim bir sorun, değişkenlerin sayısının ve boyutunun for döngüsünün dışında yaşaması ve bir çatışmaya neden olabileceğidir. Döngüler için iki kullanmanın nedeni bu mu? [kod buraya yapıştırıldı ( pastebin.com/immndpwS )]
if(...) foreach(int *v, values) .... Döngünün dışındaysa genişler if(...) int count = 0 ...; for(...) ...;ve kırılır.
İşte C99'daki her makro için tam bir program örneği:
#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[]yarar? nextBunun yerine basitçe yazamaz .nextmısın?
free()) ve bir başkası için tanımının içindeki değere bir referans var. Gerçekten çok zeki olan bir şeye örnek; kod, kasıtlı olarak akıllılık eklemeden yeterince karmaşıktır. Kernighan'ın aforizması ( stackoverflow.com/questions/1103299/… ) geçerlidir!
C'de foreach yoktur.
Veriler arasında döngü yapmak için bir for döngüsü kullanabilirsiniz, ancak uzunluğun bilinmesi veya verilerin bir bilinen değerle (örn. Null) sonlandırılması gerekir.
char* nullTerm;
nullTerm = "Loop through my characters";
for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}
Muhtemelen zaten bildiğiniz gibi, C'de "foreach" tarzı döngü yoktur.
Bu sorunu çözmek için burada zaten çok sayıda harika makro sağlanmış olsa da, belki bu makroyu yararlı bulabilirsiniz:
// "length" is the length of the array.
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)
... ile birlikte kullanılabilir for(olduğu gibi for each (...)).
Bu yaklaşımın avantajları:
item for ifadesi içinde bildirilir ve artırılır (tıpkı Python'da olduğu gibi!).p, item) oluşturulan tüm değişkenler döngünün kapsamı dışında görünmez (çünkü bunlar for döngüsü başlığında bildirilir).Dezavantajları:
typeof() bir GNU uzantısı olana güvenirSize biraz zaman kazandırmak için bunu şu şekilde test edebilirsiniz:
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;
}
Varsayılan olarak gcc ve clang üzerinde çalışıyor gibi görünüyor; diğer derleyicileri test etmedi.
Bu oldukça eski bir soru, ama bunu göndermem gerektiğini düşünüyorum. GNU C99 için bir foreach döngüsüdür.
#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;
}
Bu kodun GNU / Linux üzerinde gcc, icc ve clang ile çalışması test edilmiştir.
C, her yapı için bir yapıya sahip olmasa da, her zaman bir dizinin sonunu geçen biri için deyimsel bir temsile sahip olmuştur (&arr)[1]. Bu, her döngü için aşağıdaki gibi basit bir deyim yazmanıza olanak tanır:
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
(&arr)[1]dizinin sonunu geçen bir dizi öğesi anlamına gelmez, dizinin sonunu geçen bir dizi anlamına gelir. (&arr)[1][0] dizisinin son öğesi değil, ilk öğeye (dizi [1]) göstericiye dönüşen [1] dizisidir. Ben çok daha iyi, daha güvenli ve deyimsel yapmak olacağına inanıyorum const int* begin = arr; const int* end = arr + sizeof(arr)/sizeof(*arr);o zaman ve for(const int* a = begin; a != end; a++).
C 'for' ve 'while' anahtar kelimelerine sahiptir. C # gibi bir dilde bir foreach ifadesi şöyle görünüyorsa ...
foreach (Element element in collection)
{
}
... o zaman bu foreach ifadesinin C'deki karşılığı şöyle olabilir:
for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}
İşte C ile takılıp kaldığımda kullandığım şey şu: Aynı öğe adını aynı kapsamda iki kez kullanamazsınız, ancak bu gerçekten bir sorun değil çünkü hepimiz güzel yeni derleyiciler kullanamayız :(
#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 */
Kullanımı:
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);
DÜZENLEME:FOREACH Ad alanı kirliliğini önlemek için c99 sözdizimini kullanmanın bir alternatifi :
#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)])dizi öğesi 0 değerine sahip olduğunda durur. Bu nedenle, bunu kullanmak double Array[]tüm öğeleri yinelemeyebilir. Görünüşe göre döngü testi şu veya bu olmalıdır: i<nveya A[i]. Anlaşılır olması için örnek kullanım durumları ekleyebilirsiniz.
if ( bla ) FOREACH(....) { } else....
FOREACHad alanı kirliliğini önlemek için c99 sözdizimini kullanan alternatif bir sürümüyle düzenleme özgürlüğüne sahip oldum .
Eric'in cevabı , "ara" veya "devam et" kullandığınızda işe yaramıyor.
Bu, ilk satırı yeniden yazarak düzeltilebilir:
Orijinal satır (yeniden biçimlendirilmiş):
for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)
Sabit:
for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)
Bunu Johannes'in döngüsüyle karşılaştırırsanız, aslında aynı şeyi yaptığını göreceksiniz, sadece biraz daha karmaşık ve daha çirkin.
İşte basit bir tane, tek for döngüsü:
#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
İsterseniz dizine ( i) ve üzerinde yinelediğimiz geçerli öğeye ( ) erişmenizi sağlar it. Döngüleri iç içe yerleştirirken adlandırma sorunları yaşayabileceğinizi unutmayın, öğe ve dizin adlarını makronun parametreleri yapabilirsiniz.
Düzenleme: İşte kabul edilen cevabın değiştirilmiş bir versiyonu foreach. Belirttiğiniz Lets startendeksi, sizebu nedenle çürük diziler (işaretçiler) üzerinde çalıştığı, gerek int*ve değiştirilemez count != sizeiçin i < sizeher ihtimale karşı kullanıcı yanlışlıkla değiştirir 'i' den büyük olması sizeve sonsuz döngüye takılıyorum.
#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);
Çıktı:
index: 2. element: 3
index: 3. element: 4
index: 4. element: 5
İşlev işaretçileriyle çalışmayı planlıyorsanız
#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)
Kullanımı:
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);
Ancak bunun yalnızca gcc üzerinde çalışacağını düşünüyorum (emin değilim).
C'nin bir uygulaması yoktur for-each. Bir diziyi nokta olarak ayrıştırırken, alıcı dizinin ne kadar uzun olduğunu bilmez, bu nedenle dizinin sonuna ne zaman ulaştığınızı söylemenin bir yolu yoktur. Unutma, C'deint* bir int içeren bir bellek adresine bir noktadır. Sırayla kaç tane tamsayı yerleştirildiği hakkında bilgi içeren bir başlık nesnesi yoktur. Bu nedenle, programcının bunu takip etmesi gerekir.
Bununla birlikte, listeler için bir for-eachdöngüye benzeyen bir şey uygulamak kolaydır .
for(Node* node = head; node; node = node.next) {
/* do your magic here */
}
Diziler için benzer bir şey elde etmek için iki şeyden birini yapabilirsiniz.
Aşağıda bu tür yapılara bir örnek verilmiştir:
typedef struct job_t {
int count;
int* arr;
} arr_t;
foreach" neyin?