2011-06-29 69 views
11
char *p = "string"; //creates pointer to constant string 

char p[] = "string"; //just an array with "string" 

Tôi chỉ là một chút nhầm lẫn về lý do tại sao nó trong ví dụ đầu tiên tạo ra một con trỏ đến một chuỗi liên tục? Không phải nó chỉ là một con trỏ đề cập đến một nơi trong bộ nhớ với "chuỗi"?Con trỏ để const chuỗi trong C

+0

Bạn có thể muốn đọc phần 6 (và các mục khác) của [c-faq] (http://c-faq.com/). – pmg

+0

tìm thấy điều thú vị: http://www.geeksforgeeks.org/storage-for-strings-in-c/ – NDestiny

Trả lời

14

Thật không may hợp pháp trong C (và trong C++ 03, để tương thích). Nhưng bất kỳ nỗ lực nào để sửa đổi chuỗi ký tự bằng con trỏ sẽ dẫn đến hành vi Không xác định. Vì vậy, tốt hơn luôn gán chuỗi chữ đến một const char*

const char * cp = "Hello"; //OK 
char* p = "Hello"; //OK (unfortunately) 
cp[0] = 'Y'; //Compile-time error, good 
p[0] = 'Y'; //no compiler error, undefined behavior 
21

Trong trường hợp đầu tiên, "string" có thể được lưu trữ trong khu vực chỉ đọc của quy trình, do đó, việc sửa đổi bộ nhớ được trỏ đến bởi p sẽ gây ra hành vi không xác định.

Trong trường hợp thứ hai, bộ nhớ thực được cấp phát và khởi tạo trên ngăn xếp lúc chạy (hoặc trong phần thích hợp của quá trình khởi động chương trình nếu nó không phải là biến cục bộ), do đó sửa đổi bộ nhớ là OK.

Các trường hợp đầu tiên có thể được minh họa như thế này:

+---+   +---+---+---+---+---+---+---+ 
| | ----> | s | t | r | i | n | g | \0| 
+---+   +---+---+---+---+---+---+---+ 
    p 

Trong khi trường hợp thứ hai là:

+---+---+---+---+---+---+---+ 
| s | t | r | i | n | g | \0| 
+---+---+---+---+---+---+---+ 
       p 

Hai tờ khai có một sự khác biệt đáng kể, mặc dù bạn có thể đã nghe nói rằng họ là những giống với sách lập trình C chất lượng thấp.

Đầu tiên là một con trỏ loại char *, trong khi thứ hai là một mảng loại char []. Định danh mảng phân rã thành con trỏ trong một số ngữ cảnh, nhưng điều đó không làm cho chúng trỏ đến. Một con trỏ chỉ là một địa chỉ và một mảng là "toàn bộ điều" - trong trường hợp đầu tiên sizeof(p) mang lại kích thước của một con trỏ (thường là 4 hoặc 8 tùy thuộc vào máy mục tiêu), và trong trường hợp thứ hai nó mang lại 7 * sizeof(char), độ dài của chuỗi thực tế.

+0

"khu vực chỉ đọc của tệp thực thi": có thể "quy trình" quan trọng hơn ở đây ... "có thể thực thi "tập trung nhiều hơn vào tệp đĩa chứa chương trình, nhưng điều quan trọng là bộ nhớ mà nội dung tệp được sao chép sẽ được thực hiện bởi hầu hết các trình tải hệ điều hành hiện đại. Tôi thích rằng bạn đã đặt trường hợp thứ hai của bạn 'p' dưới 'i' ... một phần của tôi muốn có nó dưới 's' để nhấn mạnh" mảng bắt đầu từ ... "- như sự hiểu biết mảng offsets là rất quan trọng - nhưng bạn đã nhấn mạnh rằng p * là * tất cả các mảng chứa dữ liệu văn bản, điều này quan trọng hơn nhiều trong ngữ cảnh này. +1 –

+0

Câu trả lời rất hay. Cũng là phương pháp đồ họa để giải thích sự khác biệt. –

+0

@Tony: cảm ơn bạn đã sửa chữa, cập nhật câu trả lời của tôi. –

3

Đầu tiên tạo con trỏ và đặt nó thành địa chỉ của chuỗi không đổi (có lẽ trong vùng không có tính năng ghi ghi trên trang). Viết cho con trỏ này là bất hợp pháp (và có thể sẽ bị lỗi).

Cách thứ hai tạo mảng và sao chép ký tự vào đó. Việc ghi vào mảng này sẽ ghi vào một số vị trí trên ngăn xếp của bạn và hoàn toàn hợp pháp.

+0

Trong trường hợp đầu tiên, ghi vào con trỏ không phải là bất hợp pháp trong C, nó là hành vi không xác định. Nó có thể gây ra lỗi bảo vệ bộ nhớ hoặc nó có thể hoạt động tốt. Nó phụ thuộc hoàn toàn vào sự kết hợp của hệ điều hành trình biên dịch và kiến ​​trúc máy. – JeremyP

1

Trong trường hợp đầu tiên, "chuỗi" có thể được lưu trữ trong một khu vực chỉ đọc của quá trình này, vì vậy cố gắng để thay đổi bộ nhớ được trỏ đến bởi p sẽ gây ra hành vi không xác định.

Nó có thể được chứng minh bằng cách chạy các dòng mã trên nhiều lần.

char *p="string"; 

bạn sẽ nhận thấy rằng nội dung của p (tức là địa chỉ của "chuỗi") vẫn không đổi.

char p[] = "string"; 

cho những bộ nhớ này được cấp phát mỗi lần bạn chạy nội dung của thay đổi p.

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