Trường hợp sử dụng và lợi thế của con trỏ là gì? [đóng cửa]


10

Tôi thường đấu tranh để thấy những lợi thế của con trỏ (ngoại trừ lập trình cấp thấp).

Tại sao sử dụng char * thay vì String hoặc char [] hoặc những lợi thế mà số học con trỏ mang lại.

Vì vậy, những ưu và sử dụng trường hợp con trỏ là gì?


6
Điều này sẽ nghe có vẻ hơi tinh hoa, nhưng IMHO nếu bạn phải hỏi về ưu và nhược điểm của con trỏ, rất có thể bạn không cần chúng.
Jas

3
Có lẽ! Nhưng câu hỏi vẫn còn hiệu lực!
Zolomon

1
Điều này cũng không thực sự là ngôn ngữ bất khả tri, vì không phải tất cả các ngôn ngữ lập trình đều có con trỏ thực theo nghĩa C.
David Thornley

Câu trả lời:


6

Con trỏ là cần thiết cho vị trí bộ nhớ động, nhiều cấu trúc dữ liệu và xử lý hiệu quả lượng lớn dữ liệu. Nếu không có con trỏ, bạn phải phân bổ tất cả dữ liệu chương trình trên toàn cầu hoặc theo chức năng hoặc tương đương và bạn sẽ không cần truy vấn nếu lượng dữ liệu tăng vượt quá mức bạn cho phép ban đầu. Tôi ngần ngại sử dụng tuyệt đối ở đây, nhưng theo tôi biết tất cả các ngôn ngữ máy tính hiện đại đều có con trỏ ở dạng này hay dạng khác.

Trong hầu hết các ngôn ngữ sử dụng con trỏ, có một số loại tham chiếu nhất định là con trỏ và có lẽ một số loại tham chiếu nhất định không có, và không có sự khác biệt về công chứng. Một constế bào Lisp là một cặp con trỏ, mặc dù a fixnumkhông phải là một con trỏ. Trong Java, biến được sử dụng cho thể hiện của một lớp là một con trỏ, nhưng intkhông phải là. Cú pháp ngôn ngữ không phản ánh điều đó.

C là bất thường ở chỗ con trỏ là tùy chọn, rõ ràng và cho phép số học con trỏ rõ ràng. Hoàn toàn có thể viết struct foo bar; struct foo * baz;và một khi bạn đã phân bổ bộ nhớ cho bazbạn, bạn có thể sử dụng cả hai barbazđể thể hiện struct foos. Vì con trỏ là tùy chọn, rất hữu ích khi có sự khác biệt về công chứng. (Điều này rất cần thiết trong C ++ đối với các con trỏ thông minh, như đã cho boost::shared_ptr<foo> bar;, bar.reset()có một ý nghĩa và bar->reset()có khả năng có một ý nghĩa khác.)

(Trên thực tế, con trỏ rõ ràng thường được sử dụng trong các ngôn ngữ khác khi C ban đầu được phát triển, chẳng hạn như ^trong Pascal. C là ngôn ngữ cũ hơn hầu hết được sử dụng phổ biến hiện nay và nó cho thấy.)

Một trong những mục tiêu thiết kế của C là viết Unix và do đó cần xử lý các vị trí bộ nhớ một cách chi tiết. . gán địa chỉ bộ nhớ và tính toán địa chỉ mới. Điều này cũng dẫn đến một số quyết định thiết kế trong mảng C. C dựa nhiều vào số học con trỏ và thực sự một mảng phân rã thành một con trỏ trong rất nhiều tình huống. Truyền biến cho các hàm C bằng tham chiếu được thực hiện bằng con trỏ. Không có nhu cầu mạnh mẽ về mảng và chuyển các biến bằng cách tham chiếu ở dạng mà các ngôn ngữ đương đại khác có, vì vậy C đã không có được chúng.

Vì vậy, câu trả lời là, trong hầu hết các ngôn ngữ hiện nay, bạn sử dụng con trỏ liên tục mà không bị nhắc nhở về thực tế. Trong C và ở mức độ thấp hơn C ++, bạn sử dụng các con trỏ hoặc để làm những việc ở cấp độ thấp hoặc để hoàn thành những việc ở cấp độ cao hơn mà không có ký hiệu đặc biệt nào.


câu trả lời rất hay
Kate Gregory

1
Tôi chấp nhận câu trả lời này vì nó mô tả rõ nhất sự khác biệt mà tôi không thể nắm bắt được giữa các con trỏ trong C / C ++ và Tham chiếu trong Java.
OliverS

