Yapıyı sıfır / null olarak başlat / sıfırla


92
struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

Bu yapıyı dolduruyorum ve sonra değerleri kullanıyorum. Bir sonraki yinelemede, tüm alanları yeniden kullanmaya başlamadan önce 0veya nullönce sıfırlamak istiyorum .

Bunu nasıl yapabilirim? Kullanabilir miyim memsetyoksa tüm üyelerin üzerinden geçip sonra bireysel olarak mı yapmalıyım?

Yanıtlar:


109

Yapının const statik örneğini başlangıç ​​değerleriyle tanımlayın ve ardından bu değeri sıfırlamak istediğinizde değişkeninize atayın.

Örneğin:

static const struct x EmptyStruct;

Burada ilk değerlerimi ayarlamak için statik başlatmaya güveniyorum , ancak farklı başlangıç ​​değerleri istiyorsanız bir yapı başlatıcı kullanabilirsiniz.

Ardından, döngü boyunca her seferinde yazabilirsiniz:

myStructVariable = EmptyStruct;

1
@David Heffernan: Bu, memsether şeyi sıfırlamak istiyorsam kullanmaktan daha mı iyi 0??
hari

9
@hari bu yaklaşımı kendim tercih ederim. Kullanmak memsetbeni kirli hissettiriyor. Derleyicinin mümkün olan her yerde bellek düzeni konusunda endişelenmesine izin vermeyi tercih ederim. Kesinlikle bu tür bir kullanım memsettaşınabilir değildir, ancak pratikte kodunuzu önemli olan herhangi bir yerde derlediyseniz şaşırırdım. Yani, tercih ederseniz, memset'i muhtemelen güvenle kullanabilirsiniz.
David Heffernan

2
@hari, varsayılan başlatma değerleri sağladığınız için kavramsal olarak daha iyidir (bir nesne fabrikası modeli gibi bir şey.)
Diego Sevilla

1
@cnicutar Bunu biliyorum. Cevabımın memset kullanmamayı önerdiğini unutmayın. Memset'i boş değerler atamak için bir araç olarak kullanmanın taşınabilir olmamasına işaret ettiğim yerle ilgili yorumu da not edin. Önceki yorumum, 0 bitin her zaman kayan noktalı sıfırlara karşılık geldiği gerçeğine işaret ediyor.
David Heffernan

1
@ kp11 citation please
David Heffernan

85

Modern C'ye (C99) sahip olduğunuzda böyle bir şeyi yapmanın yolu, bir bileşik değişmez kullanmaktır .

a = (const struct x){ 0 };

Bu biraz David'in çözümüne benziyor, sadece boş bir yapıyı ya da onu ilan edip etmeme konusunda endişelenmenize gerek yok static. constBenim yaptığım gibi kullanırsanız, derleyici, uygunsa, bileşiği tam anlamıyla statik olarak salt okunur depolamaya ayırmakta özgürdür.


Bu, yığında bir x örneğini oluşturup daha sonra onu a'ya kopyalar mı? Sorun olabilecek büyük yapılar / küçük yığınlar için.
Étienne

