2010-07-09 15 views
5

Giả sử tôi đã sau khởi của một mảng char:khởi tạo mảng char trong một cách tương tự như khởi tạo xâu

char charArray[]={'h','e','l','l','o',' ','w','o','r','l','d'}; 

và tôi cũng có sau khởi của một chuỗi chữ:

char stringLiteral[]="hello world"; 

Sự khác biệt duy nhất giữa nội dung của mảng đầu tiên và chuỗi thứ hai là chuỗi thứ hai có một ký tự null ở cuối của nó.

Khi đó là vấn đề khởi tạo mảng char, có macro hay cái gì cho phép chúng tôi đặt văn bản khởi tạo giữa hai dấu ngoặc kép nhưng mảng không nhận được ký tự kết thúc null không? Nó chỉ không có ý nghĩa với tôi rằng khi một ký tự null kết thúc là không cần thiết, chúng ta nên sử dụng cú pháp khởi tạo được đề cập đầu tiên và viết hai dấu nháy đơn cho mỗi ký tự trong văn bản khởi tạo, cũng như các dấu hiệu virgule để tách các ký tự.

Tôi nên thêm rằng khi tôi muốn có một mảng char, nó cũng nên được rõ ràng rằng tôi không muốn sử dụng nó với các chức năng dựa trên chuỗi literals cùng với thực tế là không có tính năng trong đó sử dụng chuỗi kết quả chữ, là vào xem xét của tôi.

Tôi rất biết ơn câu trả lời của bạn.

+0

@Michael - đó là yêu cầu trong tiêu chuẩn C và C++. – Steve314

+1

* VẤN ĐỀ * mà bạn phải đối mặt là "chuỗi được trích dẫn" được yêu cầu bởi ngôn ngữ được NUL chấm dứt. – torak

Trả lời

0

tôi có thể tìm thấy một cách để làm những gì tôi muốn mặc dù nó không phải là trực tiếp những gì tôi muốn, nhưng nó có thể có tác dụng tương tự.
Đầu tiên xem xét hai loại sau đây:

template <size_t size> 
class Cont{ 
public: 
    char charArray[size]; 
}; 
template <size_t size> 
class ArrayToUse{ 
public: 
    Cont<size> container; 
    inline ArrayToUse(const Cont<size+1> & input):container(reinterpret_cast<const Cont<size> &>(input)){} 
}; 

Trước khi tiếp tục, bạn có thể muốn đi here và hãy nhìn vào nhà xây dựng biểu thức hằng số và các loại khởi tạo.
Bây giờ nhìn vào đoạn mã sau:

const Cont<12> container={"hello world"}; 
ArrayToUse<11> temp(container); 
char (&charArray)[11]=temp.container.charArray; 

văn bản Cuối cùng initializer được viết giữa hai trích dẫn kép.

+0

Đảm bảo chia nhỏ một số nhận xét xung quanh cấu trúc đó. Như bạn có thể đã đoán được bởi các câu trả lời và nhận xét khác, ** không ** chấm dứt '\ 0' là một khái niệm khá bất thường và phải có các dấu hiệu cảnh báo thích hợp. – DevSolar

+0

@DevSolar: được đánh giá cao – Pooria

3

Không có cách nào để làm những gì bạn muốn. Cách đầu tiên để khởi tạo mảng chỉ định các khởi tạo riêng biệt cho mỗi ký tự, cho phép rõ ràng bỏ qua '\ 0'. Thứ hai là khởi tạo một mảng ký tự từ một chuỗi ký tự, mà trong C/C++ luôn bị chấm dứt bởi một ký tự null.

EDIT: chỉnh: 'con trỏ ký tự' -> 'mảng nhân vật'

+2

Thực ra, tôi không tin vào trường hợp thứ hai đang khởi tạo một con trỏ tới một chuỗi ký tự. Nó tạo ra một mảng và khởi tạo nội dung của nó dựa trên nội dung của chuỗi. Và có sự khác biệt thực sự quan trọng. – torak

+0

không bao giờ nhận thấy khái niệm "khởi tạo nhân vật riêng biệt", nhờ – Pooria

0

Câu trả lời cơ bản là đại đa số các mảng char là chuỗi - trong C, chuỗi được null chấm dứt. C++ thừa hưởng quy ước đó. Ngay cả khi null đó là không cần thiết, hầu hết thời gian nó không phải là một vấn đề chỉ để lại nó có anyway.

