Inisialisasi / reset struct ke nol / null


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

Saya mengisi struct ini dan kemudian menggunakan nilainya. Pada iterasi berikutnya, saya ingin mengatur ulang semua bidang ke 0atau nullsebelum saya mulai menggunakannya kembali.

Bagaimana saya bisa melakukan itu? Dapatkah saya menggunakan memsetatau saya harus melalui semua anggota dan kemudian melakukannya secara individu?

Jawaban:


109

Tentukan instance statis const dari struct dengan nilai awal dan kemudian cukup tetapkan nilai ini ke variabel Anda kapan pun Anda ingin menyetel ulang.

Sebagai contoh:

static const struct x EmptyStruct;

Di sini saya mengandalkan inisialisasi statis untuk menetapkan nilai awal saya, tetapi Anda dapat menggunakan penginisialisasi struct jika Anda menginginkan nilai awal yang berbeda.

Kemudian, setiap kali putaran Anda dapat menulis:

myStructVariable = EmptyStruct;

1
@David Heffernan: apakah ini lebih baik daripada menggunakan memsetjika saya hanya ingin mengatur ulang semuanya ke 0??
hari

9
@ari Saya lebih suka persetujuan ini sendiri. Menggunakan memsetmembuat saya merasa kotor. Saya lebih suka membiarkan kompiler khawatir tentang tata letak memori jika memungkinkan. Sebenarnya penggunaan semacam memsetitu tidak portabel tetapi dalam praktiknya saya akan terkejut jika Anda pernah menyusun kode Anda di mana saja yang penting. Jadi, Anda mungkin dapat menggunakan memset dengan aman jika Anda menginginkannya.
David Heffernan

2
@hari, secara konseptual lebih baik, karena Anda memberikan nilai inisialisasi default (sesuatu seperti pola pabrik objek.)
Diego Sevilla

1
@cnicutar Saya tahu ini. Perhatikan bahwa jawaban saya merekomendasikan untuk tidak menggunakan memset. Perhatikan juga komentar tentang di mana saya menunjukkan non-portabilitas menggunakan memset sebagai sarana untuk menetapkan nilai null. Komentar saya sebelumnya hanya menunjukkan kenyataan bahwa 0 bit selalu sesuai dengan angka nol floating point.
David Heffernan

1
@ kp11 kutipan please
David Heffernan

85

Cara untuk melakukan hal seperti itu bila Anda memiliki C modern (C99) adalah dengan menggunakan literal majemuk .

a = (const struct x){ 0 };

Ini agak mirip dengan solusi David, hanya saja Anda tidak perlu khawatir untuk mendeklarasikan struktur kosong atau apakah akan mendeklarasikannya static. Jika Anda menggunakan constseperti yang saya lakukan, kompilator bebas mengalokasikan literal gabungan secara statis dalam penyimpanan hanya-baca jika sesuai.


Apakah itu membuat instance x pada tumpukan untuk kemudian menyalinnya ke a? Untuk struktur besar / tumpukan kecil itu bisa jadi masalah.
Étienne

1
Seperti semua pengoptimalan, ini sepenuhnya bergantung pada compiler, jadi Anda harus memeriksa apa yang dihasilkan oleh compiler Anda. "Biasanya" pada kompiler modern tidak, ini dapat melacak inisialisasi dengan sangat baik dan hanya melakukan apa yang diperlukan, tidak lebih. (Dan jangan berpikir bahwa hal-hal seperti itu adalah masalah sebelum Anda mengukur perlambatan yang sebenarnya. Biasanya tidak.)
Jens Gustedt

3
Peringatan "penginisialisasi hilang" benar-benar palsu. Standar C mengatur dengan tepat apa yang harus terjadi daripada, dan menganggap { 0 }sebagai penginisialisasi default. Matikan peringatan itu, itu adalah alarm palsu.
Jens Gustedt

1
@JensGustedt Apakah typecasting ini benar-benar diperlukan? Tidak bisakah saya menulisnya seperti ini? struct xa = (const) {0};
Patrick

1
@Patrick, meskipun sintaksnya serupa, ini bukan pemeran tetapi "literal gabungan". Dan Anda mencampur inisialisasi dan tugas.
J Gustedt

58

Lebih baik dari semua di atas adalah menggunakan spesifikasi Standar C untuk inisialisasi struct:

struct StructType structVar = {0};

Ini semua bit nol (pernah).


13
Saya tidak berpikir Anda dapat melakukannya setiap kali dalam satu lingkaran
David Heffernan

