เริ่มต้น / รีเซ็ตโครงสร้างเป็นศูนย์ / ศูนย์


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

ฉันเติมโครงสร้างนี้แล้วใช้ค่า ในการทำซ้ำครั้งถัดไปฉันต้องการรีเซ็ตฟิลด์ทั้งหมดเป็น0หรือnullก่อนที่จะเริ่มใช้ซ้ำ

ฉันจะทำเช่นนั้นได้อย่างไร? ใช้ได้memsetไหมหรือต้องผ่านสมาชิกทั้งหมดแล้วทำทีละคน

คำตอบ:


109

กำหนดอินสแตนซ์แบบคงที่ของโครงสร้างด้วยค่าเริ่มต้นจากนั้นกำหนดค่านี้ให้กับตัวแปรของคุณเมื่อใดก็ตามที่คุณต้องการรีเซ็ต

ตัวอย่างเช่น:

static const struct x EmptyStruct;

ที่นี่ฉันอาศัยการเริ่มต้นแบบคงที่เพื่อตั้งค่าเริ่มต้นของฉัน แต่คุณสามารถใช้ตัวเริ่มต้นโครงสร้างได้หากคุณต้องการค่าเริ่มต้นที่แตกต่างกัน

จากนั้นทุกครั้งที่วนรอบคุณสามารถเขียน:

myStructVariable = EmptyStruct;

1
@David Heffernan: ดีกว่าใช้memsetถ้าฉันต้องการรีเซ็ตทุกอย่างเป็นเท่านั้น0??
hari

9
@hari ฉันต้องการที่จะยอมรับตัวเองมากกว่านี้ การใช้memsetทำให้ฉันรู้สึกสกปรก ฉันชอบให้คอมไพเลอร์กังวลเกี่ยวกับเค้าโครงหน่วยความจำทุกที่ที่เป็นไปได้ การพูดอย่างเคร่งครัดว่าการใช้งานดังกล่าวmemsetไม่สามารถพกพาได้ แต่ในทางปฏิบัติฉันจะประหลาดใจถ้าคุณเคยรวบรวมรหัสของคุณในทุกที่ที่มีความสำคัญ ดังนั้นคุณสามารถใช้ memset ได้อย่างปลอดภัยหากต้องการ
David Heffernan

2
@hari เป็นแนวคิดที่ดีกว่าเนื่องจากคุณระบุค่าเริ่มต้นเริ่มต้น (บางอย่างเช่นรูปแบบโรงงานวัตถุ)
Diego Sevilla

1
@cnicutar ฉันรู้เรื่องนี้ โปรดทราบว่าคำตอบของฉันไม่แนะนำให้ใช้ memset โปรดสังเกตความคิดเห็นเกี่ยวกับจุดที่ฉันชี้ให้เห็นถึงการไม่สามารถพกพาได้ของการใช้ memset เป็นวิธีการกำหนดค่า null ความคิดเห็นก่อนหน้าของฉันเพียงแค่ชี้ให้เห็นถึงความเป็นจริงที่ว่า 0 บิตสอดคล้องกับเลขศูนย์ลอยตัว
David Heffernan

1
@ kp11 โปรดอ้างอิง
David Heffernan

85

วิธีที่จะทำสิ่งเช่นเมื่อคุณมี C ทันสมัย (C99) คือการใช้ตัวอักษรผสม

a = (const struct x){ 0 };

staticนี้จะค่อนข้างคล้ายกับวิธีการแก้ปัญหาของดาวิดเดียวที่คุณจะได้ไม่ต้องกังวลการประกาศโครงสร้างว่างเปล่าหรือว่าจะประกาศว่า หากคุณใช้constตามที่ฉันทำคอมไพลเลอร์มีอิสระที่จะจัดสรรสารประกอบตามตัวอักษรแบบคงที่ในหน่วยเก็บข้อมูลแบบอ่านอย่างเดียวหากเหมาะสม


นั่นสร้างอินสแตนซ์ของ x บนสแต็กเพื่อคัดลอกไปยัง a หรือไม่? สำหรับโครงสร้างขนาดใหญ่ / กองเล็กที่อาจเป็นปัญหาได้
Étienne

