2010-03-05 13 views
5

Xem xét các báo cáo sau:Số học và mảng con trỏ: điều gì thực sự hợp pháp?

int *pFarr, *pVarr; 

int farr[3] = {11,22,33}; 
int varr[3] = {7,8,9}; 

pFarr = &(farr[0]); 
pVarr = varr; 

Ở giai đoạn này, cả hai con trỏ đang trỏ vào đầu của mỗi địa chỉ mảng tương ứng. Đối với * pFarr, chúng tôi hiện đang tìm kiếm tại 11 và cho * pVarr, 7.

Tương tự, nếu tôi yêu cầu nội dung của từng mảng thông qua * Farr và * varr, tôi cũng có được 11 và 7.

Vì vậy, rất tốt.

Bây giờ, hãy thử pFarr++pVarr++. Tuyệt quá. Chúng tôi hiện đang xem 22 và 8, như mong đợi.

Nhưng bây giờ ...

Đang cố gắng để di chuyển lên farr++varr++ ... và chúng tôi có được "loại sai trong lập luận để tăng".

Bây giờ, tôi nhận ra sự khác biệt giữa một con trỏ mảng và một con trỏ thông thường, nhưng vì hành vi của chúng tương tự nhau, tại sao giới hạn này? Điều này còn gây nhầm lẫn cho tôi khi tôi cũng xem xét rằng trong cùng một chương trình, tôi có thể gọi hàm sau theo cách có vẻ đúng đắn và theo cách khác không chính xác, và tôi nhận được hành vi tương tự, mặc dù ngược lại với những gì đã xảy ra mã được đăng ở trên !?

working_on_pointers (pFarr, farr); // calling with expected parameters 
working_on_pointers (farr, pFarr); // calling with inverted parameters 

.

void working_on_pointers (int *pExpect, int aExpect[]) { 

    printf("%i", *pExpect); // displays the contents of pExpect ok 
    printf("%i", *aExpect); // displays the contents of aExpect ok 

    pExpect++;    // no warnings or errors 
    aExpect++;    // no warnings or errors 

    printf("%i", *pExpect); // displays the next element or an overflow element (with no errors) 
    printf("%i", *aExpect); // displays the next element or an overflow element (with no errors) 

} 

Ai đó có thể giúp tôi hiểu tại sao các con trỏ mảng và con trỏ hoạt động theo cách tương tự trong một số ngữ cảnh, nhưng khác nhau ở các ngữ cảnh khác?

Cảm ơn rất nhiều.

EDIT: Noobs như bản thân mình hơn nữa có thể được hưởng lợi từ tài nguyên này: http://www.panix.com/~elflord/cpp/gotchas/index.shtml

+0

' Đang cố gắng để di chuyển lên Farr ++ và varr ++ ... và chúng tôi có được" loại sai trong lập luận để tăng, incrementing của một mảng không được phép, là tất cả. Và, bạn không cần dấu ngoặc đơn trong & (farr [0]);) Con trỏ là __NOT__ mảng! –

+2

"Tôi nhận ra sự khác biệt giữa một con trỏ mảng và một con trỏ thông thường". Rõ ràng, bạn không. Không có thứ như "con trỏ mảng". Mảng không phải là một con trỏ, dấu chấm. Bạn không thể tăng mảng. – AnT

+1

điều này là đúng. tuy nhiên khi bạn xem xét rằng trình biên dịch giảm mảng đến con trỏ trong các hàm, thì bạn có thể thấy một người mới sẽ nghĩ rằng một mảng đã được tăng lên như thế nào, trong thực tế nó là một con trỏ. – bitcruncher

Trả lời

7

Sự khác biệt là bởi vì đối với farr++ có bất kỳ tác dụng, ở đâu đó trình biên dịch sẽ cần phải lưu trữ mà farr sẽ đánh giá đến địa chỉ của phần tử thứ hai của mảng. Nhưng không có chỗ cho thông tin đó. Trình biên dịch chỉ phân bổ vị trí cho số nguyên 3.

