Điều gì đặc biệt về cấu trúc?


81

Tôi biết rằng trong C, chúng ta không thể trả về một mảng từ một hàm mà là một con trỏ tới một mảng. Nhưng tôi muốn biết điều đặc biệt là gì structskhiến chúng có thể trả về bởi các hàm mặc dù chúng có thể chứa các mảng.

Tại sao structgói làm cho chương trình sau hợp lệ?

#include <stdio.h>

struct data {
    char buf[256];
};

struct data Foo(const char *buf);

int main(void)
{
    struct data obj;
    obj = Foo("This is a sentence.");
    printf("%s\n", obj.buf);
    return 0;
}

struct data Foo(const char *buf)
{
    struct data X;
    strcpy(X.buf, buf);
    return X;
}

1
Bạn có thể làm điều tương tự với a union. Nghiệp đoàn có gì đặc biệt?
user253751

19
Bạn chứ không nên tự hỏi tại sao các mảng rất lạ trong C.
CodesInChaos

khi trả về một cấu trúc, nếu cấu trúc không vừa với một vài thanh ghi, thì một bộ nhớ 'ẩn' do trình biên dịch cấp phát, cấu trúc được sao chép (thông qua memcpy ()) vào bộ nhớ ẩn rồi lại được sao chép (thông qua memcpy ( )) biến cấu trúc của ông ta gọi. Bộ nhớ 'ẩn' đó bị mất cho tất cả các chức năng khác. Hai cuộc gọi thêm để memcpy()và sự mất mát của 'ẩn' bộ nhớ là lý do chính mà một struct không nên passed tovà cũng không returned frommột hàm. Chính sách tốt nhất là chuyển một con trỏ đến cấu trúc.
user3629249

không có câu trả lời nào trong số ba câu trả lời đề cập đến việc truyền một cấu trúc, (đúng hơn là chúng chỉ thảo luận về việc truyền các mảng), nhưng chúng không trả lời câu hỏi.
user3629249

1
@ user3629249 - không thể trả lời câu hỏi vì câu hỏi được đặt ra trước khi thiếu hiểu biết. Cách duy nhất để trả lời câu hỏi là cố gắng giải thích tại sao câu hỏi đó không thể được hỏi. Hãy tưởng tượng nếu tôi hỏi bạn "Tại sao màu Xanh lại giống màu Đỏ?" Bạn sẽ nhanh chóng giải thích tại sao bạn không thể trả lời câu hỏi.
Hogan

Câu trả lời:


100

Một cách tốt hơn để hỏi cùng một câu hỏi sẽ là "điều gì đặc biệt về mảng", vì đó là các mảng có cách xử lý đặc biệt gắn liền với chúng, không phải structs.

Hành vi truyền và trả lại mảng bằng con trỏ theo dấu vết của việc triển khai ban đầu C. Mảng "phân rã" thành con trỏ, gây ra nhiều nhầm lẫn, đặc biệt là ở những người mới làm quen với ngôn ngữ này. Mặt khác, các cấu trúc hoạt động giống như các kiểu dựng sẵn, chẳng hạn như ints, doubles, v.v. Điều này bao gồm bất kỳ mảng nào được nhúng trong struct, ngoại trừ các thành viên mảng linh hoạt , không được sao chép.


