Những bộ óc trẻ có cần học các khái niệm con trỏ không?


89

Tại sao bậc thầy C Dennis Ritchie giới thiệu con trỏ trong C? Và tại sao các ngôn ngữ lập trình khác như VB.NET hoặc Java hoặc C # lại loại bỏ chúng? Tôi đã tìm thấy một số điểm trong Google và tôi cũng muốn nghe ý kiến ​​của bạn. Tại sao họ loại bỏ các khái niệm con trỏ trong các ngôn ngữ hiện đại?

Mọi người nói C là ngôn ngữ cơ bản và con trỏ là khái niệm làm cho C trở nên mạnh mẽ và nổi bật và khiến C vẫn phải cạnh tranh với các ngôn ngữ hiện đại hơn. Vậy thì tại sao họ lại loại bỏ con trỏ trong các ngôn ngữ hiện đại hơn?

Bạn có nghĩ rằng kiến ​​thức về con trỏ vẫn quan trọng đối với các lập trình viên mới? Mọi người đang sử dụng VB.NET hoặc Java ngày nay, hỗ trợ các tính năng nâng cao hơn C (và không sử dụng bất kỳ khái niệm con trỏ nào) và nhiều người như tôi thấy bây giờ (bạn bè của tôi) chọn các ngôn ngữ này bỏ qua C vì chúng hỗ trợ các tính năng nâng cao. Tôi bảo họ bắt đầu với C. Họ nói rằng thật lãng phí khi tìm hiểu các khái niệm về con trỏ khi bạn đang làm những điều nâng cao trong VB.NET hoặc Java mà không thể có trong C.

Bạn nghĩ sao?

Cập nhật :

Các ý kiến ​​tôi đọc trên Google là:

  1. Các máy tính trước đó quá chậm và không được tối ưu hóa.

  2. Sử dụng con trỏ giúp truy cập trực tiếp vào một địa chỉ và điều này giúp tiết kiệm thời gian thay vì tạo một bản sao của địa chỉ đó trong các cuộc gọi chức năng.

  3. Bảo mật kém hơn đáng kể khi sử dụng các con trỏ và đó là lý do tại sao Java và C # không bao gồm chúng.

Những điều này và một số nhiều hơn những gì tôi tìm thấy. Tôi vẫn cần một số câu trả lời có giá trị. Điều đó sẽ được đánh giá rất cao.


52
Java không có con trỏ? Đo không phải sự thật. Mọi tham chiếu đối tượng trong Java về cơ bản là một con trỏ.
quant_dev

20
Điều mà quant_dev có nghĩa là Java chứa đầy các con trỏ được sử dụng trong suốt, trong khi các lập trình viên không thể sử dụng chúng một cách rõ ràng.
sakisk

9
Đây là một bài viết từ Joel Spolsky có liên quan ... joelonsoftware.com/articles/fog0000000319.html
Joe Internet

11
"Tại sao bậc thầy C Dennis Ritchie lại giới thiệu con trỏ trong c?" Con trỏ không được giới thiệu trong c, chúng đi thẳng từ thực tiễn lắp ráp, bao gồm tên.
dmckee

14
@quaint_dev: Chà, Java thực sự không có con trỏ. Tài liệu tham khảo không thể làm mọi thứ con trỏ có thể làm, vì vậy cố gắng hiểu con trỏ theo cách tham chiếu không phải là cách để đi (và một sai lầm rất nhiều lập trình viên học C hoặc C ++ mắc phải). Con trỏ có thể làm số học. Tài liệu tham khảo không thể. (Một giới hạn thực sự bốc mùi mỗi khi tôi buộc phải sử dụng Java)
Billy ONeal

Câu trả lời:


128

Quay trở lại những ngày đó, các nhà phát triển đã làm việc gần gũi hơn với kim loại. C về cơ bản là một sự thay thế cấp cao hơn cho lắp ráp, gần với phần cứng như bạn có thể nhận được, do đó, điều tự nhiên là bạn cần con trỏ để có hiệu quả trong việc giải quyết các vấn đề mã hóa. Tuy nhiên, con trỏ là công cụ sắc bén, có thể gây ra thiệt hại lớn nếu sử dụng bất cẩn. Ngoài ra, việc sử dụng trực tiếp con trỏ mở ra khả năng cho nhiều vấn đề bảo mật, điều mà trước đây không phải là vấn đề (vào năm 1970, internet bao gồm khoảng vài chục máy trên một vài trường đại học và thậm chí còn không được gọi như vậy ...), nhưng ngày càng trở nên quan trọng hơn. Vì vậy, ngày nay các ngôn ngữ cấp cao hơn được thiết kế có ý thức để tránh các con trỏ bộ nhớ thô.

Nói rằng "những điều nâng cao được thực hiện trong VB.Net hoặc Java là không thể có trong C" cho thấy quan điểm rất hạn chế, để nói rằng ít nhất :-)