Sẽ tốt hơn nếu thêm một lời giải thích ngắn gọn về lý do tại sao Java không sử dụng các con trỏ để làm rõ hơn "con" nhận thức của Gosling (người tạo chính của Java).
Guido Anselmi

10

Cấu trúc dữ liệu phức tạp. Bạn không thể xây dựng một cái gì đó như danh sách được liên kết hoặc cây nhị phân mà không có con trỏ.

Không có "ưu" và "nhược điểm" của con trỏ. Chúng chỉ là một công cụ, giống như một cái búa.


5
Trong Java, không có con trỏ. Tuy nhiên, có thể xây dựng danh sách liên kết và cây nhị phân. Có một sự khác biệt giữa các tham chiếu (như trong Java) và các con trỏ (như trong C).
StartClass0830

7
Không có sự khác biệt giữa tài liệu tham khảo và con trỏ. Số học con trỏ là đặc trưng C; có những ngôn ngữ khác có con trỏ, nhưng không có số học con trỏ (ví dụ: Pascal).
zvrba

1
Con trỏ và tài liệu tham khảo không đồng nghĩa như bạn nghĩ. Đọc này để thấy sự khác biệt. stackoverflow.com/questions/57483/
trộm

4
Để giải quyết hai mục đầu tiên của danh sách đó: các tham chiếu Java CÓ THỂ được gán lại và chúng có thể trỏ đến null. Tính năng phân biệt của một con trỏ là cho phép bạn gián tiếp tham chiếu một đối tượng khác. Thử nghiệm litmus của tôi là: nếu bạn có thể xây dựng cấu trúc dữ liệu vòng tròn (mà bạn có thể với các tham chiếu Java), thì đó là một con trỏ. (Lưu ý rằng bạn không thể xây dựng cấu trúc dữ liệu vòng tròn với các tham chiếu C ++.)
zvrba

1
Có một sự khác biệt giữa con trỏ và tài liệu tham khảo. C #, ví dụ, có cả hai . ( blog.msdn.com/b/ericlippert/archive/2009/02/17/iêng )
Steven Evers

2
  • Với con trỏ, bạn có thể phân bổ và phân bổ bộ nhớ trong thời gian chạy.
  • Và bạn có thể sử dụng các cấu trúc dữ liệu lớn bên ngoài phạm vi được phép mà không bị sao chép.

Các tham chiếu trong C ++, Java và các loại ngôn ngữ khác chỉ là 'con trỏ an toàn'. Và các tài liệu tham khảo này được sử dụng rất nhiều trong Java.


1
Tài liệu tham khảo trong C ++ KHÔNG phải là con trỏ an toàn. Tài liệu tham khảo trong C ++ không liên quan gì đến con trỏ. Tài liệu tham khảo trong C ++ là bí danh . Chúng không thể được gán cho NULLvà chúng không thể được sửa đổi sau khi chúng được tạo.
Billy ONeal

@Billy: Các tham chiếu C ++ thường được triển khai bằng cách sử dụng các con trỏ và hoạt động tương tự trong một số thứ, vì vậy mọi người cứ nghĩ về chúng như một loại con trỏ bị ràng buộc.
David Thornley

2

Khá nhiều chương trình máy tính cần kiểm tra và thay đổi giá trị trong bộ nhớ (được gọi là nhìn trộm và chọc, đối với những người trong chúng ta đủ tuổi). Bạn cần kiểm soát vị trí của các giá trị đó trong bộ nhớ, để kết quả có thể dự đoán được (và trong một số trường hợp nhất định, thứ tự rất quan trọng: tải mã thực thi là một ví dụ). Do đó, bạn cần có một kiểu dữ liệu đại diện cho một vị trí trong bộ nhớ. Ngay cả khi môi trường lập trình của bạn che giấu điều đó dưới sự trừu tượng, nó vẫn ở đó.


2

char*là một ví dụ nhàu nát của con trỏ. Bạn có lẽ tốt hơn là sử dụng std::string(hoặc một số loại tốt hơn xử lý sự đặc biệt unicode / ansi / multibyte của bạn) hơn char*. Đối với hầu hết các ví dụ khác của con trỏ ( Employee*, PurchaseOrder*, ...), tuy nhiên, có rất nhiều ưu điểm:

  • phạm vi lớn hơn một hàm duy nhất - phân bổ đối tượng trên heap và truyền con trỏ xung quanh trong một thời gian dài
  • Hàm nhanh hơn gọi cho các đối tượng lớn vì bạn không có chi phí sao chép của giá trị truyền qua
  • một cách để kích hoạt chức năng thay đổi các tham số được truyền cho nó
  • tiết kiệm không gian và thời gian trong các bộ sưu tập chỉ sao chép một địa chỉ thay vì toàn bộ đối tượng