4
thực sự 'gây ra nhiều sự nhầm lẫn'. 'x' và '& x' có cùng giá trị / địa chỉ là một điều điên rồ. Nó không ngạc nhiên rằng newbs nhận sai về mình :(
Martin James

1
Trí nhớ của tôi có thể đang lừa dối tôi, nhưng có phải đã có lúc không thể chuyển structtừng giá trị không?
alk

5
@alk Tôi nghĩ, khi các cấu trúc lần đầu tiên được thêm vào ngôn ngữ, ban đầu có một số hạn chế trong việc chuyển chúng đến / trả lại chúng từ các hàm, nhưng chúng được đánh dấu rõ ràng là một thiếu sót trong trình biên dịch đã sớm được sửa chữa, không phải là một dấu hiệu rằng có bất cứ điều gì sai khi muốn chuyển và trả lại chúng.
Steve Summit

8
@jamesqf: struct Point {short x, y, z;};. Bạn thực sự muốn sử dụng con trỏ để di chuyển chúng? Bạn chắc chắn không tiết kiệm không gian theo cách này.
Đánh dấu VY

6
@jamesqf Tôi không chắc điều này xứng đáng nhận được phản hồi. Nếu bạn tin rằng C không hơn nhiều so với assembly, nếu bạn tin rằng không bao giờ có lý do gì để không sử dụng con trỏ, tôi có thể thấy bạn có thể nghĩ rằng việc truyền cấu trúc là vô ích. Nhưng đối với phần còn lại của chúng ta, những người coi C như một ngôn ngữ cấp cao (mặc dù là ngôn ngữ cấp thấp, như HLL), và những người coi hệ thống kiểu của C là chung (với ngoại lệ được lưu ý là trạng thái cấp hai của mảng ), tại sao chúng ta không muốn chuyển hoặc trả về cấu trúc? (BTW, IIRC, K & R1 cho biết việc chuyển cấu trúc đang được tiến hành và nó hoạt động ở V7 cc vào thời điểm cuốn sách ra mắt.)
Steve Summit

38

Trước hết, để trích dẫn C11, chương §6.8.6.4, returntuyên bố, ( tôi nhấn mạnh )

Nếu một returncâu lệnh có biểu thức được thực hiện, giá trị của biểu thức được trả về cho người gọi dưới dạng giá trị của biểu thức gọi hàm.

Việc trả về một biến cấu trúc là có thể (và đúng), bởi vì, giá trị cấu trúc được trả về. Điều này tương tự như trả về bất kỳ kiểu dữ liệu nguyên thủy nào (trả về intchẳng hạn).

Mặt khác, nếu bạn trả về một mảng , bằng cách sử dụng return <array_name>, về cơ bản, nó sẽ trả về địa chỉ của phần tử đầu tiên của mảng NOTE , địa chỉ này sẽ trở nên không hợp lệ trong trình gọi nếu mảng là cục bộ cho các hàm được gọi. Vì vậy, trả về mảng theo cách đó là không thể.

Vì vậy, TL; DR , không có gì đặc biệt với structs, đặc biệt là ở mảng .


GHI CHÚ:

Trích dẫn C11lại, chương §6.3.2.1, ( nhấn mạnh của tôi )

Ngoại trừ khi nó là toán hạng của sizeoftoán tử, _Alignoftoán tử hoặc toán &tử một ngôi hoặc là một chuỗi ký tự được sử dụng để khởi tạo mảng, một biểu thức có kiểu '' mảng kiểu '' được chuyển đổi thành biểu thức có kiểu '' con trỏ để gõ '' trỏ đến phần tử ban đầu của đối tượng mảng và không phải là một giá trị. [...]


chính xác thì OTOH là gì ?!

1
@Sukl Đó là chữ viết tắt của "mặt khác" :)
Sourav Ghosh

1
@Sukl Tôi nghĩ những chữ viết tắt này gần giống với Internet. Chúng chắc chắn đã được sử dụng rất nhiều trong những ngày vinh quang của Usenet, và vẫn tồn tại trong hầu hết các diễn đàn. Rất may, ngay cả đối với những người không biết, Google có thể giải mã chúng ;-) Và chỉ có một số ít được sử dụng thường xuyên ngày nay (những cái phổ biến nhất)
chi

@chi yes.Google có khả năng giải mã chúng rất xuất sắc.

1
@Sukl: Bạn có thể thấy AcronymFinder hữu ích để theo dõi các từ viết tắt.
Jonathan Leffler

11

Không có gì đặc biệt về structcác loại; đó là có điều gì đó đặc biệt về các kiểu mảng ngăn chúng được trả về trực tiếp từ một hàm.

Một structbiểu thức được coi như một biểu thức của bất kỳ kiểu không phải mảng nào khác; nó đánh giá giá trị của struct. Vì vậy, bạn có thể làm những việc như

struct foo { ... };

struct foo func( void )
{
  struct foo someFoo;
  ...
  return someFoo;
}

Biểu thức someFoođánh giá giá trị của struct foođối tượng; nội dung của đối tượng được trả về từ hàm (ngay cả khi những nội dung đó chứa mảng).

Một biểu thức mảng được xử lý khác nhau; nếu nó không phải là toán hạng của sizeoftoán &tử hoặc một ngôi hoặc nếu nó không phải là một chuỗi ký tự được sử dụng để khởi tạo một mảng khác trong một khai báo, thì biểu thức được chuyển đổi ("phân rã") từ kiểu "mảng của T" thành "con trỏ tới T" , và giá trị của biểu thức là địa chỉ của phần tử đầu tiên.

Vì vậy, bạn không thể trả về một mảng theo giá trị từ một hàm, vì bất kỳ tham chiếu nào đến biểu thức mảng đều được tự động chuyển đổi thành giá trị con trỏ.


-5

Structs có các thành viên dữ liệu là public theo mặc định nên có thể trong trường hợp struct truy cập dữ liệu trong main nhưng không phải trong trường hợp class. Vì vậy, gói struct là hợp lệ.


1
Bạn có thấy rằng câu hỏi là về C? Trong C, không có public/ privatephân biệt, và không có classes. Câu hỏi đặt ra là tại sao lại structcần a trong C để trả về giá trị củ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.