Trước hết, tất cả các ngôn ngữ này (thậm chí là lắp ráp) đều hoàn chỉnh, vì vậy về mặt lý thuyết, bất cứ điều gì có thể có trong một ngôn ngữ, đều có thể thực hiện được. Chỉ cần nghĩ về những gì xảy ra khi một đoạn mã VB.Net hoặc Java được biên dịch và thực thi: cuối cùng, nó được dịch thành (hoặc ánh xạ tới) mã máy, bởi vì đó là điều duy nhất mà máy hiểu được. Trong các ngôn ngữ được biên dịch như C và C ++, bạn thực sự có thể lấy toàn bộ mã máy tương đương với mã nguồn cấp cao hơn ban đầu, dưới dạng một hoặc nhiều tệp / thư viện thực thi. Trong các ngôn ngữ dựa trên VM, sẽ khó khăn hơn (và thậm chí là không thể) để có được toàn bộ biểu diễn mã máy tương đương của chương trình của bạn, nhưng cuối cùng nó vẫn ở đâu đó, trong phần sâu của hệ thống thời gian chạy và JIT.

Bây giờ, tất nhiên, đó là một câu hỏi hoàn toàn khác nhau cho dù một số giải pháp là khả thi trong một ngôn ngữ cụ thể. Không có nhà phát triển hợp lý nào có thể bắt đầu viết một ứng dụng web trong hội đồng :-) Nhưng thật hữu ích khi biết rằng hầu hết hoặc tất cả các ngôn ngữ cấp cao hơn đó đều được xây dựng dựa trên số lượng lớn thời gian chạy và mã thư viện lớp, một khối lớn được thực hiện bằng ngôn ngữ cấp thấp hơn, điển hình là C.

Vì vậy, để có được câu hỏi,

Bạn có nghĩ rằng kiến ​​thức về con trỏ cho những người trẻ tuổi [...] là quan trọng không?

Khái niệm đằng sau con trỏ là gián tiếp . Đây là một khái niệm rất quan trọng và IMHO mỗi lập trình viên giỏi nên nắm bắt nó ở một mức độ nhất định. Ngay cả khi ai đó chỉ làm việc với các ngôn ngữ cấp cao hơn, việc xác định và tham chiếu vẫn rất quan trọng. Không hiểu điều này có nghĩa là không thể sử dụng cả một nhóm các công cụ rất mạnh, hạn chế nghiêm trọng khả năng giải quyết vấn đề của một người trong thời gian dài.

Vì vậy, câu trả lời của tôi là có, nếu bạn muốn trở thành một lập trình viên thực sự giỏi, bạn cũng phải hiểu con trỏ (cũng như đệ quy - đây là khối vấp ngã điển hình khác cho các nhà phát triển vừa chớm nở). Bạn có thể không cần bắt đầu với nó - Tôi không nghĩ C là tối ưu như ngôn ngữ đầu tiên hiện nay. Nhưng tại một số điểm, người ta nên làm quen với sự gián tiếp. Không có nó, chúng ta không bao giờ có thể hiểu làm thế nào các công cụ, thư viện và khung mà chúng ta đang sử dụng thực sự hoạt động. Và một thợ thủ công không hiểu cách thức hoạt động của các công cụ của mình là rất hạn chế. Đủ công bằng, người ta cũng có thể nắm bắt được nó trong các ngôn ngữ lập trình cấp cao hơn. Một bài kiểm tra quỳ tốt là thực hiện chính xác một danh sách liên kết đôi - nếu bạn có thể làm điều đó bằng ngôn ngữ yêu thích của mình, bạn có thể khẳng định rằng bạn hiểu rõ về sự gián tiếp.

Nhưng nếu không phải vì bất cứ điều gì khác, chúng ta nên làm điều đó để học cách tôn trọng các lập trình viên cũ, những người đã cố gắng xây dựng những thứ không thể tin được bằng cách sử dụng các công cụ đơn giản lố bịch mà họ có (so với những gì chúng ta có bây giờ). Tất cả chúng ta đều đứng trên vai những người khổng lồ, và thật tốt khi chúng ta thừa nhận điều này, thay vì giả vờ rằng chúng ta là những người khổng lồ.


5
Đây là một câu trả lời hay nhưng nó không thực sự trả lời câu hỏi: "Những bộ óc trẻ có cần học các khái niệm con trỏ không?"
Falcon

11
+1 Câu trả lời hay. Tuy nhiên, tôi sẽ bỏ qua đối số hoàn chỉnh đầy đủ - đối với lập trình thực tế, đó là cá trích đỏ, như bạn cũng lưu ý sau này. Đó là lý thuyết tính toán, tức là hoàn thành chỉ có nghĩa là có một chương trình trong không gian (đối với nhiều ngôn ngữ, vô hạn) của các chương trình tiềm năng thực hiện cùng một thuật toán, chứ không thực sự khả thi hay thậm chí là có thể thực hiện được. Chỉ cần chỉ ra rằng tất cả mã máy ở cuối cũng chứng minh điều đó cũng không gây ra sự ngu ngốc "Tôi có thể làm mọi thứ bằng một ngôn ngữ vì chúng đều giống nhau, harhar!" hạt giống.

5
+1 cho "Và một thợ thủ công không hiểu cách thức hoạt động của các công cụ của mình là rất hạn chế."
quick_now

6
Ngoài ra, không hiểu cơ chế của con trỏ (và bằng các tham chiếu mở rộng) có nghĩa là bạn không hiểu các khái niệm về bản sao cơ sở hạ tầng nông / sâu, có thể gây ra các lỗi khó theo dõi nghiêm trọng. Ngay cả trong các ngôn ngữ cấp cao "hiện đại".
Mavrik

1
C được thiết kế để trở thành trình biên dịch di động cho Unix, tức là gần với kim loại.

