2011-10-06 37 views
5

Tôi có ứng dụng thử nghiệm sau đây:Tại sao char * được xử lý giống như char ** trong C?

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

int main(void){ 
    char buf[512]; 
    buf[0]= 0x1; 
    buf[1]= 0x2; 
    char *temp1 = &buf; 
    char *temp2 = buf; 
    char *temp3 = &buf[0]; 
    printf("temp1:%p, temp2:%p, temp3:%p\n",temp1,temp2,temp3); 
    printf("0 = %d, %d, %d\n",temp1[0],temp2[0],temp3[0]); 
    printf("1 = %d, %d, %d\n",temp1[1],temp2[1],temp3[1]); 
    return; 
} 

Nó biên dịch với một cảnh báo:

Nhưng khi tôi chạy nó, cả ba con trỏ cư xử như vậy.

./testptr 
temp1:0x7fff3a85f220, temp2:0x7fff3a85f220, temp3:0x7fff3a85f220 
0 = 1, 1, 1 
1 = 2, 2, 2 

Tôi biết rằng buf == &buf[0], nhưng tại sao &buf == &buf[0]? Không nên &bufchar**?

+1

'& buf' thực sự là một' char (*) [512] '(một con trỏ đến một mảng' char' 512 mục). Chúng không hoàn toàn giống nhau. –

+0

Bạn đã thay đổi mã của mình giữa việc bắt đầu trình biên dịch và dán mã vào câu hỏi. Vấn đề là trên dòng 9 bây giờ. –

+0

Xin lỗi bạn đúng, chỉ cần thêm một dòng mới – austinmarton

Trả lời

3

Tất cả các con trỏ cư xử như vậy bởi vì bạn đã tuyên bố tất cả trong số họ làm char*. C được gõ tĩnh vì vậy loại được ràng buộc với biến và không phải là giá trị.

Bây giờ phần hành vi được giải thích, chúng tôi chỉ cần tìm hiểu lý do tại sao chúng thực sự có cùng giá trị (theo% p printf). Vâng, đây chỉ là một tạo phẩm của con trỏ được thực hiện như một địa chỉ bộ nhớ của GCC (các offset và kích thước tạo ra * khác với ** được xử lý bởi hệ thống kiểu/trình biên dịch đằng sau hậu trường).Lưu ý rằng giống như bất kỳ nội dung đáng ngờ nhất nào đưa ra cảnh báo, điều này có thể là hành vi không xác định hoặc ít nhất, một thực tiễn không tốt :)

2

Mảng không phải là con trỏ, mặc dù chúng có thể được sử dụng theo cùng một cách. Bạn tình cờ đã tìm thấy một khía cạnh trong đó ngữ nghĩa mảng và con trỏ khác nhau.

+0

Tôi phát hiện ra điều này khi tôi vô tình chuyển '& buf' thay vì' buf' làm đối số thứ hai của kiểu 'void *' thành hàm [recv] (http://linux.die.net/man/2/recv) . Có thể điều này có thể gây ra vấn đề ngay cả khi ví dụ trên của tôi không minh họa nó? – austinmarton

+0

@austinmarton: Tôi thích bị nhầm lẫn bên cạnh hoang tưởng khi nói đến cảnh báo trình biên dịch C – hugomg

+0

@missingno: Cuộc gọi công bằng. Trong ứng dụng ban đầu của tôi, lỗi này đã được chuyển thành một con trỏ void vì vậy không có cảnh báo nào được tạo ra. – austinmarton

1

Bạn có thể làm việc từ đại số của các toán tử *&.

  • chúng ta biết rằng buf là địa chỉ của phần tử 0 thứ i của mảng buf

  • chúng ta biết rằng &buf[0] cũng là địa chỉ của phần tử 0 thứ

  • theo định nghĩa buf[0] tương đương với *(buf+0)

  • &(*(a)) tương đương với a.

Vì vậy, &buf[0] trở thành &(*(buf+0)) đó là buf.

Cập nhật

Ở đây, chúng ta hãy đặt nó ra như một bằng chứng.

  1. &buf[0] Cho trước.
  2. &(buf[0]) theo các quy tắc ưu tiên C với() 's
  3. &((*(buf+0)))buf[0] == *(buf+0).
  4. &(*(buf+0)) loại bỏ dấu ngoặc không liên quan
  5. buf QED
+3

Tôi đồng ý với những gì bạn đang nói ('buf == & buf [0]'), nhưng đó không phải là những gì tôi đang hỏi về ('& buf == buf'?). – austinmarton

+0

@austinmarton, hãy làm theo các bước: chúng là bằng chứng cho thấy, có, '& buf' tương đương với' buf'. –

+1

@ Charlie: Không, bằng chứng nói rằng '& buf [0]' tương đương với 'buf', không phải' & buf' tương đương với 'buf', đó là câu hỏi được đặt ra. – icktoofay

1

Nếu bạn nghĩ về mã thực sự được trình biên dịch tạo ra khi nào nó xử lý một mảng, nó trở nên rõ ràng hơn. Tên buf tham chiếu đến địa chỉ của phần tử đầu tiên (zeroth) của mảng (không gian liền kề để chứa các ký tự). Nếu bạn nhìn vào đối tượng tại mục nhập của bảng biểu tượng cho "buf", bạn sẽ tìm thấy địa chỉ của phần tử đầu tiên đó. Khi bạn tham khảo, ví dụ, buf [0], trình biên dịch tạo ra địa chỉ của buf, cộng với 0 lần kích thước của một char. Điều này xảy ra giống với địa chỉ của chính buf.

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