Hampir semua bahasa memiliki foreach
lingkaran atau sesuatu yang serupa. Apakah C punya? Bisakah Anda memposting beberapa kode contoh?
foreach
loop dalam program C?
Hampir semua bahasa memiliki foreach
lingkaran atau sesuatu yang serupa. Apakah C punya? Bisakah Anda memposting beberapa kode contoh?
foreach
loop dalam program C?
Jawaban:
C tidak memiliki foreach, tetapi makro sering digunakan untuk meniru bahwa:
#define for_each_item(item, list) \
for(T * item = list->head; item != NULL; item = item->next)
Dan bisa digunakan seperti
for_each_item(i, processes) {
i->wakeup();
}
Iterasi melalui larik juga dimungkinkan:
#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)
Dan bisa digunakan seperti
int values[] = { 1, 2, 3 };
foreach(int *v, values) {
printf("value: %d\n", *v);
}
Edit: Jika Anda juga tertarik dengan solusi C ++, C ++ memiliki native untuk setiap sintaks yang disebut "berbasis rentang"
#define foreach(item, array) int count=0, size=sizeof(array)/sizeof(*(array)); for(item = (array); count != size; count++, item = (array)+count)
Satu masalah yang dapat saya lihat adalah bahwa jumlah dan ukuran variabel berada di luar loop for, dan mungkin menyebabkan konflik. Apakah ini alasan Anda menggunakan dua untuk loop? [kode ditempel di sini ( pastebin.com/immndpwS )]
if(...) foreach(int *v, values) ...
. Jika mereka berada di luar loop maka akan mengembang if(...) int count = 0 ...; for(...) ...;
dan akan putus.
Berikut adalah contoh program lengkap untuk setiap makro di 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[]
definisi? Tidak bisakah Anda menulis next
saja .next
?
free()
) dan untuk hal lain ia memiliki referensi ke nilai di dalam definisinya. Ini benar-benar contoh dari sesuatu yang terlalu pintar; kode cukup kompleks tanpa sengaja menambahkan kepintaran padanya. Pepatah Kernighan ( stackoverflow.com/questions/1103299/… ) berlaku!
Tidak ada foreach dalam C.
Anda dapat menggunakan perulangan for untuk mengulang melalui data tetapi panjangnya perlu diketahui atau data harus diakhiri dengan nilai yang diketahui (mis. Null).
char* nullTerm;
nullTerm = "Loop through my characters";
for(;nullTerm != NULL;nullTerm++)
{
//nullTerm will now point to the next character.
}
Seperti yang mungkin sudah Anda ketahui, tidak ada loop bergaya "foreach" di C.
Meskipun sudah ada banyak sekali makro hebat yang disediakan di sini untuk mengatasi hal ini, mungkin makro ini berguna bagi Anda:
// "length" is the length of the array.
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)
... yang dapat digunakan dengan for
(seperti dalam for each (...)
).
Keuntungan dari pendekatan ini:
item
dideklarasikan dan bertambah dalam pernyataan for (seperti di Python!).p
, item
), tidak terlihat di luar lingkup loop (karena mereka dideklarasikan di header loop for).Kekurangan:
typeof()
, yang merupakan ekstensi GNU, bukan bagian dari C standarHanya untuk menghemat waktu, berikut cara mengujinya:
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;
}
Sepertinya bekerja pada gcc dan clang secara default; belum menguji kompiler lain.
Ini adalah pertanyaan yang cukup lama, tetapi saya pikir saya harus memposting ini. Ini adalah foreach loop untuk 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;
}
Kode ini telah diuji untuk bekerja dengan gcc, icc dan clang di GNU / Linux.
Meskipun C tidak memiliki a untuk setiap konstruk, C selalu memiliki representasi idiomatik untuk salah satu dari akhir array (&arr)[1]
. Ini memungkinkan Anda untuk menulis idiomatik sederhana untuk setiap loop sebagai berikut:
int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
printf("%d\n", *a);
(&arr)[1]
tidak berarti satu item larik melewati akhir larik, itu berarti satu larik melewati akhir larik. (&arr)[1]
bukan item terakhir dari larik [0], ini adalah larik [1], yang meluruh menjadi penunjuk ke elemen pertama (dari larik [1]). Saya percaya akan jauh lebih baik, lebih aman dan idiomatis untuk dilakukan const int* begin = arr; const int* end = arr + sizeof(arr)/sizeof(*arr);
dan kemudian for(const int* a = begin; a != end; a++)
.
C memiliki kata kunci 'untuk' dan 'sementara'. Jika pernyataan foreach dalam bahasa seperti C # terlihat seperti ini ...
foreach (Element element in collection)
{
}
... maka padanan dari pernyataan foreach di C ini mungkin seperti:
for (
Element* element = GetFirstElement(&collection);
element != 0;
element = GetNextElement(&collection, element)
)
{
//TODO: do something with this element instance ...
}
Inilah yang saya gunakan ketika saya terjebak dengan C. Anda tidak dapat menggunakan nama item yang sama dua kali dalam lingkup yang sama, tetapi itu sebenarnya bukan masalah karena tidak semua dari kita dapat menggunakan kompiler baru yang bagus :(
#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 */
Pemakaian:
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: Berikut adalah alternatif untuk FOREACH
menggunakan sintaks c99 untuk menghindari polusi 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)])
akan berhenti setelah elemen array memiliki nilai 0. Jadi menggunakan ini dengan double Array[]
tidak dapat melakukan iterasi melalui semua elemen. Sepertinya tes loop harus salah satu atau yang lain: i<n
atau A[i]
. Mungkin menambahkan contoh kasus penggunaan untuk kejelasan.
if ( bla ) FOREACH(....) { } else....
FOREACH
yang menggunakan sintaks c99 untuk menghindari polusi namespace.
Jawaban Eric tidak berfungsi saat Anda menggunakan "istirahat" atau "lanjutkan".
Ini bisa diperbaiki dengan menulis ulang baris pertama:
Baris asli (diformat ulang):
for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)
Tetap:
for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)
Jika Anda membandingkannya dengan putaran Johannes, Anda akan melihat bahwa dia sebenarnya melakukan hal yang sama, hanya sedikit lebih rumit dan lebih buruk.
Ini yang sederhana, single for loop:
#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
Memberi Anda akses ke indeks jika Anda menginginkannya ( i
) dan item saat ini yang sedang kita iterasi ( it
). Perhatikan bahwa Anda mungkin memiliki masalah penamaan saat membuat loop bersarang, Anda dapat membuat item dan nama indeks menjadi parameter untuk makro.
Sunting: Berikut adalah versi modifikasi dari jawaban yang diterima foreach
. Memungkinkan Anda menentukan start
indeks, size
sehingga ia bekerja pada array yang membusuk (pointer), tidak perlu int*
dan diubah count != size
menjadi untuk i < size
berjaga-jaga jika pengguna secara tidak sengaja mengubah 'i' menjadi lebih besar dari size
dan terjebak dalam loop tak terbatas.
#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);
Keluaran:
index: 2. element: 3
index: 3. element: 4
index: 4. element: 5
Jika Anda berencana untuk bekerja dengan pointer fungsi
#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)
Pemakaian:
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);
Tapi saya pikir ini hanya akan berfungsi di gcc (tidak yakin).
C tidak memiliki implementasi for-each
. Saat mem-parsing array sebagai titik, penerima tidak mengetahui berapa panjang array tersebut, sehingga tidak ada cara untuk mengetahui kapan Anda mencapai akhir array. Ingat, di C int*
adalah titik ke alamat memori yang mengandung int. Tidak ada objek header yang berisi informasi tentang berapa banyak bilangan bulat yang ditempatkan secara berurutan. Jadi, programmer perlu melacak ini.
Namun, untuk list, mudah untuk mengimplementasikan sesuatu yang menyerupai for-each
loop.
for(Node* node = head; node; node = node.next) {
/* do your magic here */
}
Untuk mencapai sesuatu yang serupa untuk array, Anda dapat melakukan salah satu dari dua hal.
Berikut ini adalah contoh dari struct tersebut:
typedef struct job_t {
int count;
int* arr;
} arr_t;
foreach
" dari apa?