39

Tôi nghĩ bạn cần phải khác biệt.

Java và các ngôn ngữ cấp cao khác không loại bỏ các con trỏ. Những gì họ đã làm là để loại bỏ số học con trỏ đơn giản.

Trong thực tế, Java vẫn cho phép số học con trỏ được bảo vệhạn chế : truy cập mảng. Trong C cũ đơn giản, truy cập mảng không có gì ngoài hội nghị. Đó là một ký hiệu khác, một đường cú pháp, nếu bạn muốn, để giao tiếp rõ ràng, những gì bạn đang làm.
Tuy nhiên, array[index]tương đương với *(array+index). Do đó, nó cũng tương đương với index[array]mặc dù tôi cho rằng một số trình biên dịch C có thể đưa ra cảnh báo cho bạn, nếu bạn làm điều đó.
Như một hệ quả, pointer[0]tương đương với *pointer. Điều đó đơn giản là vì "con trỏ tới một mảng" là địa chỉ của mục nhập đầu tiên của mảng và địa chỉ của các phần tử tiếp theo được tính bằng cách thêm chỉ mục.

Trong Java, mỹ phẩm con trỏ đơn giản (tham chiếu và hội thảo) không còn tồn tại nữa. Tuy nhiên con trỏ tồn tại. Họ gọi chúng là tài liệu tham khảo, nhưng nó không thay đổi nó là gì. Và truy cập mảng vẫn hoàn toàn giống nhau: Nhìn vào địa chỉ, thêm chỉ mục và sử dụng vị trí bộ nhớ đó. Tuy nhiên, trong Java, nó sẽ kiểm tra xem chỉ mục đó có nằm trong giới hạn của mảng mà bạn đã phân bổ ban đầu hay không. Nếu không, nó sẽ ném một ngoại lệ.

Bây giờ, lợi thế của cách tiếp cận Java là, bạn không có mã, chỉ viết một cách mù quáng các byte tùy ý vào các vị trí bộ nhớ tùy ý. Điều này cải thiện sự an toàn và bảo mật, bởi vì nếu bạn không kiểm tra lỗi tràn bộ đệm và như vậy, bộ thực thi sẽ làm điều đó cho bạn.

Nhược điểm của điều này là, nó đơn giản là ít mạnh mẽ hơn. Có thể thực hiện lập trình an toàn cho bộ nhớ trong C. Không thể hưởng lợi từ tốc độ và khả năng lập trình không an toàn trong Java.

Trên thực tế, không có gì khó về con trỏ hoặc số học con trỏ. Chúng chỉ được giải thích một cách bình thường theo những cách phức tạp, trong khi tất cả một con trỏ là một chỉ mục cho một mảng khổng lồ (không gian bộ nhớ của bạn), tất cả tham chiếu một giá trị sẽ cung cấp cho bạn chỉ mục nơi tìm thấy nó, tất cả những gì hội thảo sẽ làm là tìm kiếm giá trị tại một chỉ số nhất định. (Đây chỉ là một chút đơn giản, vì nó không tính đến việc các giá trị có kích thước khác nhau trong bộ nhớ, tùy thuộc vào loại của chúng. Nhưng đó là một chi tiết hoàn cảnh, thay vì một phần của khái niệm thực tế)

IMHO, mọi người trong công việc của chúng tôi sẽ có thể hiểu điều đó, hoặc họ chỉ đơn giản là trong lĩnh vực sai.


13
+1 Java và C # vẫn có con trỏ và tất nhiên NullPulumExceptions
jk.

5
Cũng lưu ý rằng các tài liệu tham khảo có thể trỏ đến các khu vực khác nhau theo thời gian, vì trình thu gom rác di chuyển công cụ xung quanh. Con trỏ thường tĩnh.

