2015-05-12 13 views
6

Tôi đã viết một chương trình nhỏ để tự làm quen với con trỏ và mối quan hệ giữa chúng nhiều hơn một chút. Để làm điều này, tôi đã viết một đoạn mã nhỏ chỉ khai báo và khởi tạo số nguyên a, sau đó khai báo một con trỏ *p đến địa chỉ a và sau đó đi sâu hơn để gán con trỏ cho con trỏ *pp và cứ tiếp tục như vậy đến ****pppp. Nếu tôi hiểu con trỏ một cách chính xác một con trỏ đến một con trỏ đến một ... về cơ bản các công trình như thế này:Địa chỉ in một con trỏ trỏ tới, giá trị địa chỉ trỏ tới, và địa chỉ của con trỏ chính nó

Address of pointer (or integer) itself: 0x7fff08d1c658 0x7fff08d1c660 0x7fff08d1c668 0x7fff08d1c670 0x7fff08d1c67c 
               ↑     ↑     ↑    ↑     ↑ 
              pppp  -->  ppp  -->  pp  -->  p  -->  a = 42 
               ↓     ↓     ↓    ↓     
Address pointer points to:    0x7fff08d1c660 0x7fff08d1c668 0x7fff08d1c670 0x7fff08d1c67c 

Các địa chỉ trên đường chéo phải giống hệt nhau vì con trỏ trước luôn trỏ tới địa chỉ của con trỏ tới đó nó đã được gán. Bây giờ tôi muốn kiểm tra điều này trong một chương trình sử dụng các cuộc gọi printf() và tại đây tôi không chắc chắn liệu cách tôi in địa chỉ các con trỏ phức tạp hơn **pp, ***ppp****pppp chỉ đến và cách tôi in địa chỉ của các con trỏ này là chính xác. Ai đó có thể chỉ ra những sai lầm có thể xảy ra? Đây là đoạn mã tiếp theo sản lượng của nó:

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

int main() 
{ 
    int a; 
    int *p; 
    int **pp; 
    int ***ppp; 
    int ****pppp; 

    a = 42; 

    /* Take the address of a */ 
    p = &a; 

    /* Take the address of p */ 
    pp = &p; 

    /* Take the address of pp */ 
    ppp = &pp; 


    /* Take the address of ppp */ 
    pppp = &ppp; 

    printf("Address of int &a:        %p\n", &a); 
    printf("value of a:         %d\n\n", a); 

    printf("Address where p points to via (void *)p:  %p\n", (void *)p); 
    printf("Value that *p points to via *p:    %d\n", *p); 
    printf("Address of *p itself via (void *)&p:   %p\n\n", (void *)&p); 

    printf("Address where pp points to via (void *)pp:  %p\n", (void *)pp); 
    printf("Value that **pp points to via **pp:   %d\n", **pp); 
    printf("Address of **pp itself via (void *)&pp:  %p\n\n", (void *)&pp); 

    printf("Address where ppp points to via (void *)ppp: %p\n", (void *)ppp); 
    printf("Value that ***ppp points to via ***ppp:  %d\n", ***ppp); 
    printf("Address of ***ppp itself via (void *)&ppp:  %p\n\n", (void *)&ppp); 

    printf("Address where pppp points to via (void *)pppp: %p\n", (void *)pppp); 
    printf("Value that ****pppp points to via ****pppp: %d\n", ****pppp); 
    printf("Address of ****pppp itself via (void *)&pppp: %p\n", (void *)&pppp); 

    return EXIT_SUCCESS; 
} 

Output:


Address of int &a:        0x7fff08d1c67c 
value of a:         42 

Address where p points to via (void *)p:  0x7fff08d1c67c 
Value that *p points to via *p:    42 
Address of *p itself via (void *)&p:   0x7fff08d1c670 

Address where pp points to via (void *)pp:  0x7fff08d1c670 
Value that **pp points to via **pp:   42 
Address of **pp itself via (void *)&pp:  0x7fff08d1c668 

Address where ppp points to via (void *)ppp: 0x7fff08d1c668 
Value that ***ppp points to via ***ppp:  42 
Address of ***ppp itself via (void *)&ppp:  0x7fff08d1c660 

Address where pppp points to via (void *)pppp: 0x7fff08d1c660 
Value that ****pppp points to via ****pppp: 42 
Address of ****pppp itself via (void *)&pppp: 0x7fff08d1c658 
+0

Tôi không hiểu những gì bạn đang yêu cầu. Không có gì sai với mã của bạn. –

+0

Điều này có vẻ tốt, –

+0

Có nhiều cách khác nhau được đề cập trong các câu trả lời stackoverflow khác nhau và trên internet để in ra địa chỉ của con trỏ ithemselves rằng tôi đã thực sự không chắc chắn liệu logic của tôi về cách in chúng là chính xác. –

Trả lời

2

Mã của bạn chủ yếu là đúng: bạn hiểu rằng printf in giá trị của con trỏ với việc chuyển đổi %p người chỉ định. Đầu ra thực tế là thực hiện cụ thể nhưng có thể được phân tích cú pháp trở lại thành một giá trị con trỏ bằng scanf với cùng một thông số %p.

Có một chi tiết nhỏ bạn gặp sai trong printf("Address of int &a: %p\n", &a);: con trỏ phải luôn được chuyển đổi thành void * khi được chuyển đến printf làm giá trị để chuyển đổi cho thông số %p. Lý do cho điều này là tinh tế: trên một số kiến ​​trúc, con trỏ đến các loại khác nhau có thể có một biểu diễn khác nhau, bao gồm một kích thước khác nhau và có thể được chuyển đến printf theo cách khác. Chuyển đổi con trỏ thành void * đảm bảo rằng con trỏ sẽ được chuyển theo dạng và cách thức được mong đợi bởi hàm printf.

chuyển đổi này không tự động như printf mất một số biến của tham số của các loại khác nhau, các đối số được truyền một cách cụ thể để vararg chức năng: ví dụ float giá trị được chuyển đổi thành và thông qua như double, nhưng các loại con trỏ khác nhau là không được chuyển đổi thành void *, vì vậy bạn phải viết chuyển đổi này một cách rõ ràng với một dàn diễn viên (void *).

Ví dụ về kiến ​​trúc với các biểu diễn con trỏ khác nhau ít phổ biến hơn, nhưng các lập trình viên cũ có thể nhớ những ngày của các con trỏ là nearfar và các mô hình bộ nhớ khác nhau.

+0

Đúng nếu tôi sai, nhưng tôi chắc chắn rằng 90% mã này sẽ biên dịch + chạy mà không có phép đúc thành '(void *)' với các phiên bản gần đây của GCC và các cài đặt ngôn ngữ tương đối hiện đại (mặc dù nó sẽ cảnh báo bạn) –

+0

Theo tôi có thể thấy đã đúc tất cả các con trỏ qua '(void *)' trong mã của tôi (ngoại trừ địa chỉ của mảng mà @CoolGuy đã chỉ ra) .Tôi không hoàn toàn chắc chắn nơi mà tôi đã nhận được sai. (Loại bỏ các phôi sẽ đưa ra một cảnh báo với '-pedantic' được chuyển đến' gcc'.) –

+0

@brauner: xin lỗi về điều đó, tôi viết e * một chi tiết nhỏ * nơi tôi nên rõ ràng hơn. Tôi đã cập nhật câu trả lời. Quan điểm của tôi cũng là giải thích lý do cho sự cần thiết phải chỉ ra con trỏ như '(void *)' – chqrlie

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