Trong thực tế, con trỏ rất quan trọng đến nỗi hầu hết các ngôn ngữ dường như không có chúng thực sự chỉ có chúng. Các kiểu tham chiếu trong C # và Java về cơ bản là các con trỏ được ngụy trang thành các đối tượng rắn.

Bây giờ, thao tác con trỏ ( p++trên một con trỏ, hoặc p += delta) là một câu chuyện hoàn chỉnh. Một số người nghĩ rằng nó nguy hiểm, một số người nghĩ rằng nó thật tuyệt. Nhưng đó thậm chí còn xa hơn từ câu hỏi của bạn.


1

Con trỏ có thể nhanh hơn và có thể phát sinh ít chi phí hơn, cả về cấu trúc dữ liệu và trong việc giữ dấu chân thực hiện chương trình. (Xin lưu ý từ 'có thể'.)

Nói chung, quy tắc là, nếu bạn đã phân bổ một tài nguyên, bằng cách thực hiện phân bổ của riêng bạn hoặc có một cái gì đó thay mặt bạn, thì công việc của bạn là giải phóng nó khi hoàn thành.

Gánh nặng của việc thực hiện ở trên là đặt trách nhiệm trở lại cho nhà phát triển, thay vì phải thực hiện thời gian chạy. Điều này có một số lợi thế hơn ở chỗ mọi thứ có thể được sống lâu hơn, hoặc vượt qua các ranh giới, hoặc được xử lý vào những thời điểm thích hợp hơn, hoặc không cần phải mang trọng lượng của một người thu gom rác xung quanh.

Trong các trường hợp kỳ lạ, thường liên quan đến ngoại lệ và phạm vi, có một số trường hợp cạnh đòi hỏi người ta phải cẩn thận hơn một chút nếu mã không dọn dẹp được tránh. Trên thực tế, những trường hợp này có thể được thiết kế xung quanh. Chúng tôi sống mà không có mã được quản lý trong nhiều thập kỷ.

Thông thường, những gì làm cho con trỏ "cứng" chỉ là không hiểu những gì đang xảy ra ở cấp độ phần cứng. Không có gì hơn là do dự.

Con trỏ cung cấp cho bạn nhiều quyền truy cập thô hơn và điều này có thể rất hữu ích, thông minh hoặc cần thiết. Bạn có thể chỉ đến bất cứ nơi nào và coi nó là bất cứ điều gì. Nếu bạn sử dụng sức mạnh giống như Chúa của bạn cho tốt, thì nó rất, rất tốt.

Phía con thường lãng phí bằng cách quên phát hành một cái gì đó, hoặc bằng cách phát hành nó nhiều lần, hoặc tham chiếu một cái gì đó sau khi nó được phát hành, hoặc từ chối một cái gì đó khi bạn không chỉ ra bất cứ nơi nào. Những điều này thường dẫn đến các sự cố ngoạn mục, và thành thật mà nói thường là dấu hiệu cho thấy bạn có vấn đề logic, thay vì con trỏ rất mong manh.

Nếu bạn là một nhà phát triển vững chắc, việc sử dụng các con trỏ sẽ không có vấn đề gì hơn bất kỳ cấu trúc dữ liệu nào khác. Một lần nữa, đó không phải là khoa học tên lửa, và mọi người đã làm điều đó trong nhiều thập kỷ mà không hề chớp mắt. Nó chỉ được dạy ít hơn trong những ngày này.

Tất cả những gì đã nói, trừ khi bạn có nhu cầu về con trỏ, các trường hợp lồi lõm và ngoại lệ mà một bộ sưu tập rác tốt cung cấp giúp làm việc trong một môi trường được quản lý đẹp hơn nhiều. Thật tuyệt khi có thể lấy một số bộ nhớ, sử dụng nó và từ bỏ nó, biết rằng một lúc nào đó, nó có thể bị loại bỏ, nếu nó có ý nghĩa để làm như vậy. Đó là mã ít hơn một chút về phần mã hóa, để đổi lấy thời gian chạy thực hiện một số nâng thêm.


0

Câu trả lời tốt nhất thực sự được bao gồm trong câu hỏi: con trỏ dành cho lập trình cấp thấp. Cấp, nếu bạn đang sử dụng C, không sử dụng con trỏ cũng giống như lập trình với một tay bị trói sau lưng, nhưng câu trả lời cho điều đó là sử dụng ngôn ngữ cấp cao hơn để thay thế.


-1

Con trỏ cung cấp khả năng hiển thị vào máy cần thiết cho hầu hết các chương trình thú vị. Hầu hết các ngôn ngữ hiện đại chỉ đơn giản là ẩn các bit gritty từ bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.