3
+1: này! Và tôi nghĩ có hai điều khó nắm bắt về con trỏ (nói chung): sự gián tiếp (xảy ra trong C, C #, Java, ...) và số học con trỏ ( không xảy ra trong Java theo cùng một cách). Theo tôi cả hai đều là những khái niệm quan trọng để học và cả hai đều là những trở ngại lớn cho người mới bắt đầu. Nhưng họ không nên nhầm lẫn: sự gián tiếp có thể xảy ra mà không có số học con trỏ.
Joachim Sauer

2
Trên thực tế, back2dosđã đúng ngay lần đầu tiên, vì (array + index)đã tính đến kích thước của các đối tượng (tính bằng C).
Matthew Flaschen

4
@CyberSkull, câu trả lời là đưa ra cú pháp tương đương array[index], và đó là *(array+index). Nếu bạn muốn chỉ ra cách trình biên dịch thực hiện mọi thứ bên trong, bạn có thể nói rõ ràng về byte hoặc cung cấp cho hội đồng.
Matthew Flaschen

24

Khái niệm về con trỏ rất quan trọng trong cơ thể kiến ​​thức lập trình máy tính nói chung. Hiểu khái niệm này là tốt cho các lập trình viên hoặc lập trình viên của bất kỳ ngôn ngữ nào, ngay cả khi ngôn ngữ không hỗ trợ trực tiếp.

Con trỏ có cách sử dụng trong Cấu trúc dữ liệu (danh sách được liên kết) và Thiết kế cơ sở dữ liệu (Khóa ngoài).

Các ngôn ngữ như VB và C # có thể truyền dữ liệu bằng cách "tham chiếu" đến các phương thức, có thể được coi là một loại con trỏ.

Hiểu nơi dữ liệu được phân bổ trong bộ nhớ (stack so với heap) vẫn quan trọng đối với hiệu quả của các thuật toán.

Học những điều cơ bản đúng là quan trọng trong quan điểm của tôi.


Tôi thấy khái niệm chung là hữu ích, nhưng tôi chưa bao giờ tìm thấy một tình huống mà tôi cần một con trỏ (chủ yếu là tôi sử dụng Java và PHP). Các ví dụ duy nhất mà các khóa học C ++ của tôi từng đưa ra cho con trỏ là sử dụng chúng để tạo các cấu trúc dữ liệu phức tạp hơn như danh sách và từ điển tồn tại trong bất kỳ ngôn ngữ lập trình cấp cao nào để bắt đầu ..
Ben Brocka

2
Bạn đúng theo một cách nào đó, nhưng khi bạn truyền dữ liệu cho các phương thức, rất có thể trong một số trường hợp, bạn đang truyền một con trỏ tới biến. Tuy nhiên, khái niệm về một con trỏ là hữu ích (theo ý kiến ​​của tôi) bất kể việc triển khai nó bằng ngôn ngữ phần mềm.
NoChance

1
@SirTapTap: Đó là bởi vì nếu bạn học C ++ trong một số loại khóa học, họ sẽ dạy bạn C ++. Không phải là cách tốt nhất để sử dụng C ++. Số học con trỏ thường bị che đậy bởi vì đó là thứ mà bạn có thể có kiến ​​thức về C ++ và không biết. Nhưng ngay cả những thứ như lặp đi lặp lại trong một bộ sưu tập chung cũng được thực hiện với các con trỏ trong C ++ thực / thành ngữ. (Vì đó là nền tảng của cách Thư viện Mẫu Chuẩn hoạt động)
Billy ONeal

@BillyONeal Con trỏ đã gần một nửa khóa học, thực sự, tôi vẫn chưa bao giờ tìm thấy cách sử dụng thực tế cho con trỏ (thông minh) như một lập trình viên, với điều kiện tôi chưa bao giờ cần sự kiểm soát trực tiếp đối với bộ nhớ trong bất cứ điều gì tôi đã làm. Tất nhiên luôn có khả năng khóa học được dạy kém, nó không chính xác là sở thích của tôi.
Ben Brocka

1
@SirTapTap: Sử dụng thực tế: mọi bộ sưu tập và thuật toán trong STL. std::sort, std::partition, std::find, Vv Họ làm việc với con trỏ, và họ làm việc với các đối tượng mà hành động như con trỏ (lặp). Và họ làm việc trên bất kỳ bộ sưu tập chung; danh sách được liên kết, mảng động, deques, cây hoặc bất kỳ loại bộ sưu tập nào do người dùng xác định. Bạn không thể loại trừu tượng mà không có con trỏ.
Billy ONeal

19

Vâng, vâng, vâng, vâng và vâng !!!

Nếu bạn không biết những điều cơ bản, bạn sẽ KHÔNG BAO GIỜ có thể giải quyết những vấn đề thực sự khó, lạ, khó và phức tạp xảy ra theo cách của bạn.

Và nếu bạn hiểu rất rõ những điều cơ bản, bạn sẽ có nhiều thị trường hơn trong thị trường việc làm.


Tôi đã làm việc một lần với một người đã lập trình được 10 năm và không biết con trỏ hoạt động như thế nào. Tôi (nhiều đàn em hơn) đã dành hàng giờ tại một bảng trắng giáo dục anh ta. Điều đó đã mở mắt tôi. Ông KHÔNG CÓ IDEA về rất nhiều điều cơ bản.

Biết càng nhiều càng tốt.


Nhưng waht là những điều cơ bản? Hội, mã nhị phân?
SiberianGuy

5
Trong khi quan điểm chung của bạn là "biết càng nhiều càng tốt" là một âm thanh, tôi sẽ đặt câu hỏi rằng bạn sẽ "KHÔNG BAO GIỜ có thể giải quyết các vấn đề thực sự khó khăn, kỳ lạ, khó khăn và phức tạp xảy ra theo cách của bạn" nếu bạn không hiểu con trỏ. Điều này bằng cách nào đó ngụ ý rằng tất cả các vấn đề khó khăn có thể được giải quyết bằng cách sử dụng các con trỏ "ma thuật" này, đây không phải là trường hợp. Các khái niệm giữa các con trỏ rất hữu ích để biết, nhưng chúng không trực tiếp cần thiết cho nhiều lĩnh vực lập trình.
Dan Diplo

4
> Tôi thậm chí đã không bắt đầu trên lang băm, lipton và bò rừng! và các hạt bò nấc!
Lie Ryan

2
Khái niệm cơ bản .... những thứ như cách lưu trữ công cụ. Sự khác biệt giữa một byte, một từ, cách làm việc được ký và không dấu. Con trỏ hoạt động như thế nào. Thật là một nhân vật. Làm thế nào mọi thứ được mã hóa trong ASCII (và những ngày này, Unicode). Làm thế nào một danh sách liên kết có thể được tạo trong bộ nhớ chỉ bằng các cấu trúc đơn giản. Làm thế nào chuỗi thực sự làm việc. Từ những điều nhỏ bé này, những điều lớn hơn phát triển.
quick_now

5
Biết càng nhiều càng tốt là một nguyên tắc tốt, nhưng tôi nghĩ bạn có xe ngựa trước ngựa. Các nhà phát triển giỏi cố gắng học mọi thứ họ có thể vì họ là những nhà phát triển giỏi. Khát khao kiến ​​thức là một đặc điểm của một nhà phát triển tốt. Nó không phải là nguyên nhân của một nhà phát triển tốt. Đi ra ngoài và học hỏi nhiều như bạn sẽ không thể làm cho bạn trở thành một nhà phát triển giỏi. Nó sẽ làm cho bạn một bách khoa toàn thư đi bộ, không có gì hơn. Nếu bạn là một nhà phát triển giỏi, THÌ bạn có thể ÁP DỤNG kiến ​​thức mà bạn đạt được để giải quyết vấn đề. Nhưng nếu bạn chưa phải là một nhà phát triển giỏi, kiến ​​thức sẽ không giúp bạn có được nhiều.
corsiKa

18

Vâng, sự hiểu biết là quan trọng.

Vài tháng trước, tôi đã lập trình trong C # và tôi muốn tạo một bản sao của một danh sách. Tất nhiên những gì tôi đã làm là NewList = OldList;và sau đó bắt đầu sửa đổi NewList. Khi tôi cố in ra cả hai danh sách, cả hai đều giống nhau, vì NewListchỉ là một con trỏ OldListvà không phải là bản sao, vì vậy tôi thực sự đã thay đổi OldListtất cả. Tôi không mất quá nhiều thời gian để tìm ra điều đó, nhưng một số bạn cùng lớp của tôi không nhanh đến thế và phải giải thích tại sao điều này lại xảy ra.

Thí dụ:

List<int> a = new List<int>();
a.Add(2);
a.Add(9);
a.Add(8);
a.Add(1);
List<int> b = new List<int>();
b = a; //Does not make a copy, b is just a synonym!
b.Sort();
for (int i = 0; i < a.Count; i++)
{
    Console.WriteLine("a: " + a[i] + " b: " + b[i]);
}

Và tất nhiên, kết quả là như thế này:

a: 1 b: 1
a: 2 b: 2
a: 8 b: 8
a: 9 b: 9

Biết cách sử dụng chúng không quan trọng, nhưng hiểu chúng là rất quan trọng!


2
Thay vào đó tại sao nên sử dụng chúng và khi nào sử dụng chúng là quan trọng nhất :)
niko