Bây giờ, khi bạn tuyên bố rằng tham số chức năng là một mảng, thông số chức năng sẽ không phải là một mảng. Tham số hàm sẽ là một con trỏ. Không có tham số mảng nào trong C. Vì vậy, hai khai báo sau đây là tương đương

void f(int *a); 
void f(int a[]); 

Nó thậm chí không quan trọng số bạn đặt giữa dấu ngoặc - vì tham số thực sự sẽ là con trỏ, "kích thước" là chỉ bị bỏ qua.

này là như nhau cho các chức năng - hai sau là tương đương và có một con trỏ hàm như tham số:

void f(void (*p)()); 
void f(void p()); 

Trong khi bạn có thể gọi cả một con trỏ hàm và chức năng (vì vậy chúng được sử dụng tương tự), bạn cũng sẽ không thể để viết thư cho một hàm, bởi vì nó không phải là một con trỏ - nó chỉ chuyển đổi đến một con trỏ:

f = NULL; // error! 

Phần lớn giống như cách bạn không thể sửa đổi một mảng.

0

Hãy xem câu trả lời này tôi đã đăng liên quan đến sự khác biệt giữa con trỏ và mảng ở đây trên SO.

Hy vọng điều này sẽ hữu ích.

1

Cố gắng tăng farr hoặc varr không thành công vì không phải là con trỏ. Mỗi mảng là một mảng. Tên của một mảng, khi được đánh giá bởi chính nó (trừ khi toán hạng của toán tử sizeof hoặc address-of) đánh giá thành một giá trị (giá trị) là loại chính xác được gán cho một con trỏ. Cố gắng để tăng nó là một chút giống như cố gắng để tăng 17. Bạn có thể tăng một số mà chứa giá trị 17, nhưng tăng 17 bản thân nó sẽ không hoạt động. Tên của một mảng khá giống như vậy.

Đối với phần thứ hai của bạn, nó khá đơn giản: nếu bạn cố gắng khai báo một tham số hàm của kiểu mảng, trình biên dịch âm thầm "điều chỉnh" nó thành kiểu con trỏ. Như vậy, trong các số working_on_pointers, aExpectpExpectchính xác là cùng loại. Mặc dù ký hiệu kiểu mảng, bạn đã xác định aExpect là có loại 'con trỏ tới int'. Vì cả hai đều giống nhau, hoàn toàn mong đợi rằng chúng sẽ hành động giống nhau.

-2

bạn cần hiểu khái niệm cơ bản về mảng.

khi bạn khai báo một mảng tức là

int farr[] 

bạn đang thực sự tuyên bố một con trỏ với tuyên bố này

const int * farr 

tức là; một con trỏ "hằng số" thành số nguyên. vì vậy khi bạn làm farr ++ bạn đang thực sự cố gắng để thêm lên đến một con trỏ đó là không đổi, do đó trình biên dịch cung cấp cho bạn một lỗi.

nếu bạn cần hiểu, hãy thử khai báo một con trỏ với khai báo ở trên và bạn sẽ không thể thực hiện số học hợp pháp trên con trỏ bình thường.

P.S: nó được yên tĩnh một thời gian tôi đã được mã hóa trong C vì vậy tôi không chắc chắn về cú pháp chính xác. nhưng điểm mấu chốt là sự khác biệt giữa một con trỏ và một con trỏ liên tục.

+0

Điều này đơn giản là sai - farr không phải là một con trỏ thuộc loại nào - một mảng của nó, giá trị của nó có thể được chuyển đổi thành một con trỏ, nhưng nó không phải là mảng (hoặc farr) nữa. –

+0

Mảng không phải là con trỏ. –

5

Trong C, bạn không thể gán cho mảng.Vì vậy, đưa ra:

T data[N]; 

nơi T là một loại và N là một con số, bạn không thể nói:

data = ...; 

Với trên, và rằng data++; đang cố gắng để gán cho data, bạn sẽ có được lỗi.

