2014-06-30 21 views
5

Xin chào Tôi là người mới đến trang web này và tôi cần một số trợ giúp để hiểu được những gì sẽ được coi là "chuẩn" trong khi mã hóa cấu trúc trong C yêu cầu một chuỗi. Về cơ bản tôi tự hỏi đó trong những cách sau đây sẽ được coi là "tiêu chuẩn công nghiệp" trong khi sử dụng các cấu trúc trong C để theo dõi tất cả các bộ nhớ cấu trúc đòi hỏi:Tôi nên khai báo các chuỗi trong cấu trúc C như thế nào?

1) Fixed Size String:

typedef struct 
{ 
    int damage; 
    char name[40]; 
} Item; 

bây giờ tôi có thể nhận được kích thước sử dụng sizeof(Item)

2) Character mảng Pointer

typedef struct 
{ 
    int damage; 
    char *name; 
} Item; 

tôi biết tôi có thể lưu trữ kích thước của name sử dụng biến số thứ hai, nhưng có cách nào khác không?

i) là có bất kỳ lợi thế khác để sử dụng kích thước cố định (1)

char name[40]; 

so với cách làm như sau và sử dụng một con trỏ đến một (2) mảng char?

char *name; 

và nếu có, lợi thế là gì?

ii) Ngoài ra, là chuỗi sử dụng một con trỏ tới mảng char (2) sẽ được lưu trữ tuần tự và ngay sau cấu trúc (ngay sau con trỏ tới chuỗi) hoặc nó sẽ được lưu ở đâu đó trong bộ nhớ?

iii) Tôi muốn biết làm thế nào người ta có thể tìm ra chiều dài của một biến char * chuỗi (mà không sử dụng một size_t, hoặc giá trị số nguyên để lưu trữ các chiều dài)

+0

Tại sao thẻ C++ này được gắn thẻ? – Rapptz

+0

@Rapptz: Tôi giả sử vì mã C++ thường tiêu thụ và hiển thị các API tương thích C, vì chúng tương thích hơn với các ngôn ngữ khác –

+1

Đối với C++, nó là thành ngữ để sử dụng 'std :: string' -' struct Foo {std :: string f; }; '. –

Trả lời

6

Về cơ bản có 3 công ước chung cho chuỗi. Tất cả ba được tìm thấy trong tự nhiên, cả hai cho đại diện trong bộ nhớ và lưu trữ/truyền.

  1. Kích thước cố định. Truy cập rất hiệu quả, nhưng nếu độ dài thực tế thay đổi cả hai không gian lãng phí và cần một trong các phương pháp dưới đây để xác định kết thúc của nội dung "thực".
  2. Độ dài được đặt trước. Thêm không gian được bao gồm trong phân bổ động, để giữ độ dài. Từ con trỏ, bạn có thể tìm thấy cả nội dung ký tự và độ dài ngay trước nó. Ví dụ: BSTR Đôi khi độ dài được mã hóa để có thêm khoảng trống hiệu quả cho các chuỗi ngắn. Ví dụ: ASN-1
  3. Chấm dứt. Chuỗi mở rộng cho đến lần xuất hiện đầu tiên của ký tự chấm dứt (thường là NUL) và nội dung không thể chứa ký tự đó. Các biến thể thực hiện việc kết thúc hai chuỗi NUL theo thứ tự, cho phép các ký tự NUL riêng biệt tồn tại trong chuỗi, mà sau đó thường được coi là một chuỗi các chuỗi được đóng gói. Các biến thể khác sử dụng mã hóa như nhồi byte (UTF-8 cũng sẽ hoạt động) để đảm bảo rằng tồn tại một số mã dành riêng cho việc chấm dứt không bao giờ xuất hiện trong phiên bản được mã hóa của nội dung.

Trong trường hợp thứ ba, có chức năng như strlen để tìm kiếm trình kết thúc và tìm độ dài.

Cả hai trường hợp sử dụng con trỏ có thể trỏ đến dữ liệu ngay sau phần cố định của cấu trúc, nếu bạn phân bổ cẩn thận theo cách đó.Nếu bạn muốn ép buộc điều này, hãy sử dụng một mảng linh hoạt ở cuối cấu trúc của bạn (không cần con trỏ). Như thế này:

typedef struct 
{ 
    int damage; 
    char name[]; // terminated 
} Item; 

hoặc

typedef struct 
{ 
    int damage; 
    int length_of_name; 
    char name[]; 
} Item; 
+0

Tôi nghĩ rằng nó được gọi là "linh hoạt", không "rách rưới", và nó không được hỗ trợ bởi tất cả các trình biên dịch. – anatolyg

+0

@anatolyg: Cảm ơn vì điều đó. Tôi nghĩ rằng đó là tiêu chuẩn cho C và bất hợp pháp trong C + +? –

+0

@BenVoigt, AFAIK, có, bất hợp pháp trong C++. – chris

0

Nếu bạn biết chiều dài tối đa của chuỗi bạn cần, sau đó bạn có thể sử dụng một mảng ký tự. Nó có nghĩa là mặc dù bạn sẽ sử dụng nhiều bộ nhớ hơn bạn thường sử dụng với mảng ký tự được phân bổ động. Ngoài ra, hãy xem CString nếu bạn đang sử dụng C++. Bạn có thể tìm độ dài của mảng ký tự bằng strlen. Trong trường hợp phân bổ tĩnh, tôi tin rằng nó sẽ là một phần của biến. Năng động có thể ở bất cứ đâu trên heap.

1
1) is there any other advantage to using the fixed size (1) 

char name[40]; 

versus doing the following and using a pointer to a char array (2)? 

char *name; 

and if so, what is the advantage? 

Với mảng của bạn khai báo là char name[40]; không gian cho tên đã được phân bổ và bạn có thể tự do sao chép thông tin vào name từ name[0] qua name[39]. Tuy nhiên, trong trường hợp của char *name;, nó chỉ đơn giản là một con trỏ ký tự và có thể được sử dụng để trỏ đến một chuỗi hiện có trong bộ nhớ, nhưng không thể sử dụng nó để sao chép thông tin cho đến khi bạn cấp phát bộ nhớ để giữ thông tin đó. Vì vậy, nói rằng bạn có một chuỗi 30 ký tự bạn muốn sao chép vào name khai báo là char *name;, trước tiên bạn phải phân bổ với malloc 30 ký tự cộng một nhân vật khác để giữ các ký tự null-chấm dứt:

char *name; 
name = malloc (sizeof (char) * (30 + 1)); 

Sau đó, bạn là miễn phí để sao chép thông tin đến/từ name. Lợi thế của phân bổ động là bạn có thể realloc bộ nhớ cho name nếu thông tin bạn đang lưu trữ trong tên phát triển. vượt quá 30 ký tự. Một yêu cầu bổ sung sau khi cấp phát bộ nhớ cho name, bạn có trách nhiệm giải phóng bộ nhớ bạn đã cấp phát khi bộ nhớ không còn cần thiết nữa. Đó là một phác thảo sơ lược về những ưu điểm/khuyết điểm/yêu cầu để sử dụng cái này trái ngược với cái kia.

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