Khởi tạo / đặt lại cấu trúc thành không / null


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

Tôi đang điền vào cấu trúc này và sau đó sử dụng các giá trị. Trong lần lặp tiếp theo, tôi muốn đặt lại tất cả các trường thành 0hoặc nulltrước khi tôi bắt đầu sử dụng lại nó.

Làm thế nào tôi có thể làm điều đó? Tôi có thể sử dụng memsethay tôi phải thông qua tất cả các thành viên và sau đó làm điều đó riêng lẻ?

Câu trả lời:


109

Xác định một trường hợp tĩnh const của cấu trúc với các giá trị ban đầu và sau đó chỉ cần gán giá trị này cho biến của bạn bất cứ khi nào bạn muốn đặt lại nó.

Ví dụ:

static const struct x EmptyStruct;

Ở đây tôi dựa vào khởi tạo tĩnh để đặt các giá trị ban đầu của mình, nhưng bạn có thể sử dụng trình khởi tạo cấu trúc nếu bạn muốn các giá trị ban đầu khác nhau.

Sau đó, mỗi lần vòng lặp, bạn có thể viết:

myStructVariable = EmptyStruct;

1
@David Heffernan: điều này có tốt hơn là sử dụng memsetnếu tôi chỉ muốn đặt lại mọi thứ thành không 0??
hari,

9
@hari Tôi thích điều này tự tiếp cận hơn. Sử dụng memsetkhiến tôi cảm thấy bẩn. Tôi muốn để trình biên dịch lo lắng về bố trí bộ nhớ bất cứ khi nào có thể. Nói một cách chính xác việc sử dụng như vậy memsetlà không thể di động nhưng trên thực tế, tôi sẽ rất ngạc nhiên nếu bạn đã từng biên dịch mã của mình ở bất kỳ đâu quan trọng. Vì vậy, bạn có thể sử dụng memset một cách an toàn nếu muốn.
David Heffernan,

2
@hari, đó là khái niệm tốt hơn, như bạn cung cấp một giá trị khởi tạo mặc định (một cái gì đó giống như một mô hình nhà máy đối tượng.)
Diego Sevilla

1
@cnicutar Tôi biết điều này. Lưu ý rằng câu trả lời của tôi khuyên bạn không nên sử dụng memset. Cũng lưu ý nhận xét về nơi tôi chỉ ra tính không di động của việc sử dụng memset như một phương tiện để gán giá trị null. Nhận xét trước đây của tôi chỉ ra thực tế rằng các bit 0 luôn luôn tương ứng với các số không dấu phẩy động.
David Heffernan,

1
@ kp11 trích dẫn xin
David Heffernan

85

Cách để làm điều đó khi bạn có C (C99) hiện đại là sử dụng một từ ghép .

a = (const struct x){ 0 };

Điều này hơi giống với giải pháp của David, chỉ là bạn không phải lo lắng về việc khai báo cấu trúc trống hay có nên khai báo nó hay không static. Nếu bạn sử dụng constnhư tôi đã làm, trình biên dịch có thể tự do phân bổ hợp chất tĩnh theo nghĩa đen trong bộ nhớ chỉ đọc nếu thích hợp.


Điều đó có tạo ra một thể hiện của x trên ngăn xếp để sau đó sao chép nó vào a không? Đối với cấu trúc lớn / ngăn xếp nhỏ có thể là một vấn đề.
Étienne

1
Giống như tất cả các tối ưu hóa, điều này hoàn toàn phụ thuộc vào trình biên dịch, vì vậy bạn phải kiểm tra những gì trình biên dịch của bạn tạo ra. "Thông thường" trên các trình biên dịch hiện đại thì không, những trình biên dịch này có thể theo dõi quá trình khởi tạo rất tốt và chỉ làm những gì cần thiết, không hơn. (Và đừng nghĩ rằng những việc như vậy là vấn đề trước khi bạn đo một xuống chậm thực Họ thường thì không..)
Jens Gustedt

3
cảnh báo "thiếu bộ khởi tạo" thực sự không có thật. Tiêu chuẩn C quy định chính xác những gì phải xảy ra hơn là và lấy nó { 0 }làm trình khởi tạo mặc định. Tắt cảnh báo đó đi, đó là cảnh báo giả giả mạo.
Jens Gustedt

1
@JensGustedt Việc đánh máy này có thực sự cần thiết không? Tôi không thể viết nó như thế này? struct xa = (const) {0};
Patrick

1
@Patrick, mặc dù cú pháp tương tự, đây không phải là một kiểu ép kiểu mà là một "chữ ghép". Và bạn đang trộn lẫn khởi tạo và gán.
Jens Gustedt

58

Tốt hơn tất cả ở trên là sử dụng đặc tả C tiêu chuẩn để khởi tạo cấu trúc:

struct StructType structVar = {0};

Đây là tất cả các bit không (từng có).


13
Tôi không nghĩ rằng bạn có thể làm điều đó mỗi lần xung quanh một vòng lặp dù
David Heffernan