5
" NewListchỉ là một con trỏ tới OldList" - chính xác, cả hai NewListOldListchỉ là con trỏ, đề cập đến cùng một Listđối tượng.
Péter Török

Cũng quan trọng để hiểu rằng danh sách mới mà bạn đã tạo bkhông còn không có tham chiếu đến nó nữa, và bây giờ là rác.
TMN

14

Con trỏ khái niệm! = Con trỏ số học! = Con trỏ cú pháp

Vấn đề đầu tiên luôn luôn là, nếu bạn cần (và bạn làm) hiểu về bản sao sâu / nông, chuyển qua tham chiếu / chuyển theo giá trị, v.v ... Hai vấn đề khác chỉ khi ngôn ngữ của bạn cho phép bạn sử dụng chúng.


1
Ngày nay bạn chỉ cần biết khái niệm cơ bản của tài liệu tham khảo, không phải cú pháp con trỏ / toán học. Tôi đã học được con trỏ (với số học & cú pháp) trong C trở lại trong ngày. Các ngôn ngữ tôi hiện đang lập trình không xử lý các con trỏ kiểu C cho phép bạn làm những việc không an toàn. Người ta có thể hiểu tại sao trong python a=[1,2]; b=a; a.append(3)rằng cả hai absẽ cùng tham chiếu cùng một đối tượng [1,2,3]mà không biết nội dung như trong C, iphần tử thứ của một mảng có thể được tham chiếu bởi arr[i]hoặc i[arr]cả hai *(arr+i). Tôi thích khi ngôn ngữ không i[arr]được sử dụng.
dr jimbob

" Hai vấn đề khác chỉ khi ngôn ngữ của bạn cho phép bạn sử dụng chúng. " - Câu đó mang theo sự tự hủy của chính nó. Theo định nghĩa, ngôn ngữ du jour rất khó có thể là cùng một ngôn ngữ được sử dụng vào ngày mai. Và ngày mai bạn có thể phải đối mặt với một ngôn ngữ kích hoạt con trỏ. Dòng dưới cùng? Tốt hơn là một người nắm bắt nó bây giờ, một lần và mãi mãi. Nó không khó lắm, nhưng nó đáng giá.
JensG

14

Tại sao bậc thầy C Dennis Ritchie giới thiệu con trỏ trong C?

Bởi vì con trỏ là một cơ chế rất mạnh có thể được sử dụng theo nhiều cách.

Và tại sao các ngôn ngữ lập trình khác như VB.NET hoặc Java hoặc C # loại bỏ chúng?

Bởi vì con trỏ là một cơ chế rất nguy hiểm có thể bị lạm dụng theo nhiều cách.