1
เช่นเดียวกับการเพิ่มประสิทธิภาพทั้งหมดนี่ขึ้นอยู่กับคอมไพเลอร์อย่างสมบูรณ์ดังนั้นคุณต้องตรวจสอบว่าคอมไพเลอร์ของคุณสร้างอะไร "โดยปกติ" ในคอมไพเลอร์สมัยใหม่ไม่สามารถติดตามการเริ่มต้นได้เป็นอย่างดีและทำเฉพาะในสิ่งที่จำเป็นเท่านั้น (และอย่าคิดว่าสิ่งนั้นเป็นปัญหาก่อนที่คุณจะวัดการชะลอตัวลงจริง ๆ โดยปกติแล้วจะไม่เป็นเช่นนั้น)
Jens Gustedt

3
คำเตือน "ตัวเริ่มต้นที่ขาดหายไป" ถือเป็นการหลอกลวงจริงๆ มาตรฐาน C กำหนดสิ่งที่จะต้องเกิดขึ้นอย่างแน่นอนและมองข้าม{ 0 }การเริ่มต้นเป็นค่าเริ่มต้น ปิดการเตือนนั้นเป็นการเตือนที่ผิดพลาด
Jens Gustedt

1
@JensGustedt การพิมพ์นี้จำเป็นจริงๆหรือ? ฉันเขียนแบบนี้ไม่ได้เหรอ? โครงสร้าง xa = (const) {0};
Patrick

1
@Patrick แม้ว่าไวยากรณ์จะคล้ายกัน แต่นี่ไม่ใช่การร่าย แต่เป็น "ตัวอักษรผสม" และคุณกำลังผสมการเริ่มต้นและการมอบหมายงาน
Jens Gustedt

58

ดีกว่าที่กล่าวมาทั้งหมดคือการใช้ข้อกำหนดมาตรฐาน C สำหรับการเริ่มต้นโครงสร้าง:

struct StructType structVar = {0};

นี่คือศูนย์บิตทั้งหมด (เคย)


13
ฉันไม่คิดว่าคุณจะทำได้ทุกครั้งที่วนรอบ
David Heffernan

2
นี่เป็นเรื่องจริงที่จะได้ผล แต่น่าเสียดายที่ gcc & g ++ บ่นเรื่องนี้ gcc สร้างคำเตือนในขณะที่ g ++ สร้างข้อผิดพลาด ฉันรู้ว่า gcc & g ++ เป็นฝ่ายผิดในเรื่องนี้ (ควรเป็นไปตามข้อกำหนดมาตรฐาน C) แต่อย่างไรก็ตามเพื่อความสะดวกในการพกพาจึงจำเป็นต้องคำนึงถึงข้อ จำกัด ดังกล่าว
สีฟ้า

3
@Cyan คุณสามารถใช้{}ใน C ++ gcc devs ดูเหมือนไม่แน่ใจว่า C ++ ควรจะรองรับ{0}หรือไม่และฉันไม่คุ้นเคยกับส่วนนั้นของมาตรฐานด้วยตัวเอง
Matthew อ่าน

@ Matthew: ใช่จริงฉันสิ้นสุดการใช้ memset () เพราะมีปัญหาการพกพามากเกินไปด้วยหรือ{0} {}ไม่แน่ใจว่ามาตรฐาน C & C ++ มีความชัดเจนและซิงค์กับปัญหานี้หรือไม่ แต่ดูเหมือนว่าคอมไพเลอร์ไม่ใช่
Cyan

จะได้ผลในกรณีนี้หรือไม่? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

35

ใน C มันเป็นสำนวนทั่วไปที่จะทำให้หน่วยความจำเหลือศูนย์สำหรับการstructใช้memset:

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

ในทางเทคนิคฉันไม่เชื่อว่าสิ่งนี้เป็นแบบพกพาเพราะถือว่าNULLตัวชี้บนเครื่องแสดงด้วยค่าจำนวนเต็ม 0 แต่ใช้กันอย่างแพร่หลายเนื่องจากในเครื่องส่วนใหญ่เป็นกรณีนี้

หากคุณย้ายจาก C ไปยัง C ++ ระวังอย่าใช้เทคนิคนี้กับทุกวัตถุ C ++ ทำให้สิ่งนี้ถูกกฎหมายเฉพาะกับวัตถุที่ไม่มีฟังก์ชันสมาชิกและไม่มีการสืบทอด


