Tại sao khai báo một cấu trúc chỉ chứa một mảng trong C?


131

Tôi đã xem qua một số mã có chứa như sau:

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

Khi nào nó có ý nghĩa để sử dụng một tuyên bố như thế này?

Câu trả lời:


184

Nó cho phép bạn truyền mảng cho một hàm theo giá trị hoặc lấy nó trả về theo giá trị từ một hàm.

Các cấu trúc có thể được truyền theo giá trị, không giống như các mảng phân rã thành một con trỏ trong các bối cảnh này.


1
Cảnh giác với việc thực hiện điều này với các mảng, hơn 16 hoặc 32 byte, đối với các hàm không nội tuyến: sẽ hiệu quả hơn khi chuyển chúng bằng tham chiếu const, trừ khi callee đã cần một bản sao tmp mà nó có thể phá hủy. Nếu cuộc gọi / trả lại không tối ưu hóa đi, một mảng từ trung bình đến lớn (hàng nghìn byte) là một điều khủng khiếp để vượt qua giá trị.
Peter Cordes

84

Một ưu điểm khác là nó trừu tượng hóa kích thước để bạn không phải sử dụng [MAX]toàn bộ mã của mình bất cứ nơi nào bạn khai báo một đối tượng như vậy. Điều này cũng có thể đạt được với

typedef char ABC[MAX];

nhưng sau đó bạn có một vấn đề lớn hơn nhiều: bạn phải lưu ý rằng đó ABClà một kiểu mảng (mặc dù bạn không thể thấy điều này khi bạn khai báo các biến kiểu ABC) nếu không bạn sẽ bị choáng bởi thực tế điều đó ABCcó nghĩa khác trong một danh sách đối số chức năng so với trong một khai báo / định nghĩa biến.

Một lợi thế nữa là struct cho phép bạn sau đó thêm nhiều phần tử hơn nếu bạn cần, mà không phải viết lại nhiều mã.


45

Bạn có thể sao chép một cấu trúc và trả về một cấu trúc từ một chức năng.

Bạn không thể làm điều đó với một mảng - trừ khi nó là một phần của cấu trúc!


26

Bạn có thể sao chép nó như thế này.

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

Đối với một mảng, bạn sẽ cần sử dụng hàm memcpy hoặc một vòng lặp để gán từng phần tử.


6
(vì vậy nó cho phép mã sạch hơn - nó sẽ không tạo ra bất kỳ sự khác biệt nào về tốc độ, v.v.)
John Carter

3
Điều đó hữu ích. Thật không may, bạn không thể làm gì nếu (a == b)!?! làm thế nào không nhất quán đó là. Đối với C ++, nó tìm kiếm một toán tử ==. Trong C, nó nói "toán hạng không hợp lệ thành nhị phân ==".
Matt

11

Bạn có thể sử dụng struct để tạo một loại dữ liệu mới như chuỗi . bạn có thể định nghĩa:

struct String {
    char Char[MAX];
};

hoặc bạn có thể tạo Danh sách dữ liệu mà bạn có thể sử dụng theo đối số của hàm hoặc trả về trong phương thức của mình. Cấu trúc linh hoạt hơn một mảng, bởi vì nó có thể hỗ trợ một số toán tử như = và bạn có thể định nghĩa một số phương thức trong nó.

Hy vọng nó hữu ích cho bạn :)


2
Về cơ bản, đó là điều gần nhất C phải tạo ra một lớp. Tôi thích câu trả lời này vì nó gần nhất để chỉ ra điều đó.
Nate CK

1
Không có thứ gọi là phương thức trong C. structs trong C là dữ liệu cũ đơn giản. Nó có một toán tử = được hỗ trợ theo mặc định (mà các câu trả lời khác hiển thị là lý do để làm điều này), nhưng điều này gây hiểu lầm và chủ yếu áp dụng cho C ++, chứ không phải C.
Jonathan Sternberg