Tôi nghĩ rằng các lập trình viên nên tìm hiểu về con trỏ, nhưng từ góc độ giáo dục, việc giới thiệu chúng sớm là không khôn ngoan. Lý do là chúng được sử dụng cho rất nhiều mục đích khác nhau, thật khó để nói là người mới bắt đầu tại sao bạn lại sử dụng một con trỏ trong một trường hợp cụ thể.

Dưới đây là danh sách không đầy đủ những gì con trỏ được sử dụng cho:

  • phân bổ động ( new T)
  • cấu trúc dữ liệu đệ quy ( struct T { T* next; /* ... */ };)
  • iterators trên mảng ( for (T* p = &a[0]; p != &a[0] + n; ++p) { ... })
  • chia sẻ quyền truy cập vào các đối tượng ( T* new_pointer = existing_pointer;)
  • đa hình phụ ( T* pointer_to_base = pointer_to_derived;)
  • cuộc gọi kế thừa bằng cách tham chiếu ( mutate(&object);)
  • loại tùy chọn ( if (p) { /* ... */ })

Lưu ý rằng việc sử dụng một cơ chế duy nhất cho tất cả các khái niệm này thể hiện cả sức mạnh và sự tao nhã cho lập trình viên có kinh nghiệm và tiềm năng nhầm lẫn lớn cho người mới biết lập trình.


" Tại sao bậc thầy C Dennis Ritchie giới thiệu con trỏ trong C ? Bởi vì con trỏ là một cơ chế rất mạnh có thể được sử dụng theo nhiều cách." - Tôi không biết thực tế, nhưng tôi đoán nó có liên quan đến các hướng dẫn máy móc được gói gọn trong ngôn ngữ C và các tiền thân của lập trình viên C. Trình biên dịch được sử dụng để suy nghĩ theo con trỏ, vì vậy nó sẽ được một bất ngờ nếu anh ta không sử dụng những cơ chế mạnh mẽ nổi tiếng này. Bất cứ điều gì khác sẽ là quá xa cho năm 1978 hoặc thậm chí những năm 1960.
JensG

12

Tại sao? Bạn có thể viết một hệ thống khổng lồ với trình thiết kế biểu mẫu và trình tạo mã. Nó không đủ sao? (trớ trêu)

Và bây giờ, nghiêm túc, con trỏ không phải là một phần quan trọng của lập trình trong nhiều lĩnh vực, nhưng chúng cho phép mọi người hiểu cách thức hoạt động của bên trong. Và nếu chúng ta sẽ không có ai hiểu được cách thức hoạt động của bên trong, sẽ có một tình huống trong đó SQL2020, Windows 15 và Linux 20.04 sẽ được viết trong thùng rác thu thập máy ảo chạy trên 30 lớp trừu tượng, với mã được tạo qua IDE, bằng JavaScript .

Đây chắc chắn không phải là những gì tôi muốn thấy.

Vì vậy, có, họ phải, chắc chắn!


2
Tốt hài hước! +1 và hoàn toàn đồng ý.
heltonbiker

7

Cả con trỏ loại bỏ Java và C #, chúng đều có các tham chiếu gần giống nhau. Những gì đã được loại bỏ là mỹ phẩm con trỏ, có thể được bỏ qua trong một khóa học giới thiệu.
Không có ứng dụng không tầm thường nào có thể được thực hiện mà không có khái niệm về con trỏ hoặc tham chiếu, vì vậy nó đáng để dạy (Không thể phân bổ bộ nhớ động mà không có chúng).

Hãy xem xét những điều sau trong C ++ và Java và tôi đoán nó không khác lắm trong C #:
aClass *x = new aClass();
aClass x = new aClass();
Không thực sự có quá nhiều sự khác biệt giữa các con trỏ và các tham chiếu, phải không?
Nên tránh sử dụng con trỏ, trừ khi cần thiết và khi lập trình với các mô hình mức cao, vì vậy không có nhiều vấn đề ở đó.


6

Các lập trình viên chuyên nghiệp nên làm chủ con trỏ.

Những người muốn biết lập trình nên tìm hiểu về sự tồn tại và ý nghĩa của nó, nhưng không nhất thiết phải sử dụng chúng.

Những người muốn giải quyết các vấn đề cá nhân thông qua lập trình (như tôi, người sử dụng nhiều tập lệnh Python) rất có thể bỏ qua chúng.

Vâng, đó là ý kiến ​​của tôi ...; o)


3

Con trỏ địa chỉ biến là một trường hợp cụ thể của khái niệm tổng quát hơn về sự gián tiếp. Indirection được sử dụng trong hầu hết (tất cả?) Các ngôn ngữ hiện đại trong nhiều cấu trúc như đại biểu và cuộc gọi lại. Hiểu khái niệm về sự gián tiếp cho phép bạn biết khi nào và làm thế nào để sử dụng tốt nhất các công cụ này.


3

Vắng mặt ! Tất cả mọi người chương trình cần phải hiểu con trỏ và chỉ định.

Con trỏ là cách một lượng lớn truy cập dữ liệu được thực hiện trong tất cả các ngôn ngữ. Con trỏ là một tính năng phần cứng của tất cả các bộ vi xử lý. Các ngôn ngữ cấp cao như Java, VB & C # về cơ bản không cho phép truy cập trực tiếp vào các con trỏ từ những người sử dụng ngôn ngữ có tham chiếu. Các tham chiếu đề cập đến các đối tượng thông qua sơ đồ quản lý bộ nhớ của ngôn ngữ (có thể là một con trỏ có siêu dữ liệu hoặc chỉ là một số cho bảng bộ nhớ chẳng hạn).

