2010-10-31 28 views
5

Như những gì tôi biết về toán tử '&', nó trả về địa chỉ cơ sở của toán hạng trong bộ nhớ.Hiểu toán tử '&'

Chúng ta hãy tưởng tượng các tình huống sau (như trên máy tính của tôi):

  • sizeof (int) = 4 byte
  • sizeof (float) = 4 byte
  • sizeof (char) = 1 byte

Bây giờ, nếu tôi viết một cái gì đó như thế này:

void main() { 
int i = 5411; 
int *ip = &i; 
char *c = &i; 

printf("%d",*ip); 
printf("%c",*c); 
} 

printf đầu tiên() nên cho tôi 5411. Nói về printf thứ hai(), địa chỉ cơ sở của i chứa 10101001 (thứ tự cao hơn 8 bit = 1 byte cho con trỏ kiểu char). Do đó * c nên cho tôi 169, khi chuyển thành% c là ký tự không hợp lệ.

Nhưng trình biên dịch cho tôi '#' hoặc một số đầu ra hợp lệ khác. Tại sao nó như vậy ? Bất kỳ đầu vào?

EDIT (lấy từ bình luận của tác giả về một trong những câu trả lời):

Đó chỉ là một trường hợp giả, kể từ khi tôi đã ra khỏi máy thực tế.
Trường hợp thực tế là i = 5411

+0

Trong mọi trường hợp, nếu bạn cố gắng "in" một "char", nó sẽ được hiển thị dưới dạng char, không phải là mã số nguyên tương ứng. –

+0

có lẽ một cái gì đó để làm với mã hóa char đang được sử dụng, tôi sẽ đoán. –

+0

Vâng tôi cũng đồng ý với điều đó. Nhưng phải có lý do để nhận giá trị '#' từ printf cuối cùng(). Nó không phải là một giá trị rác. –

Trả lời

24

Dường như bạn gặp sự cố khi hiểu cách số nguyên được lưu trữ trong bộ nhớ. Lấy 5411 làm ví dụ.

5411 = 1010100100011 

này số 13 chữ số nhị phân có tuy nhiên, vì một int là 32-bit, nó phải là pad đến 32 chữ số

5411 = 00000000 00000000 00010101 00100011 

Trên một máy về cuối nhỏ (x86, ARM theo mặc định), các byte trọng số thấp nhất được lưu trữ ở phía trước, vì vậy trong bộ nhớ:

00100011 00010101 00000000 00000000 
^ 
c   c + 1  c + 2  c + 3 
ip 

Do đó, *c nên trả lại 00.100.011 tức là 35 ('#').

+0

Xin cảm ơn rất nhiều !! Đây chính xác là những gì tôi đang tìm kiếm :-) –

+0

Từ đâu đến '5411'? Mã của OP rõ ràng khởi tạo 'i' với' 1154'. – AnT

+0

@AndreyT: Xem nhận xét của OP về các câu trả lời khác. – kennytm

5

ASCII chỉ định nghĩa nhân vật lên đến 127. Bên cạnh đó, những gì bạn thực sự muốn làm là in các số tương ứng với giá trị trong *c, điều này cũng được thực hiện bằng %d. ..

printf("%d",*c); 

... phải hiển thị số như bạn mong đợi.

+0

Đó chỉ là một trường hợp giả, vì tôi đã rời khỏi máy thực tế. Trường hợp thực tế là i = 5411.% c cho '#' và% d cho 35 (thay vì 169) –

+0

@Guarav: ASCII vẫn chỉ xác định các ký tự lên đến 127 và những gì bạn thực sự muốn là in số, vì vậy số in, không phải ký tự. –

+2

@Gaurav - Tại sao bạn mong đợi 169? Trên một máy cuối nhỏ, nó phải là 35. Trên một máy tính lớn, nó phải là 0. –

1

Địa chỉ của * c là của i, vì bạn đã gán c cho & i. Sau đó nó sẽ lấy mức cao nhất hoặc thấp nhất (phụ thuộc vào người cuối) và in ký tự đó.

+0

Trường hợp i = 5411 đang in '#' làm ký tự. Một ASCII là 35 (10101001), không phải là 8 bit trên cũng không thấp hơn 8 bit. –

+0

@Gaurav - 35 mã nhị phân là 00100011 –

+0

Đồng ý. Sẽ không có sự cắt xén với dấu * c vì con trỏ ký tự đủ lớn để giữ toàn bộ giá trị của vị trí bộ nhớ. –

1

Chỉ cần học hỏi điều gì đó về mã hóa các số nguyên của bạn, bạn nên thử nghiệm một chút và làm

printf("0x%X, %X|%X|%X|%X\n", 
    i, 
    i & 0xFF, 
    (i >> 8) & 0xFF 
    (i >> 16) & 0xFF 
    (i >> 24) & 0xFF 
); 

Một sau đó làm tương tự với c[0], c[1] vv và định dạng chuỗi khác như %c.

3

Thứ nhất, chương trình của bạn bị hỏng. Cả C và C++ đều không cho phép khởi tạo một con trỏ char * với giá trị int *. Bạn cần một diễn viên rõ ràng khi khởi tạo con trỏ c.

Thứ hai, byte nào của số nguyên gốc i - thứ tự cao hơn hoặc thứ tự thấp hơn - nằm ở "địa chỉ cơ sở" của nó được xác định thực hiện. Có những kiến ​​trúc nhỏ gọn, nơi có thứ tự thấp hơn nhưng sẽ được nhìn thấy thông qua *c (có giá trị 130 trên máy 8 bit char 8 bit, không phải 114). Và có những kiến ​​trúc vĩ đại, nơi có thứ tự cao hơn nhưng sẽ được nhìn thấy qua *c (là 0 trên máy8 bit). Vì vậy, bạn nên mong đợi một trong hai ký tự có mã 130 hoặc ký tự có mã 0 để được in với %c định dạng thông số.

Thứ ba, trong một triển khai điển hình, thường không có điều như "mã ký tự không hợp lệ". Đối với bất kỳ mã nào một cái gì đó thường sẽ được in theo cách này hay cách khác. Tôi không thấy cách bạn quản lý để có được # làm đầu ra từ mã của bạn. Đây có phải là mã thực bạn đang chạy không?

+0

Hi Andrey. 1-> Mã được biên dịch. Tôi có nên chăm sóc cho đúc rõ ràng sau đó? ... 2-> Vâng, tôi đã không nhận thức được điều này, mà KennyTM trả lời ... 3-> Tôi đã đề cập, đó là một mã giả –

+1

@Gaurav Kalra: Biên dịch là gì? Bạn đã gắn thẻ bạn câu hỏi [C] và [C++]. Mã này sẽ không biên dịch như C++ bởi bất kỳ trình biên dịch C++ tự tôn trọng nào. Các trình biên dịch C với kiểm tra lỗi quá thoải mái có thể cho phép (với cảnh báo), nhưng mã vẫn là bất hợp pháp ngay cả khi C, vì vậy nếu bạn quan tâm đến việc viết mã C hợp lệ thì cần phải có đoạn mã. – AnT