2009-04-29 34 views
11

Say chúng ta có đoạn mã sau:C địa chỉ mảng nhầm lẫn

int main(){ 
    int a[3]={1,2,3}; 
    printf("  E: 0x%x\n", a); 
    printf(" &E[2]: 0x%x\n", &a[2]); 
    printf("&E[2]-E: 0x%x\n", &a[2] - a); 
    return 1; 
} 

Khi biên soạn và chạy kết quả sau:

 E: 0xbf8231f8 
    &E[2]: 0xbf823200 
&E[2]-E: 0x2 

tôi hiểu kết quả của & E [2] mà là 8 cộng với địa chỉ của mảng, kể từ khi được lập chỉ mục bởi 2 và kiểu int (4 byte trên hệ thống 32 bit của tôi), nhưng tôi không thể tìm ra lý do tại sao dòng cuối cùng là 2 thay vì 8?

Ngoài ra, loại dòng cuối cùng sẽ là gì - một số nguyên hoặc một con trỏ nguyên?

Tôi tự hỏi liệu đó có phải là hệ thống kiểu C (đúc kinda) khiến cho điều này không?

+0

Đây gần như là bản sao của http://stackoverflow.com/questions/759663/pointer-arithmetic-in-c – finnw

+0

Còn về printf ("E: 0x% x \ n", &a); – dashesy

Trả lời

10

Bạn phải nhớ những gì biểu hiện a[2] thực sự có nghĩa là . Nó chính xác tương đương với *(a+2). Vì vậy, nhiều như vậy, rằng nó là hoàn toàn hợp pháp để viết 2[a] thay vào đó, với hiệu ứng giống hệt nhau.

Để làm việc đó và có ý nghĩa, số học con trỏ có tính đến loại điều được chỉ ra. Nhưng điều đó được quan tâm đằng sau hậu trường. Bạn có thể chỉ đơn giản là sử dụng offsets tự nhiên vào mảng của bạn, và tất cả các chi tiết chỉ cần làm việc ra.

Cùng một logic áp dụng cho sự khác biệt con trỏ, điều này giải thích kết quả của bạn về 2.

Dưới mui xe, trong ví dụ của bạn, chỉ mục được nhân với sizeof(int) để nhận được bù đắp byte được thêm vào địa chỉ cơ sở của mảng. Bạn vạch trần chi tiết đó trong hai bản in của các địa chỉ.

+1

... hoặc 2 ["funny"]. –

8

Khi trừ con trỏ cùng loại kết quả là số phần tử chứ không phải số byte. Điều này là do thiết kế để bạn có thể dễ dàng chỉ mục mảng của bất kỳ loại nào. Nếu bạn muốn số byte - hãy truyền địa chỉ sang char *.

5

Dòng & E [2] -2 đang thực hiện phép trừ con trỏ, không trừ số nguyên. Trừ con trỏ (khi cả hai con trỏ trỏ đến dữ liệu cùng loại) trả về sự khác biệt của các địa chỉ chia cho kích thước của loại chúng trỏ đến. Giá trị trả về là một int.

Để trả lời câu hỏi "cập nhật" của bạn, một lần nữa con trỏ số học (lần thêm con trỏ này) đang được thực hiện. Nó được thực hiện theo cách này trong C để làm cho nó dễ dàng hơn để "index" một đoạn dữ liệu liền kề được trỏ tới bởi con trỏ.

+1

Giá trị trả về là một int, không phải là int * – paxdiablo

+0

Xin lỗi, thời điểm tóc vàng ... bạn đúng, – marcog

2

Bạn có thể quan tâm đến Pointer Arithmetic In C câu hỏi và câu trả lời.

về cơ bản, + và - toán tử tính đến kích thước phần tử khi được sử dụng trên con trỏ.

0

Nếu bạn muốn thấy sự khác biệt byte, bạn sẽ phải một loại đó là 1 byte trong kích thước, như thế này:

printf("&E[2]-E:\t0x%x\n",(char*)(&a[2])-(char*)(&a[0])) 
1

Khi thêm và trừ con trỏ trong C, bạn sử dụng kích thước của loại dữ liệu thay vì địa chỉ tuyệt đối.

Nếu bạn có một con trỏ int và thêm số 2 vào nó, nó sẽ tiến 2 * sizeof (int). Trong cùng một cách, nếu bạn trừ hai con trỏ int, bạn sẽ nhận được kết quả theo đơn vị sizeof (int) thay vì sự khác biệt của các địa chỉ tuyệt đối.

(Có gợi ý sử dụng kích thước của kiểu dữ liệu là khá thuận tiện, do đó bạn ví dụ đơn giản là có thể sử dụng p++ thay vì phải xác định kích thước của các loại hàng thời gian:. p+=sizeof(int))

7

Khi bạn tăng con trỏ bằng 1 (p + 1) sau đó con trỏ sẽ trỏ đến địa chỉ hợp lệ tiếp theo bằng cách thêm (p + sizeof (Type)) byte vào p. (nếu Type là int thì p + sizeof (int))

Logic tương tự cũng tốt cho p-1 (dĩ nhiên trừ trong trường hợp này).

Nếu bạn chỉ áp dụng những nguyên tắc ở đây:

Trong thuật ngữ đơn giản:

a[2] can be represented as (a+2) 
a[2]-a  ==> (a+2) - (a) ==> 2 

Vì vậy, đằng sau những cảnh,

a[2] - a[0] 
==> {(a+ (2* sizeof(int))) - (a+0) }/sizeof(int) 
==> 2 * sizeof(int)/sizeof(int) ==> 2 
1

Re: "Trong phần bổ sung, loại dòng cuối cùng nên là gì? Một số nguyên hoặc một con trỏ nguyên ??"

một số nguyên/số. bởi cùng một mã thông báo rằng: Hôm nay - ngày 1 tháng 4 = số. không phải ngày

+0

thực sự thanh lịch. – Pwn