Hiểu cách con trỏ hoạt động là cơ bản để hiểu cách máy tính thực sự hoạt động. Con trỏ cũng linh hoạt và mạnh mẽ hơn so với tài liệu tham khảo.

Ví dụ, lý do tại sao các mảng bắt đầu ở chỉ số 0 là vì các mảng thực sự là tốc ký cho số học con trỏ. Không tìm hiểu về cách con trỏ hoạt động, nhiều lập trình viên khởi đầu không hoàn toàn nhận được mảng.

int a, foo[10];
foo[2] = a;

Dòng 2 trong số học con trỏ sẽ là:

*(foo + sizeof(int) * 2) = a;

Không hiểu con trỏ, người ta không thể hiểu quản lý bộ nhớ, ngăn xếp, heap hoặc thậm chí là mảng! Ngoài ra, người ta cần phải hiểu con trỏ và hội thảo để hiểu cách các chức năng và đối tượng được thông qua.

TL: DR : Hiểu con trỏ là nền tảng để hiểu máy tính thực sự hoạt động .


2

Tôi nghĩ rằng vấn đề là cần phải xử lý các con trỏ giảm đi khi các lập trình viên xử lý ít hơn với phần cứng trực tiếp mà họ đang chạy. Ví dụ, phân bổ cấu trúc dữ liệu danh sách được liên kết theo cách hoàn toàn phù hợp với chuỗi các mô-đun bộ nhớ 640 byte mà phần cứng chuyên dụng có.

Xử lý các con trỏ bằng tay có thể dễ bị lỗi (dẫn đến rò rỉ bộ nhớ và mã có thể khai thác) và tốn thời gian để xử lý đúng. Vì vậy, Java và C # vv hiện đang quản lý bộ nhớ và con trỏ của bạn cho bạn thông qua Máy ảo (VM) của chúng. Điều này được cho là kém hiệu quả hơn so với sử dụng C / C ++ thô, mặc dù các máy ảo không ngừng cải thiện.

C (và C ++) vẫn là các ngôn ngữ được sử dụng rộng rãi, đặc biệt là trong không gian phần cứng tính toán hiệu năng cao, trò chơi và nhúng. Cá nhân tôi rất biết ơn Tôi đã học về con trỏ vì việc chuyển đổi sang các tham chiếu của Java (một khái niệm tương tự với con trỏ) rất dễ dàng và tôi đã không bị mất khi nhìn thấy NullPulumException đầu tiên của mình (mà thực sự nên được gọi là NullReferenceException, nhưng tôi lạc đề) .

Tôi sẽ khuyên bạn nên tìm hiểu về khái niệm con trỏ khi chúng vẫn củng cố rất nhiều cấu trúc dữ liệu, v.v. Sau đó, hãy chọn một ngôn ngữ mà bạn yêu thích để làm việc, biết rằng nếu một thứ như NPE xuất hiện, bạn sẽ biết điều gì đang thực sự xảy ra .


0

Đây là sự thật khách quan:

Một số ngôn ngữ hỗ trợ truy cập bộ nhớ trực tiếp (con trỏ), một số ngôn ngữ thì không. Có những lý do tốt cho mỗi trường hợp.

  1. Như ai đó đã nói ở đây, vào thời của C, quản lý bộ nhớ tự động không phức tạp như ngày nay. Và mọi người đã quen với nó, dù sao đi nữa. Các lập trình viên giỏi hồi đó có hiểu biết sâu sắc hơn về các chương trình máy tính so với thế hệ chúng tôi (tôi 21). Họ đã sử dụng thẻ đục lỗ và ngày chờ đợi trong một thời gian biên dịch trên máy tính lớn. Họ có thể biết tại sao mọi bit trong mã của họ tồn tại.

  2. Ưu điểm rõ ràng của các ngôn ngữ như C là chúng cho phép bạn kiểm soát tốt hơn chương trình của mình. Khi nào bạn thực sự cần nó, những ngày này? Chỉ khi bạn đang tạo các ứng dụng cơ sở hạ tầng, chẳng hạn như các chương trình liên quan đến hệ điều hành và môi trường thời gian chạy. Nếu bạn muốn phát triển phần mềm tốt, nhanh, mạnh và đáng tin cậy, thì quản lý bộ nhớ tự động thường là lựa chọn tốt hơn của bạn.

  3. Thực tế là việc truy cập bộ nhớ trực tiếp hầu hết đã bị lạm dụng trong quá trình lịch sử phát triển phần mềm. Mọi người đã tạo ra các chương trình làm rò rỉ bộ nhớ và thực sự chậm hơn do phân bổ bộ nhớ dự phòng (trong C thật dễ dàng và phổ biến để mở rộng không gian bộ nhớ ảo của quy trình cho mỗi lần cấp phát).

  4. Ngày nay, các máy ảo / thời gian chạy thực hiện công việc tốt hơn nhiều so với 99% các lập trình viên trong việc phân bổ và giải phóng bộ nhớ. Trên hết, chúng cho phép bạn linh hoạt hơn trong luồng bạn muốn chương trình của mình có, bởi vì bạn (phần lớn) không bị chiếm dụng với việc giải phóng bộ nhớ được phân bổ vào đúng thời điểm và địa điểm.

  5. Về kiến ​​thức. Tôi nghĩ thật đáng ngưỡng mộ khi các lập trình viên biết cách môi trường mà họ lập trình được thực hiện. Không nhất thiết phải đến những chi tiết nhỏ nhất, nhưng bức tranh lớn.