2
มาตรฐาน C ระบุว่า NULL เป็น 0 เสมอหากเครื่องได้รับการออกแบบให้แอดเดรสที่ไม่ถูกต้องที่กำหนดไว้ล่วงหน้าไม่ใช่ 0 ตามตัวอักษรคอมไพลเลอร์สำหรับสถาปัตยกรรมนั้นจะต้องปรับแต่งระหว่างการคอมไพล์
Kevin M

9
@KevinM ใช่สัญลักษณ์ "0" จะตรงกับตัวชี้ NULL เสมอแม้ว่าจะเป็นศูนย์ทั้งหมดก็ตาม แต่ไม่มีอะไรที่คอมไพเลอร์สามารถทำได้หากคุณตั้งค่าบิตเป็นศูนย์โดยใช้ memset
Adrian Ratnapala

"C ++ ทำให้สิ่งนี้ถูกกฎหมายเฉพาะกับออบเจ็กต์ที่ไม่มีฟังก์ชันสมาชิกและไม่มีการสืบทอด" เกี่ยวกับว่าประเภทนั้นถือเป็น 'ข้อมูลเก่าธรรมดา' หรือไม่ เกณฑ์ขึ้นอยู่กับเวอร์ชันของภาษา C ++
Max Barraclough

19

หากคุณมีคอมไพเลอร์ที่สอดคล้องกับ C99 คุณสามารถใช้ไฟล์

mystruct = (struct x){0};

มิฉะนั้นคุณควรทำตามที่ David Heffernan เขียนเช่นประกาศ:

struct x empty = {0};

และในวง:

mystruct = empty;

6

คุณสามารถใช้memsetกับขนาดของโครงสร้าง:

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

1
ฉันไม่คิดว่านักแสดงจำเป็นที่นี่ ใช่ไหม?
templatetypedef

อืมฉันชินกับ C ++ มากแล้วว่า ... มันจะทำงานใน C ++ ได้ด้วยดังนั้นฉันจึงไม่เห็นว่ามันเป็นภาระ
Diego Sevilla

ใช่ฉันไม่เจาะจงมากพอ เป็นตัวชี้ใด ๆ ของ cv ที่มีคุณสมบัติ T สามารถแปลงเป็น void ที่มีคุณสมบัติ cv ได้ * ตัวชี้ข้อมูลใด ๆ ตัวชี้ฟังก์ชันเป็นเรื่องที่แตกต่างกันโดยสิ้นเชิง Kudos
@Kevin

memsetเป็นตัวเลือกหนึ่ง แต่เมื่อใช้งานคุณต้องตรวจสอบให้แน่ใจว่าหน่วยความจำที่เขียนลงไปนั้นมีขนาดเท่ากับพารามิเตอร์ที่สามทุกประการนั่นเป็นเหตุผลว่าทำไมจึงควรอ้างถึงขนาดของวัตถุจริงไม่ใช่ขนาดของประเภทที่คุณ รู้ว่าปัจจุบันเป็น IOW memset (&x_instance, 0, sizeof(x_instance));เป็นทางเลือกที่ดีกว่ามาก BTW: (void*)นักแสดงยังไม่จำเป็นใน C ++ ด้วย
Wolf

(ขออภัยฉันพลาดที่จะดูแลคำถามตอนนี้ดีกว่า)
Wolf

4

ฉันเชื่อว่าคุณสามารถกำหนด set ว่าง ( {}) ให้กับตัวแปรของคุณได้

struct x instance;

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

นี่ไม่ใช่ C ที่ถูกต้องไม่ใช่แม้แต่ C99 ต้องเป็นสารประกอบตามตัวอักษรเหมือนในคำตอบของ JensGustedt ข้างต้น
Anders

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

5
ฉันคิดว่า OP รู้วิธีเรียก memset แต่ปัญหาคือว่าการทำเช่นนั้นฉลาดหรือไม่
David Heffernan

-1

ใส่คำอธิบายภาพที่นี่เซอร์ไพรส์จาก gnu11!

typedef struct {
    uint8_t messType;
    uint8_t ax;  //axis
    uint32_t position;
    uint32_t velocity;
}TgotoData;

TgotoData tmpData = { 0 };

ไม่มีอะไรเป็นศูนย์


1
สิ่งนี้ไม่ได้พยายามตอบคำถาม "ฉันจะรีเซ็ตฟิลด์ทั้งหมดเป็น 0 ได้อย่างไร"
MM
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.