1
Tüm optimizasyonlar gibi, bu tamamen derleyiciye bağlıdır, bu nedenle derleyicinizin ne ürettiğini kontrol etmeniz gerekir. Modern derleyicilerde "genellikle" bunu yapmaz, bunlar ilklendirmeleri çok iyi izleyebilir ve sadece gerekli olanı yapabilir, daha fazlasını değil. (Ve gerçek bir yavaşlamayı
ölçmeden

3
"eksik başlatıcı" uyarıları gerçekten sahtedir. C standardı, tam olarak ne olması gerektiğini belirtir { 0 }ve varsayılan başlatıcı olarak öngörür . Bu uyarıyı kapatın, bu sahte yanlış alarmdır.
Jens Gustedt

1
@JensGustedt Bu tip döküm gerçekten gerekli mi? Bunu böyle yazamaz mıyım? struct xa = (sabit) {0};
Patrick

1
@Patrick, sözdizimi benzer olsa da, bu bir döküm değil, bir "bileşik literal" dir. Ve başlatma ve atamayı karıştırıyorsunuz.
Jens Gustedt

58

Yukarıdakilerden daha iyisi, yapı başlatma için Standart C spesifikasyonunu kullanmaktır:

struct StructType structVar = {0};

İşte tüm bitler sıfır (hiç).


13
Bunu her seferinde bir döngü etrafında yapabileceğinizi sanmıyorum
David Heffernan

2
Bunun gerçekten işe yaraması gerekiyor. Ama maalesef gcc & g ++ bundan şikayet ediyor. gcc uyarılar üretirken, g ++ bir hata oluşturur. Gcc & g ++ 'nın bu konuda hatalı olduğunu biliyorum (Standart C spesifikasyonuna uymaları gerekiyor), ancak yine de iyi bir taşınabilirlik için bu tür sınırlamaları dikkate almak zorunludur.
Mavi

3
@Cyan {}C ++ ' da kullanabilirsiniz . Gcc geliştiricileri , C ++ 'nın desteklemesi gerekip gerekmediğinden emin{0} görünmüyor ve ben standardın bu kısmına aşina değilim.
Matthew

@Matthew: Evet, aslında memset () kullandım, çünkü {0}veya ile çok fazla taşınabilirlik sorunu vardı {}. C & C ++ standartlarının bu konuda açık ve uyumlu olup olmadığından emin değilim, ancak görünüşe göre derleyiciler öyle değil.
Camgöbeği

bu böyle bir durumda işe yarar mı? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

35

C, bir hafıza üzerinden sıfıra ortak bir deyim olan structkullanılarak memset:

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

Teknik olarak konuşursak, bunun taşınabilir olduğuna inanmıyorum çünkü NULLbir makinedeki işaretçinin tamsayı değeri 0 ile temsil edildiğini varsayıyor , ancak yaygın olarak kullanılıyor çünkü çoğu makinede durum böyledir.

C'den C ++ 'ya geçerseniz, bu tekniği her nesnede kullanmamaya dikkat edin. C ++ bunu yalnızca üye işlevi olmayan ve kalıtım içermeyen nesnelerde yasal hale getirir.


2
C standardı, NULL'un her zaman 0 olduğunu belirtir. Makine, önceden belirlenmiş geçersiz bir adres tam anlamıyla 0 olmayacak şekilde tasarlandıysa, bu mimari için derleyicinin derleme sırasında ayar yapması gerekir.
Kevin M

9
@KevinM Evet, "0" sembolü, hepsi sıfır olsa bile her zaman NULL işaretçisine karşılık gelir; ancak memset kullanarak bitleri sıfıra ayarlarsanız derleyicinin yapabileceği hiçbir şey yoktur.
Adrian Ratnapala

"C ++ bunu yalnızca üye işlevi ve kalıtımı olmayan nesnelerde yasal hale getirir." Bu, türün "düz eski veri" olarak kabul edilip edilmediğiyle ilgilidir. Kriterler, C ++ dilinin sürümüne bağlıdır.
Maksimum Barraclough

19

C99 uyumlu bir derleyiciniz varsa, şunu kullanabilirsiniz:

mystruct = (struct x){0};

aksi takdirde David Heffernan'ın yazdıklarını yapmalısınız, yani şunu beyan edin:

struct x empty = {0};

Ve döngüde:

mystruct = empty;

6

memsetYapının boyutu ile kullanabilirsiniz :

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));

1
Burada oyuncu kadrosunun gerekli olduğunu sanmıyorum. Bu mu?
templatetypedef

Şey, C ++ 'ya o kadar alıştım ki ... iyi, C ++' da da çalışacak, bu yüzden bunu bir yük olarak görmüyorum.
Diego Sevilla

Evet, yeterince spesifik değildim. Herhangi bir gösterici cv nitelikli T'ye dönüştürülebilir cv nitelikli void *. Herhangi bir veri işaretçisi, işlev işaretçisi tamamen farklı bir konudur. Kudos @Kevin
Marcus Borkenhagen

memsetBir seçenek, ama bunu kullanırken, daha iyidir neden gerçek nesnenin büyüklüğü değil, harflerin büyüklüğü başvurmak için bu üçüncü parametre olarak aynı boyutta tam olarak hafıza yazılı emin olmak zorunda sen biliyorum o anda olduğunu. IOW memset (&x_instance, 0, sizeof(x_instance));çok daha iyi bir seçimdir. BTW: (void*)döküm C ++ 'da da gereksizdir.
Wolf

(özür dilerim soruya bakmayı özledim, şimdi daha iyi)
Wolf

4

{}Değişkeninize boş set ( ) atayabileceğinize inanıyorum .

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}

Bu geçerli C değil, C99 bile değil. Yukarıdaki JensGustedt'in cevabında olduğu gibi birleşik bir literal olması gerekir.
Anders

0
 struct x myX;
 ...
 memset(&x, 0, sizeof(myX));

5
Bence OP, memset'i nasıl arayacağını biliyor, ancak asıl mesele bunu yapmanın akıllıca olup olmadığı
David Heffernan

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.