Tôi nghĩ rằng biết làm thế nào con trỏ hoạt động (ít nhất) là thú vị. Tương tự như biết làm thế nào đa hình được thực hiện. Quá trình của bạn lấy bộ nhớ từ đâu và như thế nào. Đây là những điều luôn được tôi quan tâm. Tôi có thể thành thật nói rằng họ đã biến tôi thành một lập trình viên giỏi hơn, nhưng tôi không thể nói rằng họ là một nhu cầu giáo dục cho bất cứ ai muốn trở thành một lập trình viên giỏi. Trong cả hai trường hợp, biết nhiều hơn thường sẽ giúp bạn làm việc tốt hơn .

  1. Theo cách tôi thấy, nếu tất cả những gì bạn được yêu cầu là tạo một ứng dụng bằng Java hoặc C # hoặc một cái gì đó tương tự, thì bạn cần tập trung vào các kỹ thuật triển khai và thiết kế phù hợp. Mã kiểm tra, mã sạch, mã linh hoạt. Theo thứ tự đó.

Bởi vì ngay cả khi bạn không biết tất cả các chi tiết nhỏ, một người nào đó sẽ có thể thay đổi những gì bạn đã tạo thành thứ gì đó đơn giản là hoạt động tốt hơn. Và đó thường không phải là một công việc khó khăn, một khi bạn có một thiết kế phù hợp, sạch sẽ và có thể kiểm tra được (và đó thường là phần lớn công việc).

Nếu tôi là một người phỏng vấn muốn thuê một người nào đó cho một ứng dụng ngôn ngữ cấp cao, đó sẽ là những điều tôi quan tâm nhất.

Kiến thức cấp thấp là một phần thưởng. Nó tốt cho việc gỡ lỗi và đôi khi tạo ra các giải pháp tốt hơn một chút. Nó làm cho bạn một người thú vị, chuyên nghiệp. Nó cho bạn một số sự tôn trọng tại nơi làm việc của bạn.

Nhưng trong thế giới ngày nay, đó không phải là yêu cầu thiêng liêng.


-1

Đối với hầu hết các mục đích thực tế trong các ngôn ngữ OO cấp cao, việc hiểu các tài liệu tham khảo là đủ, bạn không thực sự cần phải hiểu cách các ngôn ngữ này triển khai các tài liệu tham khảo về mặt con trỏ.

Có rất nhiều cách tiếp cận đa mô hình hiện đại và nhiều chức năng mà tôi đánh giá cao hơn nhiều so với việc có thể thực hiện số học con trỏ ưa thích, viết hàm sao chép chuỗi được tối ưu hóa thứ 1000 có thể hoạt động kém hơn String.copy của std lib của bạn theo bất kỳ cách nào.

Trước tiên, tôi khuyên bạn nên tìm hiểu nhiều khái niệm khác nhau, cấp độ cao hơn và phân nhánh để học các ngôn ngữ có thiết kế khác nhau để mở rộng tầm nhìn của bạn trước khi cố gắng chuyên về các công cụ gần với phần cứng.

Tôi thường thấy những nỗ lực hoàn toàn thất bại trong việc tối ưu hóa vi mô weblet hoặc mã tương tự để tăng 5%, khi lưu vào bộ nhớ cache (ghi nhớ), tối ưu hóa SQL hoặc chỉ điều chỉnh cấu hình máy chủ web có thể mang lại 100% hoặc nhiều hơn với ít nỗ lực. Đấu tranh với con trỏ là tối ưu hóa sớm trong hầu hết các trường hợp.


-1

Chắc chắn, chúng ta cần có một khái niệm kỹ lưỡng về con trỏ, nếu bạn thực sự muốn trở thành một lập trình viên giỏi. Lý do cho khái niệm Con trỏ là một truy cập trực tiếp vào giá trị của bạn sẽ trở nên hiệu quả và hiệu quả hơn với các hạn chế về thời gian ...

Ngoài ra, ngày nay, khi xem xét Ứng dụng di động, bộ nhớ rất hạn chế, chúng tôi cần sử dụng nó rất cẩn thận để thao tác của nó rất nhanh với phản hồi của người dùng ... Vì vậy, với mục đích này, chúng tôi cần tham khảo trực tiếp đến giá trị ...

Hãy xem xét các thiết bị của Apple, hoặc ngôn ngữ Objective C, hoàn toàn chỉ hoạt động với khái niệm con trỏ. Tất cả các biến được khai báo trong Mục tiêu C đều có Con trỏ. Bạn cần phải đi qua wiki của Objective C


Ngày nay, các ứng dụng di động có nhiều bộ nhớ hơn so với một số trung tâm dữ liệu C được hình thành. Nhiều ứng dụng di động được viết bằng Java hoặc html + javascript hoàn toàn không có con trỏ (công cụ này có TÀI LIỆU THAM KHẢO). Chỉ một phần rất nhỏ các lập trình viên rất chuyên nghiệp từng thấy các lớp HĐH bên dưới.
Jürgen Strobel
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.