[MUSIC CHƠI]
>> DOUG LLOYD: OK vậy là một gợi ý trước khi bắt đầu từ đây.
Nếu bạn không theo dõi các video trên Con trỏ có thể bạn muốn làm như vậy đầu tiên.
Bởi vì bộ phim này là một cách làm việc với con trỏ.
>> Vì vậy, nó sẽ nói chuyện về một số khái niệm
rằng chúng tôi bao gồm trong Con trỏ video, và chúng tôi
đi bóng qua chúng ngay bây giờ, giả định rằng họ đã
loại hiểu.
Vì vậy, đó chỉ là cảnh báo công bằng của bạn rằng nếu bạn nhìn thấy video này
và bạn đã không nhìn thấy con trỏ video, nó có thể loại
bay trên đầu của bạn một chút.
Và do đó, nó có thể được tốt hơn để xem nó trong thứ tự đó.
>> Vì vậy, chúng ta đã thấy một cách để làm việc với con trỏ,
đó là chúng ta khai báo một biến, và sau đó chúng tôi
khai báo một biến khác, một con trỏ biến, trỏ đến nó.
Vì vậy, chúng tôi đã tạo ra một biến với một tên, chúng tôi đã
tạo ra một biến thứ hai với một tên, và chúng tôi chỉ là biến thứ hai
tại đó đầu tiên.
Loại này có một vấn đề mặc dù, bởi vì nó
đòi hỏi chúng ta phải biết chính xác bao nhiêu bộ nhớ chúng tôi
sẽ cần lúc này Chương trình của chúng tôi được biên dịch.
>> Tại sao vậy?
Bởi vì chúng ta cần phải có khả năng tên hoặc xác định tất cả các biến thể
chúng ta có thể gặp.
Chúng tôi có thể có một mảng mà có thể là có thể giữ rất nhiều thông tin,
nhưng nó vẫn không chính xác, đủ chính xác.
Điều gì nếu chúng ta không biết, nếu chúng ta không có ý tưởng
bao nhiêu chúng tôi sẽ cần ít thời gian biên dịch?
Hoặc nếu chương trình của chúng tôi sẽ chạy trong một thời gian rất dài,
chấp nhận sử dụng khác nhau dữ liệu, và chúng tôi không thể thực sự
ước tính xem chúng tôi sẽ cần 1.000 đơn vị?
>> Nó không giống như chúng ta có thể nói tại dòng lệnh
nhập bao nhiêu mục bạn nghĩ rằng bạn sẽ cần.
Vâng những gì nếu đoán đó là sai?
Cấp phát bộ nhớ động loại cho phép chúng ta con đường
để có được xung quanh vấn đề này cụ thể.
Và cách nào nó là bằng cách sử dụng con trỏ.
>> Chúng tôi có thể sử dụng con trỏ để được tiếp cận với động
cấp phát bộ nhớ, bộ nhớ đó là phân bổ như chương trình của bạn đang chạy.
Nó không được phân bổ tại thời gian biên dịch.
Khi bạn tự động phân bổ bộ nhớ nó đến từ một hồ bơi
bộ nhớ được gọi là heap.
Trước đây tất cả các bộ nhớ chúng tôi đã được làm việc với trong khóa học
đã được phát ra từ một hồ bơi bộ nhớ được gọi là stack.
Một cách tốt để thường giữ trong mind-- và quy tắc này
không luôn luôn đúng, nhưng khá nhiều gần như
luôn giữ true-- là bất kỳ thời gian bạn đưa ra một tên biến nó
lẽ sống trên stack.
Và bất cứ lúc nào bạn không cung cấp cho một biến tên,
mà bạn có thể làm với bộ nhớ động phân bổ, nó sống trên heap.
>> Bây giờ tôi là loại trình bày này là nếu có hai hồ này của bộ nhớ.
Nhưng bạn có thể đã nhìn thấy điều này sơ đồ, mà nói chung là
một đại diện của nhớ những gì trông giống như,
và chúng tôi sẽ không quan tâm đến tất cả các công cụ ở phía trên và phía dưới.
Phần này trong những gì chúng ta quan tâm là trung ở đây, heap và stack.
Như bạn có thể nhìn thấy bằng cách nhìn vào sơ đồ này,
này thực sự không phải là hai hồ bơi riêng biệt của bộ nhớ.
Đó là một hồ bơi được chia sẻ bộ nhớ nơi bạn bắt đầu, trong hình ảnh này
bạn bắt đầu ở phía dưới và bắt đầu điền lên
từ dưới cùng với đống, và bạn bắt đầu ở đầu và bắt đầu điền lên
từ trên xuống với đống.
Nhưng nó thực sự là cùng một hồ bơi, nó chỉ
điểm khác nhau, địa điểm khác nhau trong bộ nhớ đang được phân bổ.
Và bạn có thể chạy ra khỏi bộ nhớ bằng cách hoặc là có
đống đi tất cả các cách xuống phía dưới, hoặc có
stack đi tất cả các cách để trên đầu, hoặc có heap và stack
gặp gỡ với nhau.
Tất cả những người có thể điều kiện gây ra chương trình của bạn
chạy ra khỏi bộ nhớ.
Vì vậy, giữ cho rằng trong tâm trí.
Khi chúng ta nói về heap và stack
chúng tôi đang thực sự nói về cùng một đoạn chung của bộ nhớ, chỉ cần
các phần khác nhau của bộ nhớ đó.
>> Vì vậy, làm thế nào để chúng ta có được tự động phân bổ bộ nhớ ở nơi đầu tiên?
Làm thế nào để chương trình của chúng tôi có được nhớ như nó đang chạy?
Vâng C cung cấp một chức năng gọi là malloc, cấp phát bộ nhớ, mà
bạn thực hiện một cuộc gọi đến, và bạn vượt qua trong bao nhiêu byte của bộ nhớ mà bạn muốn.
Vì vậy, nếu chương trình của bạn đang chạy và bạn muốn một thời gian chạy số nguyên,
bạn có thể mallock bốn byte của bộ nhớ, malloc ngoặc bốn.
>> mallock sẽ đi qua nhìn qua đống,
bởi vì chúng ta tự động phân bổ bộ nhớ,
và nó sẽ trở về với bạn một con trỏ tới bộ nhớ mà.
Nó không cung cấp cho bạn memory-- đó nó không cho nó một cái tên,
nó mang lại cho bạn một con trỏ đến nó.
Và đó là lý do tại sao một lần nữa tôi nói rằng điều quan trọng để có thể
đã xem phim con trỏ trước khi chúng ta đi sâu vào điều này.
Vì vậy, malloc sẽ cho bạn trở lại một con trỏ.
>> Nếu mallock không thể cung cấp cho bạn bất kỳ bộ nhớ bởi vì bạn đã chạy ra,
nó sẽ cho bạn trở lại một con trỏ null.
Bạn có nhớ những gì sẽ xảy ra nếu chúng tôi thử và tới đích của một con trỏ null?
Chúng ta đau khổ một lỗi seg, phải không?
Đó có thể là không tốt.
>> Vì vậy, mỗi khi bạn thực hiện cuộc gọi để malloc bạn luôn luôn, luôn luôn
cần phải kiểm tra có hay không con trỏ nó đã cho bạn trở lại là null.
Nếu có, bạn cần phải kết thúc chương trình của bạn bởi vì nếu bạn cố gắng và tới đích
các con trỏ null bạn đang đi phải chịu đựng một lỗi phân khúc
và chương trình của bạn đi đến sụp đổ anyway.
Vì vậy, làm thế nào để chúng ta tĩnh có được một số nguyên?
>> int x.
Chúng tôi đã có thể làm được điều đó một loạt các lần, phải không?
Điều này tạo ra một biến gọi là x sống trên stack.
Làm thế nào để chúng ta tự động lấy một số nguyên?
Int sao px bằng malloc 4.
>> Hoặc một cách thích hợp hơn chúng tôi muốn nói int sao px
bằng kích thước malloc của int, chỉ để ném một số ít
con số ma thuật xung quanh chương trình của chúng tôi.
Điều này sẽ cho ta được bốn byte của bộ nhớ từ đống,
và con trỏ chúng tôi nhận trở lại để nó được gọi là px.
Và sau đó chỉ như chúng ta đã thực hiện trước đó chúng tôi
có thể tới đích px truy cập vào bộ nhớ.
Làm thế nào để chúng ta có được một số nguyên từ người sử dụng?
Chúng tôi có thể nói int x bằng được int.
Đó là khá đơn giản.
Điều gì nếu chúng tôi muốn tạo ra một mảng của x phao sống trên stack?
nổi stack_array-- đó là tên các dấu ngoặc vuông array-- chúng tôi x.
Điều đó sẽ tạo cho chúng ta một mảng của x phao sống trên stack.
Chúng ta có thể tạo ra một mảng phao sống trên đống, quá.
Các cú pháp có thể xem xét một ít cồng kềnh hơn,
nhưng chúng ta có thể nói float sao heap_array bằng
malloc x lần kích thước của phao.
Tôi cần đủ chỗ cho hàng x giá trị điểm trôi.
Vì vậy, nói tôi cần 100 phao, hoặc 1.000 phao nổi.
Vì vậy, trong trường hợp đó nó sẽ là 400 byte cho 100 phao,
hoặc 4.000 byte cho 1.000 phao, bởi vì mỗi float chiếm
bốn byte của không gian.
>> Sau khi làm điều này tôi có thể sử dụng cú pháp khung vuông trên heap_array.
Cũng như tôi làm trên stack_array, tôi có thể truy cập vào các phần tử riêng lẻ
sử dụng heap_array không, một heap_array.
Nhưng nhớ lại lý do chúng tôi có thể làm điều đó là bởi vì tên của một mảng trong C
thực sự là một con trỏ trỏ tới Yếu tố đầu tiên của mảng đó.
Vì vậy, thực tế là chúng ta đang khai báo mảng phao trên stack đây
thực sự là một chút sai lầm.
Chúng tôi thực sự đang ở trong dòng thứ hai của mã có
cũng tạo ra một con trỏ đến một đoạn nhớ rằng sau đó chúng tôi làm một số công việc với.
>> Đây là vấn đề lớn với cấp phát động bộ nhớ mặc dù,
và đây là lý do tại sao nó thực sự quan trọng để phát triển một số thói quen tốt
khi bạn đang làm việc với nó.
Không giống như khai báo tĩnh bộ nhớ, bộ nhớ của bạn
không được tự động trở lại hệ thống khi chức năng của bạn được thực hiện.
Vì vậy, nếu chúng ta có chính, và chính gọi hàm
f, f khi kết thúc bất cứ điều gì nó đang làm gì và trả lại quyền kiểm soát các chương trình
trở lại chính, tất cả các bộ nhớ f sử dụng được cho trở lại.
Nó có thể được sử dụng một lần nữa bởi một số chương trình khác,
hoặc một số chức năng khác được gọi là sau này trong chính.
Nó có thể sử dụng cùng một bộ nhớ trên một lần nữa.
>> Nếu bạn tự động cấp phát bộ nhớ mặc dù
bạn phải nói cho rõ ràng hệ thống mà bạn đang thực hiện với nó.
Nó sẽ giữ được nó cho bạn, mà có thể dẫn đến một vấn đề của bạn chạy ra ngoài
của bộ nhớ.
Và trong thực tế, đôi khi chúng ta tham khảo Nó như là một rò rỉ bộ nhớ.
Và đôi khi những rò rỉ bộ nhớ thực sự có thể được thực sự tàn phá
cho hiệu năng hệ thống.
>> Nếu bạn là một người sử dụng internet thường xuyên bạn có thể sử dụng các trình duyệt web nhất định,
và tôi sẽ không nêu tên ở đây, nhưng có một số trình duyệt web trên mạng
đó là những tiếng xấu cho thực sự có rò rỉ bộ nhớ mà không được cố định.
Và nếu bạn rời khỏi trình duyệt của bạn mở trong một thời gian rất dài của thời gian, ngày
và ngày, hoặc vài tuần, đôi khi bạn có thể nhận thấy rằng hệ thống của bạn
là chạy thực sự, thực sự chậm.
Và lý do cho rằng là trình duyệt đã phân bổ bộ nhớ,
nhưng sau đó không nói với hệ thống mà nó được thực hiện với nó.
Và như vậy, mà lá ít bộ nhớ có sẵn cho tất cả các chương trình khác của bạn
phải chia sẻ, bởi vì bạn leaking-- rằng trình duyệt web
chương trình là bị rò rỉ bộ nhớ.
Làm thế nào để chúng tôi cung cấp cho bộ nhớ trở lại khi chúng tôi đang thực hiện với nó?
Cũng may mắn thay đó là một cách rất dễ dàng để làm điều đó.
Chúng tôi chỉ giải phóng nó.
Có một chức năng gọi là miễn phí, nó chấp nhận một con trỏ trỏ tới bộ nhớ,
và chúng tôi đang tốt để đi.
>> Vì vậy, chúng ta hãy nói rằng chúng ta đang ở trong giữa chương trình của chúng tôi,
chúng tôi muốn để malloc 50 ký tự.
Chúng tôi muốn để malloc một mảng mà có thể khả năng nắm giữ 50 ký tự.
Và khi chúng ta có được một con trỏ trở lại rằng, tên của con trỏ đó là từ.
Chúng tôi làm bất cứ điều gì chúng tôi sẽ làm gì với từ,
và sau đó khi chúng tôi thực hiện chúng ta chỉ giải phóng nó.
Và bây giờ chúng tôi đã trở lại những người 50 byte của bộ nhớ trở lại vào hệ thống.
Một số chức năng khác có thể sử dụng chúng.
Chúng tôi không cần phải lo lắng về việc bị một rò rỉ bộ nhớ bởi vì chúng tôi đã giải phóng từ.
Chúng tôi đã cho các bộ nhớ trở lại, vì vậy chúng tôi đang thực hiện làm việc với nó.
Vì vậy, có ba nguyên tắc vàng mà nên
được lưu giữ trong tâm trí bất cứ khi nào bạn tự động phân bổ bộ nhớ
với malloc.
Mỗi khối của bộ nhớ bạn malloc phải được trả tự do
trước khi chương trình của bạn kết thúc hoạt động.
Bây giờ một lần nữa, trong thiết bị hoặc trong IDE loại này xảy ra cho bạn anyway
khi you-- này sẽ xảy ra dù sao khi chương trình của bạn được chấm dứt,
tất cả các bộ nhớ sẽ được phát hành.
Nhưng đó là mã hóa nói chung là tốt thực hành để mọi khi, khi bạn đang thực hiện,
giải phóng những gì bạn đã mallocd.
>> Điều đó nói rằng, chỉ có những điều mà bạn đã mallocd nên được giải thoát.
Nếu bạn khai báo một tĩnh số nguyên, int x dấu chấm phẩy,
sống trên stack, bạn không thì muốn giải phóng x.
Vì vậy, chỉ có những điều mà bạn đã mallocd nên được giải thoát.
>> Và cuối cùng, không một cái gì đó miễn phí hai lần.
Điều đó có thể dẫn đến một tình huống kỳ lạ.
Vì vậy, tất cả mọi thứ mà bạn đã mallocd phải được trả tự do.
Chỉ có những điều mà bạn đã malloc nên được giải thoát.
Và không một cái gì đó miễn phí hai lần.
>> Vì vậy, hãy đi qua một ví dụ ở đây của những gì một số phân bổ tự động
bộ nhớ có thể trông giống như hỗn hợp với một số bộ nhớ tĩnh.
Điều gì có thể xảy ra ở đây?
Xem nếu bạn có thể làm theo dọc và đoán những gì
sẽ xảy ra khi chúng ta đi qua tất cả các dòng mã.
>> Vì vậy, chúng ta nói int m.
chuyện gì xảy ra ở đây thế?
Vâng điều này là khá đơn giản.
Tôi tạo ra một biến số nguyên được gọi là m.
Tôi màu nó màu xanh lá cây, bởi vì đó là màu sắc
mà tôi sử dụng khi tôi đang nói về các biến số nguyên.
Đó là một hộp.
Nó được gọi là m, và bạn có thể cửa hàng số nguyên bên trong của nó.
>> Nếu tôi sau đó nói int sao a?
Vâng đó là khá tương tự.
Tôi đang tạo ra một hộp gọi là a.
Nó có khả năng nắm giữ int sao, con trỏ đến số nguyên.
Vì vậy, tôi tô màu nó xanh-ish là tốt.
>> Tôi biết nó có cái gì để làm với một số nguyên,
nhưng nó không phải tự nó là một số nguyên.
Nhưng nó là khá nhiều ý tưởng tương tự.
Tôi đã tạo ra một hộp.
Cả hai bên phải hiện đang sống trên stack.
Tôi đã cho họ cả hai tên.
>> int sao b bằng kích thước của malloc int.
Điều này có thể là một chút khó khăn.
Mất một giây và suy nghĩ về những gì bạn sẽ mong đợi xảy ra trên sơ đồ này.
int sao b bằng kích thước của malloc int.
>> Vâng điều này không chỉ tạo ra một hộp.
Điều này thực sự tạo ra hai hộp.
Và nó quan hệ, nó cũng thiết lập một điểm trong một mối quan hệ.
Chúng tôi đã phân bổ một khối bộ nhớ trên heap.
Lưu ý rằng hộp trên bên phải ở đó không có tên.
>> Chúng tôi mallocd nó.
Nó tồn tại trên heap.
Nhưng b có một tên.
Đó là một biến con trỏ được gọi là b.
Sống trên stack.
>> Vì vậy, nó là một phần của bộ nhớ trỏ đến nhau.
b chứa địa chỉ trong đó khối của bộ nhớ.
Nó không có một tên khác.
Nhưng nó chỉ vào nó.
Vì vậy, khi chúng ta nói sao int b bằng kích thước malloc của int, mà ngay tại đó,
rằng mũi tên đó hiện lên trên bên phải có, mà toàn bộ điều,
Tôi sẽ có nó xuất hiện một lần nữa, là những gì sẽ xảy ra.
Tất cả điều đó sẽ xảy ra trong mà dòng mã.
Bây giờ chúng ta sẽ nhận được ít hơn đơn giản một lần nữa.
một bằng ký hiệu m.
Bạn có nhớ những gì một bằng ký hiệu m là?
Vâng đó là một địa chỉ được m.
Hoặc đặt diagrammatically hơn, một điểm đến m.
>> một bằng b.
OK vì vậy đây là một số khác.
A bằng b.
Điều gì sẽ xảy ra sơ đồ thời gian này?
>> Cũng nhớ lại rằng công trình nhà điều hành phân
bằng cách gán giá trị trên đúng với giá trị trên bên trái.
Vì vậy, thay vì một trỏ đến m, một doanh nghiệp trỏ đến cùng một nơi mà điểm b.
một không trỏ đến b, một chỉ điểm nơi b.
>> Nếu một nhọn để b mà có đã là một bằng ký hiệu b.
Nhưng thay vì một bằng b chỉ có nghĩa là b và bây giờ
trỏ đến cùng một địa chỉ, bởi vì bên trong của b chỉ là một địa chỉ.
Và bây giờ bên trong của một là cùng một địa chỉ.
m tương đương với 10, có lẽ là điều đơn giản nhất
chúng tôi đã thực hiện trong một chút.
Đặt 10 trong hộp.
Sao b bằng m + 2, nhớ lại từ con trỏ video của chúng tôi những gì sao b có nghĩa.
Chúng tôi đang đi để tới đích của b và put một số giá trị trong đó vị trí bộ nhớ.
Trong trường hợp này 12.
>> Vì vậy, khi chúng tôi tới đích của một điểm nhớ lại chúng tôi chỉ đi xuống mũi tên.
Hay nói một cách khác, chúng ta đi đến địa chỉ bộ nhớ
và chúng ta vận dụng nó một cách nào đó.
Chúng tôi đặt một số giá trị trong đó.
Trong trường hợp này sao b bằng m cộng với 2 chỉ là
đi đến các biến được trỏ đến bởi b, đi vào bộ nhớ được trỏ đến bởi b,
và đưa m cộng với 2 trong đó, 12.
>> Bây giờ tôi tự do b.
Điều gì xảy ra khi tôi tự do b?
Hãy nhớ những gì tôi đã nói phương tiện miễn phí.
Tôi nói gì khi tôi phóng b?
>> Tôi đang làm việc được với nó, phải không?
Tôi chủ yếu cung cấp lên bộ nhớ.
Tôi cho nó trở lại vào hệ thống.
Tôi không cần cái này nữa là những gì tôi đang nói với họ, OK?
>> Bây giờ nếu tôi nói sao một bằng 11 bạn có thể có thể
đã nói rằng một cái gì đó xấu sẽ xảy ra ở đây, phải không?
Và quả thực nếu tôi cố gắng mà tôi có lẽ sẽ phải chịu đựng một lỗi phân khúc.
Bởi vì bây giờ, mặc dù trước đây rằng đoạn bộ nhớ
là một cái gì đó mà tôi đã có truy cập vào, vào thời điểm này
bây giờ tôi đang truy cập vào bộ nhớ là không hợp pháp cho tôi để truy cập.
>> Và như chúng ta có thể sẽ nhớ lại, khi chúng ta truy cập vào bộ nhớ
rằng chúng tôi không phải để liên lạc, đó là nguyên nhân phổ biến nhất
của một phân khúc lỗi. Và do đó, chương trình của tôi
sẽ sụp đổ nếu tôi cố gắng để làm điều này.
Vì vậy, một lần nữa nó là một ý tưởng tốt để có được tốt thói quen thực hành và tốt ăn sâu
khi làm việc với malloc và miễn phí, do đó bạn không bị phân
lỗi lầm, và rằng bạn sử dụng động của bạn được phân bổ
bộ nhớ có trách nhiệm.
>> Tôi Doug Lloyd này là CS50.