2012-05-04 66 views
8

hãy chịu với tôi, tôi m từ ngôn ngữ và người mới khác để c và học nó từ http://c.learncodethehardway.org/book/learn-c-the-hard-way.htmlxác định một hàm trả về con trỏ struct

struct Person { 
    char *name; 
    int age; 
    int height; 
    int weight; 
}; 

struct Person *Person_create(char *name, int age, int height, int weight) 
{ 
    struct Person *who = malloc(sizeof(struct Person)); 
    assert(who != NULL); 

    who->name = strdup(name); 
    who->age = age; 
    who->height = height; 
    who->weight = weight; 

    return who; 
} 

Tôi hiểu chức năng Person_create thứ hai trả về một con trỏ của struct Person. Tôi không hiểu được (có thể là do im từ ngôn ngữ khác, erlang, ruby), tại sao nó định nghĩa nó như

struct Person *Person_create(char *name, int age, int height, int weight) 

không

và có cách khác để xác định một hàm để trả về một cấu trúc?

xin lỗi nếu câu hỏi này quá cơ bản.

+0

Hiểu sự khác biệt giữa 'Person *' và 'Person'. 'Person *' là một con trỏ tới đối tượng trong khi 'Person' là chính đối tượng. Cả hai đều là các kiểu khác nhau như cách 'int *' và 'int' khác nhau. – Mahesh

+1

vì vậy, 'struct Person * Person_create' giống với' struct Person * Person_create' và 'struct Person * Person_create'? '*' vị trí không quan trọng? – allenhwkim

+1

có, khoảng trống xung quanh '*' không quan trọng ở đây. –

Trả lời

11

Nó được xác định như vậy bởi vì nó trả về một con trỏ đến một cấu trúc, không phải là một cấu trúc. Bạn chỉ định giá trị trả lại cho một số struct Person *, không phải là struct Person.

Có thể trả về một struct đầy đủ, như vậy:

struct Person Person_create(char *name, int age, int height, int weight) 
{ 
    struct Person who; 
    who.name = strdup(name); 
    who.age = age; 
    who.height = height; 
    who.weight = weight; 
    return who; 
} 

Nhưng nó không được sử dụng rất thường xuyên.

3

Hàm trả về who, là số struct Person * - con trỏ đến cấu trúc. Bộ nhớ để giữ cấu trúc được phân bổ bởi malloc() và hàm trả về một con trỏ tới bộ nhớ đó.

Nếu hàm được khai báo trả về struct Personkhông một con trỏ, thì who cũng có thể được khai báo là cấu trúc. Khi trở về, cấu trúc sẽ được sao chép và trả về cho người gọi. Lưu ý rằng bản sao kém hiệu quả hơn là chỉ trả về một con trỏ vào bộ nhớ.

2

Đường dẫn không phải là con trỏ (hoặc tham chiếu) theo mặc định trong C/C++, vì chúng là ví dụ trong Java. Struct Person Function() sẽ cho phép cấu trúc trả về (theo giá trị, tạo bản sao) không phải là một con trỏ.

Bạn thường không muốn tạo bản sao của đối tượng (bản sao nông theo mặc định hoặc bản sao được tạo bằng cách sử dụng hàm tạo bản sao) vì điều này có thể tốn khá nhiều thời gian.

1

Để sao chép toàn bộ cấu trúc và không chỉ con trỏ kém hiệu quả vì con trỏ sizeof thường nhỏ hơn nhiều so với sizeof của toàn bộ cấu trúc.

Ngoài ra, cấu trúc có thể chứa con trỏ đến dữ liệu khác trong bộ nhớ và sao chép một cách mù quáng có thể nguy hiểm cho dữ liệu được phân bổ động (nếu mã xử lý một bản sao sẽ miễn phí, bản sao còn lại sẽ có con trỏ không hợp lệ). Vì vậy, bản sao nông hầu như luôn luôn là một ý tưởng tồi, trừ khi bạn chắc chắn rằng bản gốc nằm ngoài phạm vi - và sau đó tại sao bạn sẽ không chỉ trả về một con trỏ đến cấu trúc thay thế (một struct được phân bổ động trên đống Tất nhiên, vì vậy nó sẽ không bị phá hủy như các thực thể được cấp phát stack bị hủy bỏ, khi trở về từ một hàm).

2

Hàm Person_create trả về con trỏ đến struct Person để bạn phải xác định giá trị trả về là con trỏ (bằng cách thêm *).Để hiểu lý do trả về một con trỏ tới một cấu trúc và không phải là cấu trúc, người ta phải hiểu cách C xử lý bộ nhớ.

Khi bạn gọi một hàm trong C, bạn thêm bản ghi cho nó trên call stack. Ở cuối ngăn xếp cuộc gọi là chức năng main của chương trình bạn đang chạy, ở trên cùng là chức năng hiện đang thực thi. Các bản ghi trên ngăn xếp chứa thông tin như các giá trị của các tham số được truyền cho các hàm và tất cả các biến cục bộ của các hàm.

Có một loại bộ nhớ khác mà chương trình của bạn có quyền truy cập vào: bộ nhớ heap. Đây là nơi bạn phân bổ không gian bằng cách sử dụng malloc và không được kết nối với ngăn xếp cuộc gọi.

Khi bạn trở về từ một chức năng, ngăn xếp cuộc gọi sẽ xuất hiện và tất cả thông tin liên quan đến cuộc gọi chức năng sẽ bị mất. Nếu bạn muốn trả về một cấu trúc, bạn có hai tùy chọn: sao chép dữ liệu bên trong cấu trúc trước khi nó được xuất hiện từ ngăn xếp cuộc gọi hoặc giữ dữ liệu trong bộ nhớ heap và trả về một con trỏ tới nó. Sẽ tốn kém hơn khi sao chép byte dữ liệu cho byte hơn là chỉ đơn giản trả về một con trỏ, và do đó bạn thường muốn làm điều đó để tiết kiệm tài nguyên (cả bộ nhớ và chu kỳ CPU). Tuy nhiên, nó không đến mà không có chi phí; khi bạn giữ dữ liệu trong bộ nhớ heap, bạn phải nhớ free khi bạn ngừng sử dụng nó, nếu không chương trình của bạn sẽ bị rò rỉ bộ nhớ.

Các vấn đề liên quan