#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abc";
char * p1 = "abc";
printf("%d %d", p, p1);
}
Khi tôi in giá trị của hai con trỏ, nó đang in cùng một địa chỉ. Tại sao?
#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abc";
char * p1 = "abc";
printf("%d %d", p, p1);
}
Khi tôi in giá trị của hai con trỏ, nó đang in cùng một địa chỉ. Tại sao?
p
và p1
, thì bạn sẽ nhận thấy rằng hai con trỏ này được lưu trữ dưới hai địa chỉ khác nhau. Thực tế là giá trị của chúng giống nhau - trong trường hợp này - không liên quan.
p == p1
(chúng không khác nhau) nhưng &p != &p1
(chúng khác nhau).
Câu trả lời:
Việc hai ký tự chuỗi khác nhau có cùng nội dung được đặt ở cùng một vị trí bộ nhớ hay các vị trí bộ nhớ khác nhau là tùy thuộc vào việc triển khai.
Bạn nên luôn đối xử p
và p1
như hai con trỏ khác nhau (mặc dù họ có cùng một nội dung) khi họ có thể hoặc có thể không trỏ đến cùng một địa chỉ. Bạn không nên dựa vào tối ưu hóa trình biên dịch.
Tiêu chuẩn C11, 6.4.5, ký tự chuỗi, ngữ nghĩa
Không xác định được liệu các mảng này có khác biệt hay không miễn là các phần tử của chúng có giá trị thích hợp. Nếu chương trình cố gắng sửa đổi một mảng như vậy, hành vi không được xác định.
Định dạng để in phải là %p
:
printf("%p %p", (void*)p, (void*)p1);
Xem câu trả lời này để biết tại sao.
i modify one of the pointer, will the data in the other pointed also be modified
Bạn có thể sửa đổi con trỏ nhưng không thể sửa đổi chuỗi ký tự. Ví dụ: char *p="abc"; p="xyz";
hoàn toàn ổn trong khi char *p="abc"; p[0]='x';
gọi hành vi không xác định . Điều này không có gì để làm với volatile
. Bạn có sử dụng volatile
hay không cũng không nên thay đổi bất kỳ hành vi nào mà chúng tôi quan tâm ở đây. volatile
về cơ bản buộc phải đọc dữ liệu từ bộ nhớ mọi lúc.
p
trỏ đến chuỗi ký tự "abc"
và p[0]='x'
cố gắng sửa đổi ký tự đầu tiên của một ký tự chuỗi. Cố gắng sửa đổi một chữ chuỗi là hành vi không xác định trong C.
char []
trong C. Vì vậy, làm cho nó chỉ đọc ( const char*
như trường hợp trong C ++) sẽ đòi hỏi chaning các loại là tốt. [tiếp]
"Strings are no longer modifiable, and so may be placed in read-only memory"
, một bằng chứng lịch sử mà xâu sử dụng được sửa đổi ;-)
Trình biên dịch của bạn có vẻ khá thông minh, phát hiện ra rằng cả hai chữ đều giống nhau. Và vì các ký tự là không đổi, trình biên dịch quyết định không lưu trữ chúng hai lần.
Có vẻ như điều đáng nói là điều này không nhất thiết phải như vậy. Hãy xem câu trả lời của Blue Moon về điều này .
Btw: Câu printf()
lệnh sẽ trông như thế này
printf("%p %p", (void *) p, (void *) p1);
như "%p"
sẽ được sử dụng để in các giá trị con trỏ, và nó chỉ được xác định cho loại con trỏ void *
. * 1
Ngoài ra, tôi muốn nói rằng mã này thiếu một return
câu lệnh, nhưng tiêu chuẩn C dường như đang trong quá trình thay đổi. Những người khác có thể vui lòng làm rõ điều này.
* 1: Truyền tới void *
đây là không cần thiết cho char *
con trỏ, nhưng cho con trỏ đến tất cả các loại khác.
==
mà bạn nên sử dụng strcmpy()
hàm. Bởi vì trình biên dịch khác có thể không sử dụng tối ưu hóa (đó là trình biên dịch tối đa - thực hiện depentednt) như Alk đã trả lời PS: Blue Moon vừa thêm về nó.
Trình biên dịch của bạn đã thực hiện một cái gì đó được gọi là "chuỗi tổng hợp". Bạn chỉ định rằng bạn muốn có hai con trỏ, cả hai đều trỏ đến cùng một chuỗi ký tự - vì vậy nó chỉ tạo một bản sao của ký tự.
Về mặt kỹ thuật: Lẽ ra nó phải phàn nàn ở bạn vì đã không tạo ra các con trỏ "const"
const char* p = "abc";
Điều này có thể là do bạn đang sử dụng Visual Studio hoặc bạn đang sử dụng GCC mà không có -Wall.
Nếu bạn thực sự muốn chúng được lưu trữ hai lần trong bộ nhớ, hãy thử:
char s1[] = "abc";
char s2[] = "abc";
Ở đây, bạn tuyên bố rõ ràng rằng bạn muốn hai mảng ký tự c-string thay vì hai con trỏ đến ký tự.
Lưu ý: Tổng hợp chuỗi là một tính năng của trình biên dịch / tối ưu hóa và không phải là một khía cạnh của ngôn ngữ. Vì các trình biên dịch khác nhau như vậy trong các môi trường khác nhau sẽ tạo ra các hành vi khác nhau tùy thuộc vào những thứ như mức độ tối ưu hóa, cờ trình biên dịch và liệu các chuỗi có nằm trong các đơn vị biên dịch khác nhau hay không.
gcc (Debian 4.4.5-8) 4.4.5
không phàn nàn (cảnh báo), mặc dù đang sử dụng -Wall -Wextra -pedantic
.
const
cho các ký tự chuỗi. Cảnh báo được bật theo tùy chọn -Wwrite-strings
. Người ta dường như không được kích hoạt bởi bất kỳ lựa chọn nào khác (chẳng hạn như -Wall
, -Wextra
hoặc -pedantic
).
Như những người khác đã nói, trình biên dịch nhận thấy rằng chúng có cùng giá trị và vì vậy quyết định để chúng chia sẻ dữ liệu trong tệp thực thi cuối cùng. Nhưng nó trở nên huyền ảo hơn: khi tôi biên dịch phần sau vớigcc -O
#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abcdef";
char * p1 = "def";
printf("%d %d", p, p1);
}
nó in 4195780 4195783
cho tôi. Nghĩa là, p1
bắt đầu 3 byte sau p
, vì vậy GCC đã nhìn thấy hậu tố phổ biến của def
(bao gồm cả dấu \0
chấm hết) và thực hiện tối ưu hóa tương tự như bạn đã hiển thị.
(Đây là một câu trả lời vì quá dài để trở thành một bình luận.)
Các chuỗi ký tự trong mã được lưu trữ trong một phân đoạn dữ liệu chỉ đọc của mã. Khi bạn viết ra một chuỗi ký tự như "abc", nó thực sự trả về một 'const char *' và nếu bạn có tất cả các cảnh báo trình biên dịch trên đó, nó sẽ cho bạn biết rằng bạn đang truyền tại thời điểm đó. Bạn không được phép thay đổi các chuỗi đó vì lý do bạn đã chỉ ra trong câu hỏi này.
Khi bạn tạo một chuỗi ký tự ("abc"), nó sẽ được lưu vào một bộ nhớ, chứa các ký tự chuỗi và sau đó nó sẽ được sử dụng lại nếu bạn tham chiếu đến cùng một chuỗi ký tự, do đó cả hai con trỏ trỏ đến cùng một vị trí, nơi " abc "chuỗi ký tự được lưu trữ.
Tôi đã biết điều này một thời gian trước nên tôi có thể đã không giải thích nó thực sự rõ ràng, xin lỗi.
Điều này thực sự phụ thuộc vào trình biên dịch bạn đang sử dụng .
Trong hệ thống của tôi với TC ++ 3.5, nó in hai giá trị khác nhau cho hai con trỏ tức là hai địa chỉ khác nhau .
Trình biên dịch của bạn được thiết kế vì nó sẽ kiểm tra sự tồn tại của bất kỳ giá trị nào trong bộ nhớ và tùy thuộc vào sự tồn tại của nó, nó sẽ gán lại hoặc sử dụng cùng một tham chiếu của giá trị đã lưu trữ trước đó nếu cùng một giá trị được tham chiếu.
Vì vậy, đừng nghĩ về nó quá nhiều vì nó phụ thuộc vào cách trình biên dịch phân tích mã.
Đó là tối ưu hóa trình biên dịch nhưng quên tối ưu hóa cho tính di động. Đôi khi mã đã biên dịch dễ đọc hơn mã thực.