2
Điều này thực sự được cho là có hiệu quả. Nhưng thật không may, gcc & g ++ phàn nàn về nó. gcc tạo ra cảnh báo, trong khi g ++ tạo ra lỗi. Tôi biết rằng gcc & g ++ có lỗi về điều này (chúng được cho là tuân theo đặc điểm kỹ thuật Chuẩn C), nhưng dù sao, để có tính di động tốt, bắt buộc phải xem xét giới hạn đó.
Cyan

3
@Cyan Bạn có thể sử dụng {}trong C ++. Các nhà phát triển gcc dường như không chắc liệu C ++ có được hỗ trợ{0} hay không và bản thân tôi cũng không quen với phần đó của tiêu chuẩn.
Ma-thi-ơ Đọc

@Matthew: Vâng, thực ra, tôi đã kết thúc sử dụng memset (), vì có quá nhiều vấn đề về tính di động với {0}hoặc {}. Không chắc liệu các tiêu chuẩn C & C ++ có rõ ràng và đồng bộ về vấn đề này hay không, nhưng rõ ràng, các trình biên dịch thì không.
Cyan

điều này sẽ hoạt động trong trường hợp như vậy? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

34

Trong C, nó là một thành ngữ phổ biến để xóa bộ nhớ khi structsử dụng memset:

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

Về mặt kỹ thuật, tôi không tin rằng điều này là di động vì nó giả định rằng NULLcon trỏ trên máy được biểu thị bằng giá trị số nguyên 0, nhưng nó được sử dụng rộng rãi vì trên hầu hết các máy là trường hợp này.

Nếu bạn chuyển từ C sang C ++, hãy cẩn thận không sử dụng kỹ thuật này trên mọi đối tượng. C ++ chỉ làm cho điều này hợp pháp trên các đối tượng không có hàm thành viên và không có tính kế thừa.


2
Tiêu chuẩn C tuyên bố rằng NULL luôn bằng 0. Nếu máy được thiết kế sao cho địa chỉ không hợp lệ được xác định trước không phải là 0 theo nghĩa đen, trình biên dịch cho kiến ​​trúc đó phải điều chỉnh trong quá trình biên dịch.
Kevin M

8
@KevinM Có, ký hiệu "0" luôn tương ứng với con trỏ NULL ngay cả khi nó bằng 0; nhưng trình biên dịch không thể làm gì nếu bạn đặt các bit thành 0 bằng cách sử dụng memset.
Adrian Ratnapala

"C ++ chỉ làm cho điều này hợp pháp trên các đối tượng không có chức năng thành viên và không có tính kế thừa." Đó là về việc liệu loại có được coi là 'dữ liệu cũ thuần túy' hay không. Các tiêu chí phụ thuộc vào phiên bản của ngôn ngữ C ++.
Max Barraclough

19

Nếu bạn có trình biên dịch tuân thủ C99, bạn có thể sử dụng

mystruct = (struct x){0};

nếu không, bạn nên làm những gì David Heffernan đã viết, tức là tuyên bố:

struct x empty = {0};

Và trong vòng lặp:

mystruct = empty;

6

Bạn có thể sử dụng memsetvới kích thước của cấu trúc:

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

1
Tôi không nghĩ rằng dàn diễn viên là cần thiết ở đây. Là nó?
templatetypedef

Chà, tôi đã quá quen với C ++ nên ... tốt, nó cũng sẽ hoạt động trong C ++, vì vậy tôi không thấy nó là gánh nặng.
Diego Sevilla,

Vâng, tôi không đủ cụ thể. Bất kỳ con trỏ nào đến cv đủ tiêu chuẩn T đều có thể được chuyển đổi thành cv đủ điều kiện void *. Mọi con trỏ dữ liệu, con trỏ hàm hoàn toàn là một vấn đề khác. Kudos @Kevin
Marcus

memsetlà một tùy chọn, nhưng khi sử dụng nó, bạn phải đảm bảo rằng bộ nhớ được ghi vào có cùng kích thước chính xác với tham số thứ ba, đó là lý do tại sao tốt hơn nên tham khảo kích thước của đối tượng thực chứ không phải kích thước của loại bạn. biếthiện đang là. IOW memset (&x_instance, 0, sizeof(x_instance));là một lựa chọn tốt hơn nhiều. BTW: (void*)diễn viên cũng không cần thiết trong C ++.
Wolf

(xin lỗi tôi đã bỏ lỡ để chăm sóc các câu hỏi, nó tốt hơn bây giờ)
Wolf

5

Tôi tin rằng bạn có thể chỉ định tập hợp rỗng ( {}) cho biến của mình.

struct x instance;

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

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

5
Tôi nghĩ rằng OP biết làm thế nào để gọi memset, mà là vấn đề là có hay không làm như vậy là khôn ngoan
David Heffernan

-1

nhập mô tả hình ảnh ở đây Hãy lấy một điều bất ngờ từ gnu11!

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

TgotoData tmpData = { 0 };

không có gì là không.


1
Điều này không cố gắng trả lời câu hỏi "Làm thế nào tôi có thể đặt lại tất cả các lĩnh vực để 0"
MM
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.