2
Ini memang seharusnya berhasil. Namun sayangnya, gcc & g ++ mengeluhkannya. gcc menghasilkan peringatan, sedangkan g ++ menghasilkan kesalahan. Saya tahu bahwa gcc & g ++ salah dalam hal ini (mereka seharusnya mengikuti spesifikasi Standar C), tetapi meskipun demikian, untuk portabilitas yang baik, batasan tersebut wajib dipertimbangkan.
Cyan

3
@Cyan Anda dapat menggunakan {}C ++. Gcc devs tampaknya tidak yakin apakah C ++ seharusnya mendukung{0} dan saya sendiri tidak terbiasa dengan bagian standar itu.
Matius Baca

@Matthew: Ya, sebenarnya, saya akhirnya menggunakan memset (), karena ada terlalu banyak masalah portabilitas dengan {0}atau {}. Tidak yakin apakah standar C & C ++ jelas dan sinkron tentang masalah ini, tetapi tampaknya, kompiler tidak.
Cyan

apakah ini akan berhasil dalam kasus seperti itu? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

35

Di C, itu adalah idiom umum untuk menghilangkan memori untuk structpenggunaan memset:

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

Secara teknis, saya tidak percaya bahwa ini portabel karena mengasumsikan bahwa NULLpenunjuk pada mesin diwakili oleh nilai bilangan bulat 0, tetapi ini digunakan secara luas karena pada sebagian besar mesin demikian.

Jika Anda berpindah dari C ke C ++, berhati-hatilah untuk tidak menggunakan teknik ini pada setiap objek. C ++ hanya membuat ini legal pada objek tanpa fungsi anggota dan tidak ada warisan.


2
Standar C menyatakan bahwa NULL selalu 0. Jika mesin dirancang sedemikian rupa sehingga alamat tidak valid yang telah ditentukan sebelumnya tidak secara harfiah 0, kompilator untuk arsitektur itu harus menyesuaikan selama kompilasi.
Kevin M

9
@KevinM Ya, simbol "0" selalu sesuai dengan penunjuk NULL meskipun semuanya nol; tetapi tidak ada yang dapat dilakukan kompilator jika Anda menyetel bit ke nol menggunakan memset.
Adrian Ratnapala

"C ++ hanya membuat ini legal pada objek tanpa fungsi anggota dan tidak ada warisan." Ini tentang apakah jenisnya dianggap 'data lama biasa'. Kriteria bergantung pada versi bahasa C ++.
Max Barraclough

19

Jika Anda memiliki kompilator yang mendukung C99, Anda dapat menggunakan

mystruct = (struct x){0};

jika tidak, Anda harus melakukan apa yang ditulis David Heffernan, yaitu menyatakan:

struct x empty = {0};

Dan di loop:

mystruct = empty;

6

Anda dapat menggunakan memsetdengan ukuran struct:

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

1
Saya rasa pemeran tidak diperlukan di sini. Apakah itu?
templatetypedef

Yah, saya sangat terbiasa dengan C ++ sehingga ... yah, ini akan berfungsi juga di C ++, jadi saya tidak melihatnya sebagai beban.
Diego Sevilla

Ya, saya tidak cukup spesifik. Itu semua pointer ke cv berkualifikasi T dapat diubah ke cv kualifikasi void *. Setiap penunjuk data, penunjuk fungsi adalah masalah yang berbeda sama sekali. Kudos
@Kevin

memsetadalah sebuah opsi, tetapi saat menggunakannya, Anda harus memastikan bahwa memori yang ditulis sama ukurannya dengan parameter ketiga, oleh karena itu lebih baik merujuk ke ukuran objek sebenarnya, bukan ukuran jenis yang Anda gunakan. tahu itu saat ini. IOW memset (&x_instance, 0, sizeof(x_instance));adalah pilihan yang jauh lebih baik. BTW: (void*)pemerannya juga berlebihan di C ++.
Serigala

(maaf saya melewatkan untuk mengurus pertanyaan, lebih baik sekarang)
Wolf

4

Saya yakin Anda bisa menetapkan set kosong ( {}) ke variabel Anda.

struct x instance;

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

Ini bukan C yang valid, bahkan C99 pun tidak. Ini harus berupa literal majemuk seperti dalam jawaban JensGustedt di atas.
Anders

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

5
Saya pikir OP tahu bagaimana memanggil memset, tetapi masalahnya adalah apakah melakukannya bijaksana atau tidak
David Heffernan

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.