2013-02-27 65 views
6

Tôi không tìm thấy lý thuyết về con trỏ đặc biệt phiền hà, nhưng đôi khi tôi bị lúng túng bởi một số ký hiệu. Trong ví dụ sau, ai đó có thể giải thích cách hoạt động của đường dây p = (int*) a. Lời giải thích tôi có của mã cho thấy rằng dòng này chỉ lưu trữ địa chỉ của phần tử đầu tiên của mảng đầu tiên trong con trỏ p, sao cho printf("%u", *p) sản lượng 5. Nếu đây là trường hợp của dòng này thì đây là cách viết gián tiếp hơn p = a[0]?Ký hiệu con trỏ

int main() 
{ 
    int a[][4] = { 
     5, 7, 5, 9, 
     4, 6, 3, 1, 
     2, 9, 0, 6 
     }; 



    int *p; // create an integer pointer 
    int (*q)[4]; // create a pointer to a four-element integer array 

    p = (int*)a; // ? 
    q = a; 


    printf("%u %u\n", p, q); 
    p++; 
    q++; 
    printf("%u %u\n", p, q); 


    return 0; 
} 

Trả lời

7

Khái niệm a, khi được sử dụng trong bối cảnh giá trị , thực sự sẽ đánh giá "địa chỉ của phần tử đầu tiên của mảng a" - địa chỉ của a[0] - khi bạn đã hiểu chính xác nó.

Tuy nhiên, lưu ý rằng mảng a thực ra chúng tôi gọi là mảng 2D. Đây là mảng của mảng. Phần tử đầu tiên của mảng a là một mảng: một mảng kiểu int [4].Do đó, hãy tính đến biểu thức ở trên, biểu thị a, khi được sử dụng trong ngữ cảnh giá trị, tương đương với biểu thức &a[0], là con trỏ thuộc loại int (*)[4] và khái niệm chỉ đến toàn bộ mảng 1D a[0].

Vì lý do này, một nỗ lực để làm

p = a; 

sẽ cho kết quả trong một tin nhắn chẩn đoán từ trình biên dịch. Việc gán giá trị int (*)[4] cho đối tượng con trỏ int * là bất hợp pháp. Các loại này không tương thích. Để ngăn chặn tin chẩn đoán này mã trong câu hỏi sử dụng một diễn viên rõ ràng

p = (int *) a; 

này mạnh mẽ dìm giá trị int (*)[4] con trỏ nói trên vào p. Trong một triển khai điển hình, điều này bảo toàn giá trị số của con trỏ ban đầu, chỉ thực hiện chuyển đổi kiểu khái niệm.

Một cố gắng để truy cập giá trị của *p thường sẽ tạo ra giá trị của a[0][0] đơn giản chỉ vì số lượng địa chỉ của toàn bộ a là giống như địa chỉ của a[0] và cũng giống như địa chỉ của a[0][0]. Đoạn mã trên khai thác danh tính bằng số này, trong khi sử dụng dàn diễn viên rõ ràng để làm việc xung quanh loại không tương thích.

+0

Cảm ơn câu trả lời kỹ lưỡng như vậy. Mặc dù tôi đã biết rằng tôi đã làm việc với một mảng 2-D, tôi đã không đánh giá cao rằng con trỏ và một [0] là một con trỏ tới một [mảng int] hơn là một con trỏ [int] đơn giản. Tôi cũng bỏ lỡ thực tế đã có một số diễn viên đang diễn ra. Đây là một câu trả lời rất hữu ích. –

-2

a là mảng 3 của mảng 4 của int.

Giá trị của a là một con trỏ tới một mảng 4 của int. Giá trị của con trỏ này là địa chỉ của phần đầu của mảng.

(int *) a chuyển con trỏ thành con trỏ thành int. Giá trị không thay đổi nhưng loại khác nhau.

Lưu ý rằng để in giá trị con trỏ, đặc tả chính xác là p.

+0

"Giá trị của a là con trỏ tới" Không. Giá trị của 'a' là một mảng. – newacct

+0

@newacct Thuật ngữ hiểu lầm phổ biến. 'a' là một mảng (đọc dòng đầu tiên của tôi). Bây giờ giá trị * của một mảng là một con trỏ đến phần tử đầu tiên của nó. Giá trị của một đối tượng là những gì nó * đánh giá *. Đối với các mảng có các ngoại lệ của các toán tử không đánh giá toán hạng của chúng ('&' và 'sizeof') và chuỗi khởi tạo chuỗi cho một mảng ký tự. – ouah

+0

@newacct nếu bạn đồng ý với điều đó, vui lòng xóa bỏ phần tóm tắt – ouah

7

Lời giải thích tôi có các mã gợi ý rằng dòng này chỉ đơn giản là lưu trữ các địa chỉ của phần tử đầu tiên của mảng đầu tiên trong con trỏ p

đúng.

Nếu trường hợp này là dòng này chỉ đơn giản là cách viết gián tiếp hơn p = a[0]?

Không, không phải vậy. "Dòng này chỉ đơn giản là lưu trữ địa chỉ của phần tử đầu tiên" - đó là thay tương tự như

p = &a[0]; 

Nhưng tuyên bố trên là không hoàn toàn đúng, vì &a[0] là loại int (*)[4]. Việc chuyển nhượng đúng mà không có một diễn viên có thể là một cái gì đó giống như

p = &a[0][0]; 

Chơi xung quanh với biên soạn tờ khai khác nhau sử dụng với -Wall bật và google các lỗi thỉnh thoảng/cảnh báo :)

+0

Bạn trả lời là quá tốt mà tôi đã xóa. :) –

+0

@ruakh: nah, chỉ mục 2d đi một bên dưới - Tôi đã mở rộng phần giải thích. –

+0

@GrijeshChauhan :-) –

2

Để mở rộng về câu trả lời H2CO3 của, hãy nhớ rằng trong hầu hết các tình huống một biểu hiện của mảng loại sẽ được chuyển đổi sang một biểu hiện của con trỏ loại, và giá trị của biểu thức sẽ là địa chỉ của phần tử đầu tiên của mảng.

Loại biểu thức a là "mảng 3 phần tử của mảng 4 phần tử int". Trừ khi nó là toán hạng của sizeof, _Alignof, hoặc & khai thác unary, a sẽ chuyển để một biểu thức kiểu "con trỏ đến mảng 4 phần tử của int" (int (*)[4]), và giá trị của nó sẽ là địa chỉ của a[0]. Vấn đề là không thể gán giá trị loại int (*)[4] cho biến số int *; các loại không phải là tương thích, vì vậy chúng tôi cần phải truyền kết quả của biểu thức a tới int *.

này làm việc vì địa chỉ của mảng và địa chỉ của phần tử đầu tiên của mảng đều giống nhau - các biểu thức a, &a, a[0], &a[0], và &a[0][0] tất cả mang lại cùng giá trị, họ chỉ có khác nhau loại (int (*)[4], int (*)[4][4], int *, int (*)[4]int * tương ứng).

+0

Cảm ơn bạn. Bạn khá chính xác; sự khác biệt giữa một con trỏ kiểu int (*) [4] và kiểu int * là tin tức với tôi, và tập trung vào sự thất bại của tôi để hiểu mã. –

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