Neden yalnızca C'de bir dizi içeren bir yapı bildirilsin?


131

Aşağıdakileri içeren bir kodla karşılaştım:

struct ABC {
    unsigned long array[MAX];
} abc;

Böyle bir beyanı kullanmak ne zaman mantıklı?

Yanıtlar:


184

Diziyi bir işleve değere göre iletmenize veya bir işlevden değere göre döndürmenize olanak tanır.

Yapılar, bu bağlamlarda bir göstericiye bozunan dizilerin aksine, değere göre geçirilebilir.


1
Bunu satır içi olmayan işlevler için 16 veya 32 bayttan daha fazla dizilerle yapmaya dikkat edin: aranan ucun yok edebileceği bir tmp kopyasına zaten ihtiyacı olmadığı sürece, bunları const referansıyla geçirmek daha etkilidir. Çağrı / geri dönüş optimize edilmezse, orta ila büyük bir dizi (binlerce bayt), değer olarak geçirilmesi korkunç bir şeydir.
Peter Cordes

85

Diğer bir avantajı, boyutu soyutlamasıdır, böylece [MAX]böyle bir nesneyi bildirdiğiniz her yerde kodunuzun her yerinde kullanmak zorunda kalmazsınız . Bu aynı zamanda

typedef char ABC[MAX];

ama sonra çok daha büyük bir probleminiz var: bunun ABCbir dizi türü olduğunun farkında olmalısınız (türdeki değişkenleri bildirdiğinizde bunu göremeseniz bile ABC), aksi takdirde ABCfarklı bir anlama geleceği gerçeğinden etkileneceksiniz. bir işlev bağımsız değişken listesinde ve bir değişken bildiriminde / tanımında.

Bir başka avantaj da, yapının daha sonra gerekirse çok sayıda kodu yeniden yazmak zorunda kalmadan daha fazla öğe eklemenize izin vermesidir.


45

Bir yapıyı kopyalayabilir ve bir işlevden bir yapı döndürebilirsiniz.

Bunu bir dizi ile yapamazsınız - bir yapının parçası olmadığı sürece!


26

Bunu bu şekilde kopyalayabilirsiniz.

struct ABC a, b;
........
a = b;

Bir dizi için, her bir öğeyi atamak için memcpy işlevi veya bir döngü kullanmanız gerekir .


6
(böylece daha temiz koda izin verir - hızda herhangi bir fark yaratmaz vb.)
John Carter

3
Bu yararlıdır. Maalesef yapamazsınız eğer (a == b)!?! bu ne kadar tutarsız. C ++ için bir == operatörü arar. C'de "ikili == için geçersiz işlenenler" diyor.
Matt

11

String gibi yeni bir veri türü oluşturmak için struct'ı kullanabilirsiniz . tanımlayabilirsiniz:

struct String {
    char Char[MAX];
};

veya işlevler bağımsız değişkeniyle kullanabileceğiniz veya yöntemlerinizde döndürebileceğiniz bir veri listesi oluşturabilirsiniz . Yapı bir diziden daha esnektir, çünkü = gibi bazı işleçleri destekleyebilir ve içinde bazı yöntemler tanımlayabilirsiniz.

Umarım sizin için yararlıdır :)


2
Temel olarak, C'nin bir sınıf yaratmaya en yakın şey budur. Bu cevabı beğendim çünkü buna en yakın olanı geliyor.
Nate CK

1
C'deki C yapılarında yöntem diye bir şey basit eski veriler değildir. Varsayılan olarak desteklenen bir = işlecine sahiptir (bunu yapmanın nedeni diğer yanıtlarda gösterilmektedir), ancak bu yanıltıcıdır ve çoğunlukla C için değil, C ++ için geçerlidir.
Jonathan Sternberg

3
@J Sternberg: "Yöntem", alt yordamları etkiledikleri veri "nesneleriyle" ilişkili olarak düşünmenin bir yolu. C de onlar üzerinde çalışan "nesnelerin" ve "yöntemlerin" "sınıflarını" kesinlikle oluşturabilirsiniz. Dil böyle şeyleri resmi olarak tanımlamaz. C'de daha iyi soyutlamalar yaratmak istiyorsanız, nesneleri bir yapıya doldurmak genellikle bunu yapmanın en iyi yoludur.
Nate CK

Ek olarak, C'de gerçekten yöntemler "oluşturmak" istiyorsanız, işlevleri üzerinde çalıştıkları verilerle ilişkilendirmek için işlev işaretçileri (evet, evet, zor sözdizimi, veri koruması yok, vb.) Kullanabilirsiniz. İlk argümanda "öz" kelimesini geçmek zorundasınız (isterseniz "bu" olarak da adlandırabilirsiniz), çünkü bu işaretçinin C'deki işlevin içinde otomatik olarak oluşturulması yoktur. Elbette, hepsi jimnastik, alırsınız. C ++ 'da varsayılan olarak böyle şeyler, ancak bir bonus olarak ek yükün gizli olabileceği doğru ...
BenPen

2

Bu tür bir kullanmanın bir diğer avantajı, structtam o tip güvenlik uygulayan bir yerde structkullanılan olduğu; özellikle farklı amaçlar için kullanılan aynı boyutta dizilerden oluşan iki türünüz varsa, bu türler yanlışlıkla bir diziyi uygunsuz bir şekilde kullanmaktan kaçınmanıza yardımcı olacaktır.

Bir diziyi a dizisini sarmazsanız struct, yine typedefde onun için bir tanımlayabilirsiniz: bunun bazı avantajları vardır struct- • tür bir kez bildirilir, • boyut otomatik olarak doğrudur, • kodun amacı netleşir, • ve kodun bakımı daha kolaydır - ancak ◦ sıkı tür güvenliğini, ◦ türdeki değerleri kopyalama ve döndürme yeteneğini ve ◦ daha sonra kodunuzun geri kalanını bozmadan üye ekleme yeteneğini kaybedersiniz. typedefBelirli bir türdeki çıplak diziler için iki s, yalnızca farklı boyutlarda iseler farklı türler verir. Dahası, bir işlev bağımsız değişkeninde typedefolmadan kullanırsanız *, bu char *tür güvenliğini büyük ölçüde azaltmaya eşdeğerdir .

Özetle :

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113

1

Bir yapı, OOP bellek yönetimi paradigmalarının bazı avantajlarını taklit eden dizi başlatma, kopyalama ve fini işlevlerini içerebilir. Aslında, bu kavramı, herhangi bir kullanıcı tanımlı yapıyı yönetmek için genel bir bellek yönetimi yardımcı programı yazmak için genişletmek (tam olarak kaç baytın yönetildiğini bilmek için sizeof () yapısını kullanarak) çok kolaydır. C'de yazılan akıllı üretim kod tabanlarının çoğu bunları yoğun bir şekilde kullanır ve kapsamı çok yerel olmadığı sürece genellikle bir dizi kullanmaz.

Aslında, bir yapıya gömülü bir dizi için, bu diziye her erişmek istediğinizde bağlı kontrol gibi başka "akıllı şeyler" yapabilirsiniz. Yine, dizi kapsamı çok sınırlı olmadığı sürece, onu kullanmak ve programlar arasında bilgi aktarmak kötü bir fikirdir. Er ya da geç, sizi geceleri uyanık tutacak ve hafta sonlarınızı mahvedecek böceklerle karşılaşacaksınız.


Bu, neden yalnızca bir dizi structiçeren bir dizinin kullanılabileceği sorusuna yanıt vermez .
PJTraill
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.