Có một quy tắc đơn giản trong C về mảng và con trỏ. Đó là, trong ngữ cảnh giá trị, tên của một mảng tương đương với một con trỏ đến phần tử đầu tiên của nó và trong ngữ cảnh đối tượng, tên của một mảng tương đương với một mảng.

Ngữ cảnh đối tượng là khi bạn lấy kích thước của mảng bằng cách sử dụng sizeof hoặc khi bạn lấy địa chỉ của nó (&data) hoặc tại thời điểm khởi tạo mảng. Trong tất cả các bối cảnh khác, bạn đang ở trong bối cảnh giá trị. Điều này bao gồm việc truyền một mảng tới một hàm.

Vì vậy, chức năng của bạn:

void working_on_pointers (int *pExpect, int aExpect[]) { 

tương đương với

void working_on_pointers (int *pExpect, int *aExpect) { 

Chức năng không thể nói nếu nó đã được thông qua một mảng hoặc một con trỏ, vì tất cả nó thấy là một con trỏ.

Có thêm chi tiết trong câu trả lời cho các câu hỏi sau:

Cũng xem phần này của C for smarties trang web, mà là rất tốt bằng văn bản.

+0

tôi đã chọn một câu trả lời trước khi tôi thấy điều này, hy vọng bạn sẽ giải quyết cho một upvote? – bitcruncher

+0

@bitcruncher: Đừng lo lắng. Miễn là bạn hiểu chuyện gì đang xảy ra. –

-1

được, tôi có thể sai. nhưng mảng và con trỏ có thể được sử dụng luân phiên.

int * ptr = (int *)malloc(2* sizeof(int)); 
ptr[0]=1; 
ptr[1]=2; 

printf ("%d\n", ptr[0]); 
printf ("%d\n", ptr[1]); 

tại đây tôi đã khai báo một con trỏ và bây giờ tôi đang xử lý nó dưới dạng mảng.

hơn nữa:

Như một hệ quả của định nghĩa này, không có sự khác biệt rõ ràng trong hành vi của các "mảng subscripting" operator [] vì nó áp dụng cho các mảng và con trỏ. Trong biểu thức của mẫu [i], tham chiếu mảng "a" phân rã thành con trỏ, tuân thủ quy tắc ở trên và sau đó được chỉ định giống như biến con trỏ trong biểu thức p [i] (mặc dù các truy cập bộ nhớ cuối cùng sẽ là khác nhau, như được giải thích trong câu hỏi 2.2). Trong cả hai trường hợp, biểu thức x [i] (trong đó x là một mảng hoặc một con trỏ ), theo định nghĩa, giống hệt nhau đến * ((x) + (i)).

tham khảo: " 'http://www.lysator.liu.se/c/c-faq/c-2.html

+0

hiện đang xem xét mã sau đây \t int arr [5] = {1,2,3,4,5}; \t int * ptr = arr; tôi chỉ gán giá trị từ "arr" var thành "ptr" .. .. Tôi không yêu cầu phải sao chép một cách giải thích địa chỉ của phần tử thứ 0. vì tên của mảng là địa chỉ cho phần tử đầu tiên của mảng, tức là câu lệnh trên giống hệt với int * ptr = & arr [0]; –

+0

Vui lòng tham khảo điều này: http://www.google.ca/url?sa=t&source=web&ct=res&cd=8&ved=0CC8QFjAH&url=http%3A%2F%2Fdeneb.cs.kent.edu%2F~mikhail % 2Fclasses% 2Fioop.f00% 2FL19pointers.pdf & ei = w2yQS6-BNZOQNsHOhZEN & USG = AFQjCNHxqgxPgdzwqbiHqPpRXktudJ-4Zg & sig2 = FzIepm58ihz8mWoksFXISA và tham khảo các hộp "mảng tên và con trỏ liên tục" –

+0

thêm một referece: http://www.fredosaurus.com/ notes-cpp/arrayptr/26arraysaspointers.html –