Macro không đủ mạnh để thực hiện những gì bạn muốn. Mẫu sẽ là, ngoại trừ chúng không có bất kỳ xử lý chuỗi thời gian biên dịch nào.

Thông thường, khi mọi người muốn kết hợp các byte số và chuỗi ký tự trong cùng chuỗi mảng, chúng sử dụng chuỗi ký tự nhưng sử dụng ký tự thoát hex như \xFF.

6

Nó cho phép trong C để khai báo mảng như sau, mà sẽ khởi tạo nó mà không sao chép chấm dứt '\0'

char c[3] = "foo"; 

Nhưng đó là bất hợp pháp trong C++. Tôi không biết một thủ thuật nào cho phép nó cho C++. Tiêu chuẩn C++ tiếp tục cho biết

Lý do: Khi các mảng không bị chấm dứt này được điều khiển bởi các thường trình chuỗi chuẩn, có khả năng xảy ra thảm họa lớn.
Ảnh hưởng đến tính năng gốc: Xóa tính năng ngữ nghĩa được xác định rõ.
Khó khăn khi chuyển đổi: Biến đổi ngữ nghĩa. Các mảng phải được khai báo một phần tử lớn hơn để chứa chuỗi chấm dứt '\ 0'.
Cách sử dụng rộng rãi: Ít khi. Kiểu khởi tạo mảng này được xem là kiểu mã hóa kém.

+1

Tôi chỉ tìm thấy câu trả lời của bạn một chút khó hiểu. 'char c [4] =" foo ";' không đặt ký tự null phải không? Đây có phải là kiểu mã hóa nghèo nàn không? Làm thế nào về 'char [128] =" ";'? Chỉ khởi tạo bộ đệm? Ổn chứ? Hoặc là 'char [128] = {'\ 0'};' tốt hơn? – nus

+0

Theo sách tham khảo của Randal Albert, 'char c [4] =" foo ";' không đặt ký tự null cho bạn và theo cuốn sách, bạn nên viết nó là 'char [4] =" foo " ; '. 'char c [3] =" foo ";' là bất hợp pháp vì chúng ta cần đặt trước một khoảng trống cho ký tự null kết thúc ở phía sau. – user3437460

+0

@user đáng đọc toàn bộ câu trả lời của tôi có nội dung "Các mảng phải được khai báo một phần tử lớn hơn để chứa chuỗi chấm dứt '\ 0'." –

0

litb has the technically correct answer.

Đối với một ý kiến ​​- tôi nói chỉ sống với 'chất thải' của phần bổ sung '\ 0'. Vì vậy, nhiều lỗi là kết quả của mã mong đợi một chấm dứt null, nơi không phải là (lời khuyên này có vẻ đi trực tiếp chống lại một số lời khuyên khác tôi đã chỉ một hoặc hai ngày trước về không làm phiền đến không một bộ đệm toàn bộ. mâu thuẫn - Tôi vẫn ủng hộ null chấm dứt chuỗi trong bộ đệm).

Nếu bạn thực sự không thể sống với ký tự '\ 0' vì một số ngữ nghĩa trong cấu trúc dữ liệu bạn đang xử lý, chẳng hạn như nó có thể là một phần của cấu trúc đóng gói lớn hơn, bạn luôn có thể bắt đầu mảng mình (mà tôi nghĩ nên có ít hiệu quả hơn so với những gì các trình biên dịch có thể đã làm cho bạn):

#define MY_STRING_LITERAL "hello world" 

char stringLiteral[sizeof(MY_STRING_LITERAL) - 1]; 

memcpy(stringLiteral, MY_STRING_LITERAL, sizeof(stringLiteral)); 
+0

Tôi nghĩ phương pháp của bạn nên hiệu quả như trình biên dịch cho mảng char với lớp lưu trữ tự động, nhưng đối với mảng char với lớp lưu trữ tĩnh hoặc lớp trong phạm vi toàn cục, tôi nghĩ không có bản sao thời gian chạy được thực hiện bởi trình biên dịch. – Pooria

+0

@ garrett2011: điều đó có thể đúng đối với các mục 'const char []', nhưng tôi cho rằng hầu hết các mảng không phải const sẽ có giá trị ban đầu của chúng được sao chép từ hình ảnh chương trình 'văn bản' (không thể ghi trên hầu hết các nền tảng) vào RAM trước 'main()' được gọi. Chừng nào 'memcpy()' chỉ được thực hiện một lần, hiệu quả khôn ngoan thì nó khá là sáu, một nửa tá khác cho dù nó được thực hiện bởi thời gian chạy hay mã của bạn. –