3
@J Sternberg: "Phương pháp" chỉ là cách suy nghĩ về chương trình con có liên quan đến "đối tượng" dữ liệu mà chúng ảnh hưởng. Bạn chắc chắn có thể tạo "lớp" của "đối tượng" và "phương thức" hoạt động trên chúng trong C. Ngôn ngữ chỉ không chính thức định nghĩa những thứ đó. Nếu bạn muốn tạo ra sự trừu tượng tốt hơn trong C, nhồi mọi thứ vào một cấu trúc thường là cách tốt nhất để làm điều đó.
Nate CK

Ngoài ra, nếu bạn thực sự muốn "tạo" các phương thức trong C, bạn có thể sử dụng các con trỏ hàm (có, có, cú pháp khó, không bảo vệ dữ liệu, v.v.) để liên kết các hàm với dữ liệu mà chúng hoạt động. Bạn phải truyền "tự" trong đối số đầu tiên (thậm chí bạn có thể đặt tên là "này", nếu bạn muốn), vì không có tự động tạo con trỏ này bên trong hàm trong C. Tất nhiên, đó là tất cả các môn thể dục dụng cụ, bạn có những thứ như thế này theo mặc định trong C ++, mặc dù đúng là có thể có phần thưởng ẩn như một phần thưởng ...
BenPen

2

Một ưu điểm khác của việc sử dụng như vậy structlà nó thực thi an toàn kiểu bất cứ nơi nào structsử dụng như vậy ; đặc biệt nếu bạn có hai loại bao gồm các mảng có cùng kích thước được sử dụng cho các mục đích khác nhau, những loại này sẽ giúp bạn tránh vô tình sử dụng một mảng không phù hợp.

Nếu bạn không bao bọc một mảng trong một struct, bạn vẫn có thể khai báo một mảng typedefcho nó: điều này có một số ưu điểm của struct- • loại được khai báo một lần, • kích thước được tự động sửa, • ý định của mã trở nên rõ ràng hơn, • và mã có thể duy trì nhiều hơn - nhưng bạn mất loại an toàn nghiêm ngặt, ability khả năng sao chép và trả về các giá trị của loại và ◦ khả năng thêm thành viên sau mà không phá vỡ phần còn lại của mã. Hai typedefs cho các mảng trần của một loại nhất định chỉ mang lại các loại khác nhau nếu chúng có kích thước khác nhau. Hơn nữa, nếu bạn sử dụng typedefmà không có *trong một đối số chức năng, thì nó tương đương với char *, làm giảm đáng kể sự an toàn kiểu.

Tóm lại :

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

Một cấu trúc có thể chứa các hàm khởi tạo mảng, sao chép và các hàm fini mô phỏng một số ưu điểm của mô hình quản lý bộ nhớ OOP. Trên thực tế, thật dễ dàng để mở rộng khái niệm này để viết một tiện ích quản lý bộ nhớ chung (bằng cách sử dụng cấu trúc sizeof () để biết chính xác có bao nhiêu byte đang được quản lý) để quản lý bất kỳ cấu trúc nào do người dùng xác định. Nhiều cơ sở mã sản xuất thông minh được viết bằng C sử dụng rất nhiều và thường không bao giờ sử dụng một mảng trừ khi phạm vi của nó rất cục bộ.

Trong thực tế đối với một mảng được nhúng trong một cấu trúc, bạn có thể thực hiện các "điều thông minh" khác như kiểm tra ràng buộc bất cứ lúc nào bạn muốn truy cập vào mảng này. Một lần nữa, trừ khi phạm vi mảng rất hạn chế, việc sử dụng nó và chuyển thông tin qua các chương trình là một ý tưởng tồi. Sớm hay muộn, bạn sẽ gặp phải những con bọ khiến bạn tỉnh táo vào ban đêm và làm hỏng những ngày cuối tuần của bạn.


Điều này không trả lời câu hỏi tại sao người ta có thể sử dụng chỉstruct chứa một mảng.
PJTraill
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.