2013-04-18 37 views
5

Nếu tôi đã điều sau đây: -Đi qua một cấu trúc để một hàm trong C

struct foo 
{ 
    int a; 
    int *b; 
} bar; 

void baz(struct foo qux) 
{ 

} 

Tôi có ngay trong suy nghĩ rằng đi qua bar-baz() kết quả trong một bản sao cục bộ của bar bị đẩy vào stack? Nếu vậy, loại bản sao này là gì? trong C++, tôi giả định nó sẽ gọi hàm tạo bản sao, hoặc hàm tạo bản sao mặc định nhưng tôi không thực sự biết cách này sẽ hoạt động như thế nào trong C.

C có bất kỳ khái niệm nào của một hàm tạo bản sao mặc định không Tên? Có thể làm gì đó để thực hiện một bản sao sâu? (giả thuyết). Cách duy nhất tôi có thể nghĩ là thực sự làm một bản sao sâu và sau đó chuyển nó vào chức năng.

Thông thường, tôi sẽ chuyển con trỏ đến số foo nhưng tôi chỉ tò mò về cách hoạt động của con trỏ. Hơn nữa tôi theo ấn tượng rằng việc truyền con trỏ nhanh hơn, tiết kiệm bộ nhớ và là quá trình hành động được khuyến nghị thực hiện khi thực hiện loại thao tác này. Tôi đoán đó là một bản sao nông; điều này có thể thay đổi không?

Trả lời

4

Tôi có nghĩ rằng việc chuyển thanh thành baz() dẫn đến bản sao cục bộ của thanh bị đẩy lên ngăn xếp không?

Có.

tôi không thực sự biết làm thế nào điều này sẽ làm việc trong C.

Đáng kể như nó làm với các nhà xây dựng bản sao mặc định trong C++; mọi trường của bản sao được khởi tạo với trường tương ứng của bản gốc. Tất nhiên, vì quy tắc "như thể" toàn bộ điều có thể đun sôi xuống một memcpy.

Tôi cảm thấy rằng việc chuyển con trỏ nhanh hơn, tiết kiệm bộ nhớ và là hành động được khuyến nghị thực hiện khi thực hiện loại thao tác này.

Dành cho lớn hơn struct thường là như vậy, nhưng không phải lúc nào cũng như vậy; nếu bạn có struct nhỏ của một số trường nhỏ, chi phí sao chép có thể nhỏ hơn so với hướng dẫn (cũng có thể tốn kém bởi vì các quy tắc răng cưa của C và C++ có thể ngăn một số tối ưu).

Tôi đoán đó là bản sao nông; điều này có thể thay đổi không?

Không, bản sao nông (sao chép từng trường) là điều xảy ra với hàm tạo bản sao mặc định (trong khi có "bản sao sâu", bạn thường tạo bản sao của từng đối tượng được tham chiếu trong trường con trỏ/tham chiếu).

Ý của bạn là "chuyển bằng tham chiếu" và không phải là mặc định cho phép tính linh hoạt tối đa (và cho sự kết hợp với việc truyền đi các kiểu nguyên thủy). Nếu bạn muốn vượt qua bằng cách tham khảo bạn vượt qua một con trỏ (hoặc một tài liệu tham khảo trong C + +), thường là const nếu bạn đang ở trong chỉ cho hiệu suất, nếu không bạn vượt qua các đối tượng chính nó.

+0

p.s. không có hàm khởi tạo nào trong C; chỉ trong C++. Trong C, cấu trúc dữ liệu của bạn sẽ chỉ được sao chép byte-cho-byte. –

+0

@EdwardFalk: tất nhiên, trong thực tế tôi đã nói về * khởi tạo *, không phải xây dựng; Ngoài ra, điều "byte-cho-byte" không được chỉ định bởi tiêu chuẩn, mà thực sự chỉ nói rằng các trường được đặt tên được đảm bảo được sao chép ("Các thành viên chưa được đặt tên của các đối tượng cấu trúc có giá trị không xác định ngay cả sau khi khởi tạo.", C99 §6.7 .8 ¶9) - nghĩa là đệm có thể hoặc không được sao chép. –

+0

Giải thích tuyệt vời, tôi đoán bạn không thể ghi đè lên hành vi mặc định để thực hiện một bản sao sâu nếu điều đó là bắt buộc? – chrisw

1

Có một bản sao cục bộ của thanh được đẩy vào ngăn xếp. và phần còn lại được nhận xét về ví dụ làm việc sau đây.

#include <stdio.h> 
    struct foo 
    { 
     int a; 
     int *b; 
    } bar; 
    void baz(struct foo qux) 
    { 
     bar.a = 2; // if its a different copy then printf on main should print 1 not 2. 
     *bar.b = 5; // if its a different copy then printf on main should print 5 not 4. since the place pointer pointing to is same 
    } 
    int main(){ 
     bar.a=1; 
     bar.b = (int*)malloc(sizeof(int)); 
     *bar.b = 4; 
     baz(bar); // pass it to baz(). now the copy of bar in the stack which is what baz going to use 
     printf("a:%d | b:%d\n",bar.a,*bar.b); 
     //answer is 2 and 5 
     /*So indeed it does a shallow copy thats why we lost the "4" stored in bar.b it did not created new space in heap to store "5" instead it used the same space that b was pointing to. 
     */ 
    return 0; 
    } 
Các vấn đề liên quan