C99 standartlarıyla C diline eklenen öğelerden biri “flexible array members” (yapıların esnek dizi öğeleri). Bir “flexible array” bir yapı türünün son öğesi olarak olarak bildirilebiliyor:
1 2 3 4 |
struct Student{ int no; int grades[]; }; |
Yukarıda örnekte struct Student türünün ikinci ve son öğesinin boyut belirtilmeden bildirilen grades isimli bir int dizi (incomplete array type) olduğunu görüyorsunuz. Yapının bu öğesi için bir yer elde edilmediği sürece bu öğe yapı nesnesi içinde bir yer kaplamayacak. Aşağıdaki koda bakalım:
1 2 3 4 5 6 7 |
#include <stdio.h> int main() { printf("sizeof(int) = %zu\n", sizeof(int)); printf("sizeof(struct Student) = %zu\n", sizeof(struct Student)); } |
Kodu derleyip çalıştırdığınızda sizeof(int) ve sizeof(struct Student) değerlerinin aynı olduğunu göreceksiniz.
“flexible array” yapının son öğesi olmak zorunda. Örneğin aşağıdaki gibi bir bildirim geçersiz:
1 2 3 4 |
struct Student { int grades[]; //geçersiz int no; }; |
Peki yapının bu esnek dizi öğesini nasıl kullanacağız? Bir struct Student nesnesinin bellek alanını dinamik bellek işlevleriyle elde ederek “flexible array” öğemizin boyutunu programın çalışma zamanında belirleyebiliriz:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <stdio.h> #include <stdlib.h> int main() { size_t n; printf("kac not: "); scanf("%zu", &n); struct Student *p = (struct Student *) malloc(sizeof(struct Student) + n * sizeof(int)); //... } |
Esnek dizi özelliği olmasaydı öğe olan grades isimli dizinin boyutunu mümkün olduğunca büyük belirlemek zorunda kalacaktık:
1 2 3 4 5 6 |
#define MAX_NUMBER_OF_GRADES 20 struct Student { int no; int grades[MAX_NUMBER_OF_GRADES]; }; |
Yazacağımız kodda oluşturacağımız bazı struct Student nesneleri için muhtemelen, öğe olan dizinin yalnızca belirli sayıda elemanını kullanacağız. Bu da toplamda kullanılan bellek alanının gereksiz yere artması sonucunu doğuracak.
Yapıların esnek dizi öğelerine ilk değer verilemiyor. Aşağıdaki kod geçersiz:
1 2 3 4 5 6 7 8 9 |
struct Student { int no; int grades[]; }; int main() { struct Student s = { 12, {1, 5, 6, 7} }; //geçersiz } |
Ancak birçok derleyici böyle bir nesne tanımlamasına bir eklenti (extension) ile izin veriyor.
Esnek dizi öğesi içeren yapı nesneleri birbirine atama işleciyle atandığında esnek dizi öğeleri birbirine kopyalanmaz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <stdlib.h> #include <stdio.h> typedef struct { int age; char name[]; }Person; int main() { Person *p1 = (Person *)malloc(sizeof(Person) + 6); Person *p2 = (Person *)malloc(sizeof(Person) + 6); if (!p1 || !p2) return; p1->age = 35; strcpy(p1->name, "Kemal"); p2->age = 45; strcpy(p2->name, "Murat"); *p1 = *p2; printf("%d %s\n", p1->age, p1->name); //45 Kemal free(p1); free(p2); } |
Esnek dizi öğesinin kopyalanması için standart strcpy ya da memcpy işlevlerini çağırabiliriz.
Bu aracın C99 standartları ile dile eklenmesinden önce, esnek dizi öğesi kullanmak ancak derleyicinin sağladığı eklentilerle mümkündü. Derleyiciler tarafından sunulan tipik eklentilerden biri yapının son öğesinin boyutu 0 olan bir dizi olarak bildirilebilmesi:
1 2 3 4 |
struct Student { int id; int grades[0]; }; |
C++ dilinin sentaksında “flexible array member” yer almıyor.