1 00:00:00,000 --> 00:00:02,520 [Powered by Google Translate] [Phần 4 - thoải mái hơn] 2 00:00:02,520 --> 00:00:04,850 [Rob Bowden - Đại học Harvard] 3 00:00:04,850 --> 00:00:07,370 [Đây là CS50. - CS50.TV] 4 00:00:08,920 --> 00:00:13,350 Chúng tôi có một bài kiểm tra vào ngày mai, trong trường hợp bạn không biết điều đó. 5 00:00:14,810 --> 00:00:20,970 Đó là cơ bản tất cả mọi thứ bạn có thể đã thấy trong lớp học hoặc đã thấy trong lớp. 6 00:00:20,970 --> 00:00:26,360 Điều đó bao gồm con trỏ, mặc dù họ là một chủ đề rất gần đây. 7 00:00:26,360 --> 00:00:29,860 Bạn ít nhất phải hiểu được mức độ cao của họ. 8 00:00:29,860 --> 00:00:34,760 Bất cứ điều gì đã được đi qua trong lớp bạn nên hiểu cho bài kiểm tra. 9 00:00:34,760 --> 00:00:37,320 Vì vậy, nếu bạn có câu hỏi về họ, bạn có thể yêu cầu chúng ngay bây giờ. 10 00:00:37,320 --> 00:00:43,280 Nhưng điều này là có được một phiên rất sinh viên dẫn nơi bạn đặt câu hỏi, 11 00:00:43,280 --> 00:00:45,060 do đó, hy vọng mọi người có thắc mắc. 12 00:00:45,060 --> 00:00:48,020 Có ai có câu hỏi? 13 00:00:49,770 --> 00:00:52,090 Vâng. >> [Sinh viên] Bạn có thể đi trên con trỏ một lần nữa? 14 00:00:52,090 --> 00:00:54,350 Tôi sẽ đi qua con trỏ. 15 00:00:54,350 --> 00:00:59,180 Tất cả các biến của bạn nhất thiết phải sống trong bộ nhớ, 16 00:00:59,180 --> 00:01:04,450 nhưng thông thường bạn không lo lắng về điều đó và bạn chỉ cần nói x + 2 và y + 3 17 00:01:04,450 --> 00:01:07,080 và trình biên dịch sẽ tìm ra nơi mà những điều đang sống cho bạn. 18 00:01:07,080 --> 00:01:12,990 Một khi bạn đang làm việc với con trỏ, bây giờ bạn một cách rõ ràng bằng cách sử dụng những địa chỉ bộ nhớ. 19 00:01:12,990 --> 00:01:19,800 Vì vậy, một biến duy nhất sẽ chỉ bao giờ sống tại một địa chỉ duy nhất tại bất kỳ thời gian nhất định. 20 00:01:19,800 --> 00:01:24,040 Nếu chúng ta muốn khai báo một con trỏ, các loại là những gì sẽ trông giống như? 21 00:01:24,040 --> 00:01:26,210 >> Tôi muốn khai báo một con trỏ p. Các loại trông như thế nào? 22 00:01:26,210 --> 00:01:33,530 [Sinh viên] int * p. >> Yeah. Vì vậy, int * p. 23 00:01:33,530 --> 00:01:38,030 Và làm cách nào để làm cho nó trỏ đến x? >> [Sinh viên] ký hiệu. 24 00:01:40,540 --> 00:01:45,300 Bowden] Vì vậy, ký hiệu là nghĩa đen được gọi là địa chỉ của nhà điều hành. 25 00:01:45,300 --> 00:01:50,460 Vì vậy, khi tôi nói & x nó nhận được địa chỉ bộ nhớ của biến x. 26 00:01:50,460 --> 00:01:56,790 Vì vậy, bây giờ tôi có con trỏ p, và bất cứ nơi nào trong mã của tôi, tôi có thể sử dụng * p 27 00:01:56,790 --> 00:02:02,960 hoặc tôi có thể sử dụng x và nó sẽ được chính xác cùng một điều. 28 00:02:02,960 --> 00:02:09,520 (* P). Này đang làm gì? Ngôi sao có nghĩa là gì? 29 00:02:09,520 --> 00:02:13,120 [Sinh viên] Nó có nghĩa là một giá trị tại thời điểm đó. >> Yeah. 30 00:02:13,120 --> 00:02:17,590 Vì vậy, nếu chúng ta nhìn vào nó, nó có thể rất hữu ích để vẽ sơ đồ 31 00:02:17,590 --> 00:02:22,230 nơi này là một hộp nhỏ của bộ nhớ cho x, xảy ra để có giá trị 4, 32 00:02:22,230 --> 00:02:25,980 sau đó chúng tôi có một hộp nhỏ của bộ nhớ cho p, 33 00:02:25,980 --> 00:02:31,590 và như vậy p điểm x, vì vậy chúng tôi rút ra một mũi tên từ p đến x. 34 00:02:31,590 --> 00:02:40,270 Vì vậy, khi chúng ta nói * p chúng tôi đang nói hộp là p. 35 00:02:40,270 --> 00:02:46,480 Star là theo các mũi tên và sau đó làm bất cứ điều gì bạn muốn với hộp đó. 36 00:02:46,480 --> 00:03:01,090 Vì vậy, tôi có thể nói * p = 7, mà sẽ đi đến hộp đó là x và sự thay đổi đó đến 7. 37 00:03:01,090 --> 00:03:13,540 Hoặc tôi có thể nói int z = * p * 2; Đó là khó hiểu bởi vì ngôi sao, ngôi sao. 38 00:03:13,540 --> 00:03:19,230 Ngôi sao một dereferencing p, ngôi sao khác được nhân với 2. 39 00:03:19,230 --> 00:03:26,780 Chú ý tôi có thể có chỉ là tốt thay thế p * x. 40 00:03:26,780 --> 00:03:29,430 Bạn có thể sử dụng chúng trong cùng một cách. 41 00:03:29,430 --> 00:03:38,000 Và rồi sau đó tôi có thể có điểm p là một điều hoàn toàn mới. 42 00:03:38,000 --> 00:03:42,190 Tôi chỉ có thể nói p = &z; 43 00:03:42,190 --> 00:03:44,940 Vì vậy, bây giờ p không có điểm lâu hơn để x, nó trỏ đến z. 44 00:03:44,940 --> 00:03:50,510 Và bất cứ lúc nào tôi làm * p nó giống như làm z. 45 00:03:50,510 --> 00:03:56,170 Vì vậy, điều hữu ích về việc này là khi chúng tôi bắt đầu nhận được vào các chức năng. 46 00:03:56,170 --> 00:03:59,790 >> Đó là loại useless để khai báo một con trỏ trỏ đến một cái gì đó 47 00:03:59,790 --> 00:04:03,140 và sau đó bạn chỉ cần dereferencing nó 48 00:04:03,140 --> 00:04:06,060 khi bạn có thể sử dụng các biến ban đầu để bắt đầu với. 49 00:04:06,060 --> 00:04:18,190 Nhưng khi bạn nhận được vào các chức năng - vì vậy hãy nói rằng chúng tôi có một số chức năng, int foo, 50 00:04:18,190 --> 00:04:32,810 mà phải mất một con trỏ và chỉ * p = 6; 51 00:04:32,810 --> 00:04:39,990 Giống như chúng ta đã thấy trước đây với vùng trao đổi, bạn không có thể làm một trao đổi hiệu quả và chức năng riêng biệt 52 00:04:39,990 --> 00:04:45,180 bằng cách chỉ cần đi qua các số nguyên bởi vì tất cả mọi thứ trong C luôn luôn đi qua giá trị. 53 00:04:45,180 --> 00:04:48,360 Ngay cả khi bạn đang đi qua con trỏ bạn đang đi qua bởi giá trị. 54 00:04:48,360 --> 00:04:51,940 Nó chỉ như vậy sẽ xảy ra rằng những giá trị địa chỉ bộ nhớ. 55 00:04:51,940 --> 00:05:00,770 Vì vậy, khi tôi nói foo (p); tôi đang đi qua con trỏ vào foo chức năng 56 00:05:00,770 --> 00:05:03,910 và sau đó foo * p = 6; 57 00:05:03,910 --> 00:05:08,600 Vì vậy, bên trong là chức năng, * p vẫn còn tương đương với x, 58 00:05:08,600 --> 00:05:12,720 nhưng tôi không thể sử dụng bên trong của chức năng đó bởi vì nó không scoped trong phạm vi chức năng đó. 59 00:05:12,720 --> 00:05:19,510 Vì vậy, * p = 6 là cách duy nhất tôi có thể truy cập vào một biến địa phương từ chức năng khác. 60 00:05:19,510 --> 00:05:23,600 Hoặc, tốt, con trỏ là cách duy nhất tôi có thể truy cập vào một biến địa phương từ chức năng khác. 61 00:05:23,600 --> 00:05:31,600 [Sinh viên] Chúng ta hãy nói rằng bạn muốn quay trở lại một con trỏ. Làm thế nào chính xác để bạn làm điều đó? 62 00:05:31,600 --> 00:05:44,270 [Bowden] Quay trở lại một con trỏ như trong một cái gì đó như int y = 3, trở lại y? >> [Sinh viên] Yeah. 63 00:05:44,270 --> 00:05:48,480 [Bowden] Okay. Bạn không bao giờ nên làm điều này. Điều này là xấu. 64 00:05:48,480 --> 00:05:59,480 Tôi nghĩ rằng tôi thấy trong các slide bài giảng, bạn bắt đầu nhìn thấy sơ đồ này toàn bộ bộ nhớ 65 00:05:59,480 --> 00:06:02,880 ở đây bạn đã có địa chỉ bộ nhớ 0 66 00:06:02,880 --> 00:06:09,550 và xuống ở đây bạn có địa chỉ bộ nhớ 4 đồng biểu diễn hoặc 2 cho 32. 67 00:06:09,550 --> 00:06:15,120 Vì vậy, sau đó bạn đã có một số công cụ và một số công cụ và sau đó bạn phải ngăn xếp của bạn 68 00:06:15,120 --> 00:06:21,780 và bạn đã có đống bạn, mà bạn chỉ mới bắt đầu học tập về, lớn lên. 69 00:06:21,780 --> 00:06:24,390 [Sinh viên] Không phải là đống trên ngăn xếp? 70 00:06:24,390 --> 00:06:27,760 >> Yeah. Heap là trên đầu trang, không phải là nó? >> [Sinh viên] À, anh ấy đặt 0 trên đầu trang. 71 00:06:27,760 --> 00:06:30,320 [Sinh viên] Oh, ông đặt 0 trên đầu trang. >> [Sinh viên] Oh, okay. 72 00:06:30,320 --> 00:06:36,060 Disclaimer: Bất cứ nơi nào với CS50 bạn đang đi để xem nó theo cách này. >> [Sinh viên] Okay. 73 00:06:36,060 --> 00:06:40,290 Nó chỉ là khi lần đầu bạn nhìn thấy ngăn xếp, 74 00:06:40,290 --> 00:06:45,000 giống như khi bạn nghĩ về một chồng bạn nghĩ xếp những thứ trên đầu trang của một người khác. 75 00:06:45,000 --> 00:06:50,810 Vì vậy, chúng ta có xu hướng để lật xung quanh để ngăn xếp được lớn lên như một chồng bình thường 76 00:06:50,810 --> 00:06:55,940 thay vì ngăn xếp trễ xuống. >> [Sinh viên] Đừng đống kỹ thuật phát triển quá, mặc dù? 77 00:06:55,940 --> 00:07:01,100 Nó phụ thuộc vào những gì bạn có nghĩa là lớn lên. 78 00:07:01,100 --> 00:07:04,010 Stack và heap luôn luôn phát triển theo hướng ngược nhau. 79 00:07:04,010 --> 00:07:09,420 Một stack là luôn luôn lớn lên trong ý nghĩa rằng nó lớn lên 80 00:07:09,420 --> 00:07:12,940 đối với các địa chỉ bộ nhớ cao hơn, và heap được phát triển 81 00:07:12,940 --> 00:07:17,260 trong đó nó đang phát triển đối với các địa chỉ bộ nhớ thấp hơn. 82 00:07:17,260 --> 00:07:20,250 Vì vậy, trên cùng là 0 và phía dưới là địa chỉ bộ nhớ cao. 83 00:07:20,250 --> 00:07:26,390 Họ cả hai đang phát triển, trong việc phản đối hướng. 84 00:07:26,390 --> 00:07:29,230 [Sinh viên] Tôi chỉ có nghĩa là bởi vì bạn nói bạn đặt ngăn xếp ở phía dưới 85 00:07:29,230 --> 00:07:33,640 vì nó có vẻ trực quan hơn bởi vì các ngăn xếp để bắt đầu ở phía trên cùng của một đống, 86 00:07:33,640 --> 00:07:37,520 heap là trên bản thân nó quá, vì vậy Đó - >> Vâng. 87 00:07:37,520 --> 00:07:44,960 Bạn cũng có suy nghĩ của đống như lớn lên và lớn hơn, nhưng ngăn xếp nhiều hơn như vậy. 88 00:07:44,960 --> 00:07:50,280 Vì vậy, ngăn xếp là một trong những loại chúng ta muốn hiển thị lớn lên. 89 00:07:50,280 --> 00:07:55,390 Tuy nhiên, ở khắp mọi nơi bạn nhìn nếu không sẽ hiển thị địa chỉ 0 ở đầu 90 00:07:55,390 --> 00:07:59,590 và địa chỉ bộ nhớ cao nhất ở phía dưới, do đó, điều này là quan điểm thông thường của bạn bộ nhớ. 91 00:07:59,590 --> 00:08:02,100 >> Bạn có một câu hỏi? 92 00:08:02,100 --> 00:08:04,270 [Sinh viên] Bạn có thể cho chúng tôi biết thêm về heap? 93 00:08:04,270 --> 00:08:06,180 Yeah. Tôi sẽ nhận được trong một giây. 94 00:08:06,180 --> 00:08:12,220 Đầu tiên, sẽ trở lại lý do tại sao trở về & y là một điều xấu, 95 00:08:12,220 --> 00:08:18,470 trên stack bạn có một loạt các khung stack đại diện cho tất cả các chức năng 96 00:08:18,470 --> 00:08:20,460 đã được gọi là. 97 00:08:20,460 --> 00:08:27,990 Vì vậy, bỏ qua những điều trước đây, đỉnh của ngăn xếp của bạn luôn luôn có được các chức năng chính 98 00:08:27,990 --> 00:08:33,090 vì đó là chức năng đầu tiên được gọi là. 99 00:08:33,090 --> 00:08:37,130 Và sau đó khi bạn gọi một chức năng, ngăn xếp sẽ phát triển. 100 00:08:37,130 --> 00:08:41,640 Vì vậy, nếu tôi gọi một số chức năng, foo, và nó được khung stack riêng của mình, 101 00:08:41,640 --> 00:08:47,280 nó có thể gọi một số chức năng, quầy bar, nó được khung stack riêng của mình. 102 00:08:47,280 --> 00:08:49,840 Và quầy bar có thể được đệ quy và nó có thể gọi chính nó, 103 00:08:49,840 --> 00:08:54,150 và do đó cuộc gọi thứ hai đến một quán bar để có được khung stack riêng của mình. 104 00:08:54,150 --> 00:08:58,880 Và do đó, những gì diễn ra trong các khung stack là tất cả các biến địa phương 105 00:08:58,880 --> 00:09:03,450 và tất cả các đối số chức năng mà - 106 00:09:03,450 --> 00:09:08,730 Bất kỳ điều tại địa phương scoped để chức năng này trong các khung stack. 107 00:09:08,730 --> 00:09:21,520 Vì vậy, điều đó có nghĩa là khi tôi nói một cái gì đó giống như thanh là một chức năng, 108 00:09:21,520 --> 00:09:29,270 Tôi chỉ cần đi để khai báo một số nguyên và sau đó trở về một con trỏ đến số nguyên. 109 00:09:29,270 --> 00:09:33,790 Vì vậy, nơi y sống? 110 00:09:33,790 --> 00:09:36,900 [Sinh viên] y sống trong quán bar. >> [Bowden] Yeah. 111 00:09:36,900 --> 00:09:45,010 Nơi nào đó trong hình vuông ít bộ nhớ này là một hình vuông Littler có y trong đó. 112 00:09:45,010 --> 00:09:53,370 Khi tôi trở về và y, tôi trở lại một con trỏ đến khối này ít bộ nhớ. 113 00:09:53,370 --> 00:09:58,400 Nhưng sau đó khi trở về chức năng, khung stack của nó được lấy ra khỏi stack. 114 00:10:01,050 --> 00:10:03,530 Và đó là lý do tại sao nó được gọi là chồng. 115 00:10:03,530 --> 00:10:06,570 Nó giống như cấu trúc dữ liệu ngăn xếp, nếu bạn biết đó là gì. 116 00:10:06,570 --> 00:10:11,580 Hoặc thậm chí như một chồng các khay luôn luôn là ví dụ, 117 00:10:11,580 --> 00:10:16,060 chính là sẽ đi về phía dưới, sau đó chức năng đầu tiên bạn gọi là sẽ đi trên đó, 118 00:10:16,060 --> 00:10:20,400 và bạn không thể lấy lại chính cho đến khi bạn trở về từ tất cả các chức năng đã được gọi là 119 00:10:20,400 --> 00:10:22,340 đã được đặt trên đầu trang của nó. 120 00:10:22,340 --> 00:10:28,650 >> [Sinh viên] Vì vậy, nếu bạn đã làm trở lại y &, giá trị đó có thể thay đổi mà không cần thông báo. 121 00:10:28,650 --> 00:10:31,290 Có, it's - >> [sinh viên] Nó có thể được ghi đè. >> Yeah. 122 00:10:31,290 --> 00:10:34,660 Nó hoàn toàn - Nếu bạn cố gắng và - 123 00:10:34,660 --> 00:10:38,040 Điều này cũng sẽ là một thanh int * bởi vì nó trở về một con trỏ, 124 00:10:38,040 --> 00:10:41,310 do đó, kiểu trả về của nó là int *. 125 00:10:41,310 --> 00:10:46,500 Nếu bạn cố gắng sử dụng giá trị trả lại chức năng này, đó là xác định hành vi 126 00:10:46,500 --> 00:10:51,770 vì rằng con trỏ chỉ vào bộ nhớ xấu. >> [Sinh viên] Okay. 127 00:10:51,770 --> 00:11:01,250 Vì vậy, điều gì sẽ xảy ra nếu, ví dụ, bạn tuyên bố int * y = malloc (sizeof (int))? 128 00:11:01,250 --> 00:11:03,740 Đó là tốt hơn. Vâng. 129 00:11:03,740 --> 00:11:07,730 [Sinh viên] Chúng tôi đã nói chuyện về làm thế nào khi chúng ta kéo mọi thứ vào thùng rác của chúng tôi 130 00:11:07,730 --> 00:11:11,750 họ đang không thực sự bị xóa, chúng tôi chỉ mất con trỏ của họ. 131 00:11:11,750 --> 00:11:15,550 Vì vậy, trong trường hợp này chúng ta thực sự xóa các giá trị hoặc là nó vẫn còn đó trong bộ nhớ? 132 00:11:15,550 --> 00:11:19,130 Đối với hầu hết các phần, nó sẽ vẫn có mặt ở đó. 133 00:11:19,130 --> 00:11:24,220 Nhưng hãy nói chúng tôi xảy ra để gọi một số chức năng khác, baz. 134 00:11:24,220 --> 00:11:28,990 Baz là sẽ nhận được khung stack riêng của mình trên đây. 135 00:11:28,990 --> 00:11:31,470 Nó sẽ được ghi đè lên tất cả các công cụ này, 136 00:11:31,470 --> 00:11:34,180 và sau đó nếu sau đó bạn cố gắng và sử dụng con trỏ mà bạn có trước khi, 137 00:11:34,180 --> 00:11:35,570 nó sẽ không phải là cùng một giá trị. 138 00:11:35,570 --> 00:11:38,150 Nó sẽ thay đổi chỉ bởi vì bạn được gọi là baz chức năng. 139 00:11:38,150 --> 00:11:43,080 [Sinh viên] Nhưng nếu chúng ta không, chúng tôi vẫn có được 3? 140 00:11:43,080 --> 00:11:44,990 [Bowden] Trong tất cả các khả năng, bạn sẽ. 141 00:11:44,990 --> 00:11:49,670 Nhưng bạn không thể dựa vào đó. C chỉ nói hành vi không xác định. 142 00:11:49,670 --> 00:11:51,920 >> [Sinh viên] Oh, nó. Okay. 143 00:11:51,920 --> 00:11:58,190 Vì vậy, khi bạn muốn trả về một con trỏ, đây là nơi malloc đến trong sử dụng. 144 00:12:00,930 --> 00:12:15,960 Tôi đang viết thực sự chỉ cần trả lại malloc (3 * sizeof (int)). 145 00:12:17,360 --> 00:12:24,050 Chúng tôi sẽ đi qua malloc hơn trong một giây, nhưng ý tưởng của malloc là tất cả các biến địa phương của bạn 146 00:12:24,050 --> 00:12:26,760 luôn luôn đi trên stack. 147 00:12:26,760 --> 00:12:31,570 Bất cứ điều gì malloced đi trên heap, và nó mãi mãi và sẽ luôn luôn được trên heap 148 00:12:31,570 --> 00:12:34,490 cho đến khi bạn giải phóng nó một cách rõ ràng. 149 00:12:34,490 --> 00:12:42,130 Vì vậy, điều này có nghĩa là khi bạn malloc một cái gì đó, nó sẽ tồn tại sau khi trở về chức năng. 150 00:12:42,130 --> 00:12:46,800 [Sinh viên] nó sẽ tồn tại sau khi chương trình ngừng chạy? >> Số 151 00:12:46,800 --> 00:12:53,180 Được rồi, do đó, nó sẽ có mặt ở đó cho đến khi chương trình là tất cả các cách thực hiện hoạt động. >>. 152 00:12:53,180 --> 00:12:57,510 Chúng ta có thể đi qua các chi tiết về những gì sẽ xảy ra khi chương trình dừng chạy. 153 00:12:57,510 --> 00:13:02,150 Bạn có thể cần nhắc nhở tôi, nhưng đó là một điều riêng biệt hoàn toàn. 154 00:13:02,150 --> 00:13:04,190 [Sinh viên] Vì vậy, malloc tạo ra một con trỏ? >> Yeah. 155 00:13:04,190 --> 00:13:13,030 Malloc - >> [sinh viên] Tôi nghĩ rằng malloc chỉ định một khối bộ nhớ rằng một con trỏ có thể sử dụng. 156 00:13:15,400 --> 00:13:19,610 [Bowden] Tôi muốn rằng sơ đồ một lần nữa. >> [Sinh viên] Vì vậy, chức năng này hoạt động, mặc dù không? 157 00:13:19,610 --> 00:13:26,430 [Sinh viên] Yeah, malloc chỉ định một khối bộ nhớ mà bạn có thể sử dụng, 158 00:13:26,430 --> 00:13:30,470 và sau đó nó sẽ trả về địa chỉ của khối đầu tiên của bộ nhớ. 159 00:13:30,470 --> 00:13:36,750 >> [Bowden] Yeah. Vì vậy, khi bạn malloc, bạn lấy một số khối của bộ nhớ 160 00:13:36,750 --> 00:13:38,260 hiện đang trong heap. 161 00:13:38,260 --> 00:13:43,040 Nếu heap là quá nhỏ, sau đó các đống chỉ là đi để phát triển, và nó phát triển theo hướng này. 162 00:13:43,040 --> 00:13:44,650 Vì vậy, hãy nói rằng heap là quá nhỏ. 163 00:13:44,650 --> 00:13:49,960 Sau đó, nó về để phát triển một chút và trả về một con trỏ trỏ tới khối này chỉ tăng trưởng. 164 00:13:49,960 --> 00:13:55,130 Khi bạn công cụ miễn phí, bạn đang làm cho phòng trong đống này, 165 00:13:55,130 --> 00:14:00,030 như vậy thì sau đó gọi đến malloc có thể sử dụng lại bộ nhớ mà trước đó bạn đã giải phóng. 166 00:14:00,030 --> 00:14:09,950 Điều quan trọng về malloc và free là nó cho phép bạn kiểm soát hoàn toàn 167 00:14:09,950 --> 00:14:12,700 trong suốt cuộc đời của các khối bộ nhớ. 168 00:14:12,700 --> 00:14:15,420 Biến toàn cầu luôn luôn sống. 169 00:14:15,420 --> 00:14:18,500 Các biến địa phương sống trong phạm vi của họ. 170 00:14:18,500 --> 00:14:22,140 Ngay sau khi bạn đi qua một cú đúp xoăn, các biến địa phương đã chết. 171 00:14:22,140 --> 00:14:28,890 Malloced bộ nhớ là còn sống khi bạn muốn nó được sống 172 00:14:28,890 --> 00:14:33,480 và sau đó được phát hành khi bạn nói với nó sẽ được phát hành. 173 00:14:33,480 --> 00:14:38,420 Đó là thực sự là 3 loại duy nhất của bộ nhớ, thực sự. 174 00:14:38,420 --> 00:14:41,840 Có tự động quản lý bộ nhớ, đó là ngăn xếp. 175 00:14:41,840 --> 00:14:43,840 Sự việc xảy ra cho bạn tự động. 176 00:14:43,840 --> 00:14:46,910 Khi bạn nói x int, bộ nhớ được phân bổ cho x int. 177 00:14:46,910 --> 00:14:51,630 Khi x đi ra khỏi phạm vi, bộ nhớ được khai hoang cho x. 178 00:14:51,630 --> 00:14:54,790 Sau đó có quản lý bộ nhớ động, đó là những gì malloc, 179 00:14:54,790 --> 00:14:56,740 đó là khi bạn có kiểm soát. 180 00:14:56,740 --> 00:15:01,290 Bạn quyết định động khi bộ nhớ nên và không nên được phân bổ. 181 00:15:01,290 --> 00:15:05,050 Và sau đó là tĩnh, mà chỉ có nghĩa là nó tồn tại mãi mãi, 182 00:15:05,050 --> 00:15:06,610 đó là biến toàn cầu. 183 00:15:06,610 --> 00:15:10,240 Họ chỉ cần luôn luôn trong bộ nhớ. 184 00:15:10,960 --> 00:15:12,760 >> Câu hỏi? 185 00:15:14,490 --> 00:15:17,230 [Sinh viên] Bạn có thể xác định một khối chỉ bằng cách sử dụng dấu ngoặc nhọn 186 00:15:17,230 --> 00:15:21,220 nhưng không có để có một nếu tuyên bố hoặc một tuyên bố bất cứ điều gì trong khi hoặc như thế? 187 00:15:21,220 --> 00:15:29,130 Bạn có thể xác định một khối như trong một chức năng, nhưng mà có dấu ngoặc nhọn quá. 188 00:15:29,130 --> 00:15:32,100 [Sinh viên] Vì vậy, bạn có thể không chỉ có giống như một cặp ngẫu nhiên của các dấu ngoặc nhọn trong mã của bạn 189 00:15:32,100 --> 00:15:35,680 có các biến địa phương? >> Có, bạn có thể. 190 00:15:35,680 --> 00:15:45,900 Bên trong của thanh int chúng ta có thể có {int y = 3;}. 191 00:15:45,900 --> 00:15:48,440 Đó là nghĩa vụ ngay tại đây. 192 00:15:48,440 --> 00:15:52,450 Nhưng điều đó hoàn toàn xác định phạm vi của int y. 193 00:15:52,450 --> 00:15:57,320 Sau khi là nẹp xoăn thứ hai, y không thể được sử dụng nữa. 194 00:15:57,910 --> 00:16:00,630 Bạn hầu như không bao giờ làm điều đó, mặc dù. 195 00:16:02,940 --> 00:16:07,370 Trở lại với những gì sẽ xảy ra khi một chương trình kết thúc, 196 00:16:07,370 --> 00:16:18,760 có loại một quan niệm sai lầm / nửa lời nói dối mà chúng tôi cung cấp để làm cho mọi việc dễ dàng hơn. 197 00:16:18,760 --> 00:16:24,410 Chúng tôi nói với bạn rằng khi bạn cấp phát bộ nhớ 198 00:16:24,410 --> 00:16:29,860 bạn đang phân bổ một số đoạn của bộ nhớ RAM cho biến đó. 199 00:16:29,860 --> 00:16:34,190 Nhưng bạn không thực sự tiếp xúc trực tiếp bộ nhớ RAM bao giờ hết trong chương trình của bạn. 200 00:16:34,190 --> 00:16:37,490 Nếu bạn nghĩ về nó, làm thế nào tôi vẽ 201 00:16:37,490 --> 00:16:44,330 Và trên thực tế, nếu bạn đi qua trong GDB, bạn sẽ thấy điều tương tự. 202 00:16:51,120 --> 00:16:57,590 Bất kể bao nhiêu lần bạn chạy chương trình của bạn hoặc những gì chương trình bạn đang chạy, 203 00:16:57,590 --> 00:16:59,950 stack là luôn luôn đi để bắt đầu - 204 00:16:59,950 --> 00:17:06,510 bạn sẽ luôn luôn thấy các biến xung quanh một cái gì đó oxbffff địa chỉ. 205 00:17:06,510 --> 00:17:09,470 Nó thường là một nơi nào đó trong khu vực đó. 206 00:17:09,470 --> 00:17:18,760 Nhưng làm thế nào có thể 2 chương trình có thể có con trỏ cùng một bộ nhớ? 207 00:17:20,640 --> 00:17:27,650 [Sinh viên] Có một số chỉ định bất kỳ nơi oxbfff là vụ phải được trên RAM 208 00:17:27,650 --> 00:17:31,320 mà thực sự có thể được ở những nơi khác nhau tùy thuộc vào khi chức năng này được gọi là. 209 00:17:31,320 --> 00:17:35,920 Yeah. Thuật ngữ này là bộ nhớ ảo. 210 00:17:35,920 --> 00:17:42,250 Ý tưởng là tất cả các quá trình duy nhất, tất cả các chương trình đang chạy trên máy tính của bạn 211 00:17:42,250 --> 00:17:49,450 có riêng của mình - chúng ta hãy giả sử 32 bit hoàn toàn độc lập không gian địa chỉ. 212 00:17:49,450 --> 00:17:51,590 Đây là không gian địa chỉ. 213 00:17:51,590 --> 00:17:56,220 Nó có riêng của mình hoàn toàn độc lập 4 gigabyte sử dụng. 214 00:17:56,220 --> 00:18:02,220 >> Vì vậy, nếu bạn chạy đồng thời 2 chương trình, chương trình này thấy 4 gigabyte với chính nó, 215 00:18:02,220 --> 00:18:04,870 chương trình này thấy 4 gigabyte với chính nó, 216 00:18:04,870 --> 00:18:07,720 và nó không thể cho chương trình này để dereference một con trỏ 217 00:18:07,720 --> 00:18:10,920 và kết thúc với bộ nhớ từ chương trình này. 218 00:18:10,920 --> 00:18:18,200 Và những gì bộ nhớ ảo là một ánh xạ từ một quá trình không gian địa chỉ 219 00:18:18,200 --> 00:18:20,470 những điều thực tế về bộ nhớ RAM. 220 00:18:20,470 --> 00:18:22,940 Vì vậy, nó là hệ điều hành của bạn để biết rằng, 221 00:18:22,940 --> 00:18:28,080 hey, khi anh chàng này dereferences con trỏ oxbfff, mà thực sự có nghĩa là 222 00:18:28,080 --> 00:18:31,040 rằng ông muốn RAM byte 1000, 223 00:18:31,040 --> 00:18:38,150 trong khi nếu chương trình này dereferences oxbfff, ông thực sự muốn RAM byte 10.000. 224 00:18:38,150 --> 00:18:41,590 Chúng có thể được tùy tiện cách xa nhau. 225 00:18:41,590 --> 00:18:48,730 Điều này thậm chí của sự vật trong một không gian địa chỉ duy nhất quá trình. 226 00:18:48,730 --> 00:18:54,770 Vì vậy, giống như nó nhìn thấy tất cả 4 GB với chính nó, nhưng hãy nói - 227 00:18:54,770 --> 00:18:57,290 [Sinh viên] tất cả các quá trình duy nhất - 228 00:18:57,290 --> 00:19:01,350 Hãy nói rằng bạn có một máy tính với chỉ 4 GB RAM. 229 00:19:01,350 --> 00:19:06,430 Tất cả các quá trình duy nhất nhìn thấy cả 4 gigabyte? >>. 230 00:19:06,430 --> 00:19:13,060 Nhưng 4 gigabyte nó thấy là nói dối. 231 00:19:13,060 --> 00:19:20,460 Nó chỉ là nó nghĩ rằng nó có tất cả bộ nhớ này bởi vì nó không biết bất kỳ quá trình khác đang tồn tại. 232 00:19:20,460 --> 00:19:28,140 Nó sẽ chỉ sử dụng bộ nhớ càng nhiều như nó thực sự cần. 233 00:19:28,140 --> 00:19:32,340 Các hệ điều hành không phải là đi để cung cấp cho bộ nhớ RAM để quá trình này 234 00:19:32,340 --> 00:19:35,750 nếu nó không được sử dụng bất kỳ bộ nhớ trong toàn bộ khu vực này. 235 00:19:35,750 --> 00:19:39,300 Nó sẽ không để cho nó bộ nhớ cho khu vực đó. 236 00:19:39,300 --> 00:19:54,780 Tuy nhiên, ý tưởng này là - Tôi đang cố gắng để suy nghĩ của tôi không thể nghĩ về một tương tự. 237 00:19:54,780 --> 00:19:56,780 Sự so sánh khó khăn. 238 00:19:57,740 --> 00:20:02,700 Một trong các vấn đề của bộ nhớ ảo hoặc một trong những điều nó giải quyết 239 00:20:02,700 --> 00:20:06,810 là quá trình phải được hoàn toàn không biết gì về nhau. 240 00:20:06,810 --> 00:20:12,140 Và như vậy bạn có thể viết bất kỳ chương trình mà chỉ cần dereferences bất kỳ con trỏ, 241 00:20:12,140 --> 00:20:19,340 như chỉ cần viết một chương trình nói rằng * (ox1234), 242 00:20:19,340 --> 00:20:22,890 và đó là địa chỉ bộ nhớ dereferencing 1234. 243 00:20:22,890 --> 00:20:28,870 >> Nhưng đó là hệ điều hành để sau đó dịch 1234 phương tiện. 244 00:20:28,870 --> 00:20:33,960 Vì vậy, nếu 1234 sẽ xảy ra là một địa chỉ bộ nhớ hợp lệ cho quá trình này, 245 00:20:33,960 --> 00:20:38,800 như đó là trên stack hoặc một cái gì đó, thì điều này sẽ trả về giá trị của địa chỉ bộ nhớ 246 00:20:38,800 --> 00:20:41,960 như xa như là quá trình biết. 247 00:20:41,960 --> 00:20:47,520 Nhưng nếu 1234 là không phải là một địa chỉ hợp lệ, giống như nó sẽ xảy ra với đất 248 00:20:47,520 --> 00:20:52,910 trong một số đôi chút về bộ nhớ ở đây là ngoài ngăn xếp và vượt ra ngoài đống 249 00:20:52,910 --> 00:20:57,200 và bạn đã không thực sự được sử dụng, sau đó đó là khi bạn có được những thứ như segfaults 250 00:20:57,200 --> 00:21:00,260 bởi vì bạn đang chạm vào bộ nhớ mà bạn không nên chạm vào. 251 00:21:07,180 --> 00:21:09,340 Điều này cũng đúng - 252 00:21:09,340 --> 00:21:15,440 Một hệ thống 32-bit, 32 bit có nghĩa là bạn có 32 bit để xác định một địa chỉ bộ nhớ. 253 00:21:15,440 --> 00:21:22,970 Đó là lý do tại sao con trỏ là 8 byte bởi vì 32 bit là 8 byte hoặc 4 byte. 254 00:21:22,970 --> 00:21:25,250 Con trỏ là 4 byte. 255 00:21:25,250 --> 00:21:33,680 Vì vậy, khi bạn nhìn thấy một con trỏ như oxbfffff, đó là - 256 00:21:33,680 --> 00:21:40,080 Trong bất kỳ chương trình nào, bạn chỉ có thể xây dựng bất cứ con trỏ tùy ý, 257 00:21:40,080 --> 00:21:46,330 bất cứ nơi nào từ ox0 bò 8 f's - ffffffff. 258 00:21:46,330 --> 00:21:49,180 [Sinh viên] Không phải bạn nói rằng họ đang 4 byte? >> Yeah. 259 00:21:49,180 --> 00:21:52,730 [Sinh viên] Sau đó, mỗi byte sẽ có - >> [Bowden Hexadecimal. 260 00:21:52,730 --> 00:21:59,360 Hexadecimal - 5, 6, 7, 8. Vì vậy, con trỏ, bạn sẽ luôn luôn nhìn thấy trong hệ thập lục phân. 261 00:21:59,360 --> 00:22:01,710 Đó chỉ là cách chúng tôi phân loại con trỏ. 262 00:22:01,710 --> 00:22:05,240 Mỗi 2 chữ số thập lục phân là 1 byte. 263 00:22:05,240 --> 00:22:09,600 Vì vậy, sẽ là 8 chữ số thập lục phân cho 4 byte. 264 00:22:09,600 --> 00:22:14,190 Vì vậy, mỗi con trỏ duy nhất trên một hệ thống 32-bit sẽ là 4 byte, 265 00:22:14,190 --> 00:22:18,550 có nghĩa là trong quá trình của bạn, bạn có thể xây dựng bất kỳ 4 byte tùy ý 266 00:22:18,550 --> 00:22:20,550 và làm cho một con trỏ ra khỏi nó, 267 00:22:20,550 --> 00:22:32,730 có nghĩa là như xa như nó biết, nó có thể giải quyết toàn bộ khoảng 2 đến 32 byte của bộ nhớ. 268 00:22:32,730 --> 00:22:34,760 Mặc dù nó không thực sự có quyền truy cập vào đó, 269 00:22:34,760 --> 00:22:40,190 ngay cả khi máy tính của bạn chỉ có 512 MB, nó nghĩ rằng nó đã có nhiều bộ nhớ. 270 00:22:40,190 --> 00:22:44,930 Và hệ điều hành là đủ thông minh rằng nó sẽ chỉ phân bổ những gì bạn thực sự cần. 271 00:22:44,930 --> 00:22:49,630 Nó không chỉ cần đi, oh, một quá trình mới: 4 đồng biểu diễn. 272 00:22:49,630 --> 00:22:51,930 >> Yeah. >> [Sinh viên] ox có nghĩa là gì? Tại sao bạn viết nó? 273 00:22:51,930 --> 00:22:54,980 Nó chỉ là biểu tượng cho hệ thập lục phân. 274 00:22:54,980 --> 00:22:59,590 Khi bạn nhìn thấy một sự khởi đầu số với con bò, những điều kế tiếp là thập lục phân. 275 00:23:01,930 --> 00:23:05,760 [Sinh viên] Bạn đã được giải thích về những gì sẽ xảy ra khi một chương trình kết thúc. >>. 276 00:23:05,760 --> 00:23:09,480 Điều gì sẽ xảy ra khi một chương trình kết thúc là hệ điều hành 277 00:23:09,480 --> 00:23:13,600 chỉ cần xóa các ánh xạ mà nó có những địa chỉ này, và đó là nó. 278 00:23:13,600 --> 00:23:17,770 Các hệ điều hành có thể chỉ cần cung cấp cho rằng bộ nhớ một chương trình khác để sử dụng. 279 00:23:17,770 --> 00:23:19,490 [Sinh viên] Okay. 280 00:23:19,490 --> 00:23:24,800 Vì vậy, khi bạn phân bổ một cái gì đó trên heap hoặc stack biến toàn cầu hoặc bất cứ điều gì, 281 00:23:24,800 --> 00:23:27,010 tất cả họ đều chỉ biến mất ngay sau khi chương trình kết thúc 282 00:23:27,010 --> 00:23:32,120 vì hệ điều hành miễn phí cung cấp cho rằng bộ nhớ cho bất kỳ quá trình khác. 283 00:23:32,120 --> 00:23:35,150 [Sinh viên] Mặc dù có lẽ vẫn còn giá trị được viết bằng? >> Yeah. 284 00:23:35,150 --> 00:23:37,740 Các giá trị có khả năng vẫn còn đó. 285 00:23:37,740 --> 00:23:41,570 Nó chỉ là nó sẽ được khó khăn để có được ở họ. 286 00:23:41,570 --> 00:23:45,230 Đó là khó khăn hơn nhiều để có được ở họ hơn là để có được một tập tin đã xóa 287 00:23:45,230 --> 00:23:51,450 bởi vì các loại tập tin đã xóa ngồi ở đó trong một thời gian dài và ổ đĩa cứng lớn hơn rất nhiều. 288 00:23:51,450 --> 00:23:54,120 Vì vậy, nó sẽ ghi đè lên các bộ phận khác nhau của bộ nhớ 289 00:23:54,120 --> 00:23:58,640 trước khi nó xảy ra để ghi đè lên các đoạn bộ nhớ rằng tập tin đó được sử dụng để được ở. 290 00:23:58,640 --> 00:24:04,520 Tuy nhiên, bộ nhớ chính, bộ nhớ RAM, bạn chu kỳ thông qua nhanh hơn rất nhiều, 291 00:24:04,520 --> 00:24:08,040 do đó, nó sẽ rất nhanh chóng được ghi đè. 292 00:24:10,300 --> 00:24:13,340 Câu hỏi này hay bất cứ điều gì khác? 293 00:24:13,340 --> 00:24:16,130 [Sinh viên] Tôi có câu hỏi về một chủ đề khác nhau. >> Okay. 294 00:24:16,130 --> 00:24:19,060 Có ai có câu hỏi về điều này? 295 00:24:20,170 --> 00:24:23,120 >> Okay. Khác nhau chủ đề. >> [Sinh viên] Okay. 296 00:24:23,120 --> 00:24:26,550 Tôi đã đi qua một số bài kiểm tra thực hành, 297 00:24:26,550 --> 00:24:30,480 và một trong số họ đã nói về các sizeof 298 00:24:30,480 --> 00:24:35,630 và giá trị mà nó trả về hoặc các loại biến khác nhau. >>. 299 00:24:35,630 --> 00:24:45,060 Và họ nói rằng cả int và dài trở lại 4, vì vậy họ đang dài cả 4 byte. 300 00:24:45,060 --> 00:24:48,070 Có sự khác biệt giữa một int và một thời gian dài, hoặc là nó cùng một điều? 301 00:24:48,070 --> 00:24:50,380 Có, có một sự khác biệt. 302 00:24:50,380 --> 00:24:52,960 Các tiêu chuẩn C - 303 00:24:52,960 --> 00:24:54,950 Tôi có thể sẽ gặp rắc rối. 304 00:24:54,950 --> 00:24:58,800 Các tiêu chuẩn C giống như những gì C, tài liệu chính thức của C. 305 00:24:58,800 --> 00:25:00,340 Đây là những gì nó nói. 306 00:25:00,340 --> 00:25:08,650 Vì vậy, các tiêu chuẩn C chỉ nói rằng một char mãi mãi và sẽ luôn luôn là 1 byte. 307 00:25:10,470 --> 00:25:19,040 Tất cả mọi thứ sau đó - một đoạn ngắn là luôn luôn chỉ được xác định là lớn hơn hoặc bằng một char. 308 00:25:19,040 --> 00:25:23,010 Điều này có thể được nghiêm chỉnh lớn hơn, nhưng không tích cực. 309 00:25:23,010 --> 00:25:31,940 Int chỉ được xác định là lớn hơn hoặc bằng một đoạn ngắn. 310 00:25:31,940 --> 00:25:36,210 Và một thời gian dài chỉ được xác định là lớn hơn hoặc bằng một int. 311 00:25:36,210 --> 00:25:41,600 Và một lâu dài lớn hơn hoặc bằng một thời gian dài. 312 00:25:41,600 --> 00:25:46,610 Vì vậy, điều duy nhất các tiêu chuẩn C định nghĩa là sự sắp xếp tương đối của tất cả mọi thứ. 313 00:25:46,610 --> 00:25:54,880 Số tiền thực tế của bộ nhớ rằng mọi thứ mất nói chung là đến thực hiện, 314 00:25:54,880 --> 00:25:57,640 nhưng nó khá tốt quy định tại điểm này. >> [Sinh viên] Okay. 315 00:25:57,640 --> 00:26:02,490 Vì vậy, quần short được hầu như luôn luôn sẽ là 2 byte. 316 00:26:04,920 --> 00:26:09,950 Ints gần như luôn luôn sẽ là 4 byte. 317 00:26:12,070 --> 00:26:15,340 Chờ đợi lâu gần như luôn luôn sẽ là 8 byte. 318 00:26:17,990 --> 00:26:23,160 Và chờ đợi, nó phụ thuộc vào việc bạn đang sử dụng một hệ thống 32-bit hoặc 64-bit. 319 00:26:23,160 --> 00:26:27,450 Vì vậy, một thời gian dài sẽ tương ứng với các loại hệ thống. 320 00:26:27,450 --> 00:26:31,920 Nếu bạn đang sử dụng một hệ thống 32-bit như gia dụng, nó sẽ là 4 byte. 321 00:26:34,530 --> 00:26:42,570 Nếu bạn đang sử dụng 64-bit như rất nhiều các máy tính gần đây, nó sẽ là 8 byte. 322 00:26:42,570 --> 00:26:45,230 >> Ints hầu như luôn luôn 4 byte vào thời điểm này. 323 00:26:45,230 --> 00:26:47,140 Chờ đợi Long là hầu như luôn luôn 8 bytes. 324 00:26:47,140 --> 00:26:50,300 Trong quá khứ, ints được sử dụng để chỉ là 2 byte. 325 00:26:50,300 --> 00:26:56,840 Nhưng hãy chú ý rằng điều này hoàn toàn đáp ứng tất cả các mối quan hệ lớn hơn hoặc bằng. 326 00:26:56,840 --> 00:27:01,280 Vì vậy, miễn là hoàn toàn được phép có cùng kích thước như một số nguyên, 327 00:27:01,280 --> 00:27:04,030 và nó cũng được phép có cùng kích thước như một lâu dài. 328 00:27:04,030 --> 00:27:11,070 Và nó chỉ như vậy sẽ xảy ra là 99,999% của các hệ thống, nó là có được bằng 329 00:27:11,070 --> 00:27:15,800 hoặc một int hoặc một lâu dài. Nó chỉ phụ thuộc vào-32 bit hoặc 64-bit. >> [Sinh viên] Okay. 330 00:27:15,800 --> 00:27:24,600 Trong phao, làm thế nào là điểm thập phân được chỉ định trong các bit? 331 00:27:24,600 --> 00:27:27,160 Giống như như nhị phân? >> Yeah. 332 00:27:27,160 --> 00:27:30,570 Bạn không cần phải biết rằng đối với CS50. 333 00:27:30,570 --> 00:27:32,960 Bạn thậm chí không biết rằng ở 61. 334 00:27:32,960 --> 00:27:37,350 Bạn không thể học mà thực sự trong bất kỳ khóa học nào. 335 00:27:37,350 --> 00:27:42,740 Nó chỉ là một đại diện. 336 00:27:42,740 --> 00:27:45,440 Tôi quên allotments bit chính xác. 337 00:27:45,440 --> 00:27:53,380 Ý tưởng về điểm nổi là bạn phân bổ một số cụ thể của bit để đại diện - 338 00:27:53,380 --> 00:27:56,550 Về cơ bản, mọi thứ trong ký hiệu khoa học. 339 00:27:56,550 --> 00:28:05,600 Vì vậy, bạn phân bổ một số cụ thể của bit để đại diện cho số, như 1,2345. 340 00:28:05,600 --> 00:28:10,200 Tôi không bao giờ có thể đại diện cho một số với chữ số hơn 5. 341 00:28:12,200 --> 00:28:26,300 Sau đó, bạn cũng có thể phân bổ một số cụ thể của bit để nó có xu hướng trở nên giống như 342 00:28:26,300 --> 00:28:32,810 bạn chỉ có thể đi đến một số lượng nhất định, như đó là số mũ lớn nhất bạn có thể có, 343 00:28:32,810 --> 00:28:36,190 và bạn chỉ có thể đi xuống đến một số mũ nào đó, 344 00:28:36,190 --> 00:28:38,770 như đó là số mũ nhỏ nhất bạn có thể có. 345 00:28:38,770 --> 00:28:44,410 >> Tôi không nhớ các bit cách chính xác được giao cho tất cả các giá trị, 346 00:28:44,410 --> 00:28:47,940 nhưng một số lượng nhất định của các bit được dành riêng 1,2345, 347 00:28:47,940 --> 00:28:50,930 một số lượng nhất định của các bit được dành riêng cho số mũ, 348 00:28:50,930 --> 00:28:55,670 và nó chỉ có thể đại diện cho một số mũ của một kích thước nhất định. 349 00:28:55,670 --> 00:29:01,100 [Sinh viên] Và một đôi? Là giống như một phao dài thêm? >> Yeah. 350 00:29:01,100 --> 00:29:07,940 Đó là điều tương tự như một phao ngoại trừ bây giờ bạn đang sử dụng 8 byte thay vì 4 byte. 351 00:29:07,940 --> 00:29:11,960 Bây giờ bạn sẽ có thể sử dụng 9 chữ số hoặc 10 chữ số, 352 00:29:11,960 --> 00:29:16,630 và điều này sẽ có thể tăng lên đến 300 thay vì 100. >> [Sinh viên] Okay. 353 00:29:16,630 --> 00:29:21,550 Và nổi cũng là 4 byte. >>. 354 00:29:21,550 --> 00:29:27,520 Vâng, một lần nữa, nó có thể phụ thuộc tổng thể thực hiện chung, 355 00:29:27,520 --> 00:29:30,610 nhưng nổi là 4 byte, tăng gấp đôi là 8. 356 00:29:30,610 --> 00:29:33,440 Đôi được gọi là tăng gấp đôi bởi vì họ là tăng gấp đôi kích thước của phao nổi. 357 00:29:33,440 --> 00:29:38,380 [Sinh viên] Okay. Và có đôi tăng gấp đôi? >> Không có. 358 00:29:38,380 --> 00:29:43,660 Tôi nghĩ rằng - >> [sinh viên] Giống như chờ đợi lâu? >> Yeah. Tôi không nghi vậy. Vâng. 359 00:29:43,660 --> 00:29:45,950 [Sinh viên] Trong thử nghiệm năm ngoái đã có một câu hỏi về các chức năng chính 360 00:29:45,950 --> 00:29:49,490 phải là một phần của chương trình của bạn. 361 00:29:49,490 --> 00:29:52,310 Câu trả lời là rằng nó không phải là một phần của chương trình của bạn. 362 00:29:52,310 --> 00:29:55,100 Trong những gì tình hình? Đó là những gì tôi thấy. 363 00:29:55,100 --> 00:29:59,090 [Bowden] Có vẻ như - >> [sinh viên] tình hình gì? 364 00:29:59,090 --> 00:30:02,880 Bạn có vấn đề? >> [Sinh viên] Yeah, tôi chắc chắn có thể kéo nó lên. 365 00:30:02,880 --> 00:30:07,910 Nó không phải là, về mặt kỹ thuật, nhưng về cơ bản nó sẽ là. 366 00:30:07,910 --> 00:30:10,030 [Sinh viên] Tôi thấy một trên một năm khác nhau. 367 00:30:10,030 --> 00:30:16,220 Nó giống như là Đúng hay Sai: hợp lệ - >> Oh, một tập tin c? 368 00:30:16,220 --> 00:30:18,790 [Sinh viên] Bất kỳ c tập tin phải có - [cả hai nói cùng một lúc - không thể hiểu] 369 00:30:18,790 --> 00:30:21,120 Okay. Vì vậy, đó là riêng biệt. 370 00:30:21,120 --> 00:30:26,800 >> A c file. Chỉ cần để chứa các chức năng. 371 00:30:26,800 --> 00:30:32,400 Bạn có thể biên dịch một tập tin vào mã máy, nhị phân, bất cứ điều gì, 372 00:30:32,400 --> 00:30:36,620 mà không có nó là thực thi. 373 00:30:36,620 --> 00:30:39,420 File thực thi hợp lệ phải có một hàm main. 374 00:30:39,420 --> 00:30:45,460 Bạn có thể viết 100 chức năng trong 1 tập tin nhưng không chính 375 00:30:45,460 --> 00:30:48,800 và sau đó biên dịch sang nhị phân, 376 00:30:48,800 --> 00:30:54,460 sau đó bạn viết một tập tin mà chỉ có chính nhưng nó gọi một loạt các chức năng này 377 00:30:54,460 --> 00:30:56,720 trong tập tin nhị phân này ở đây. 378 00:30:56,720 --> 00:31:01,240 Và như vậy khi bạn đang làm thực thi, đó là mối liên kết 379 00:31:01,240 --> 00:31:05,960 là nó kết hợp các tập tin nhị phân 2 vào một tập tin thực thi. 380 00:31:05,960 --> 00:31:11,400 Vì vậy, một c tập tin không cần phải có một chức năng chính ở tất cả. 381 00:31:11,400 --> 00:31:19,220 Và trên cơ sở mã lớn, bạn sẽ thấy hàng ngàn các tập tin c. Và 1 tập tin chính. 382 00:31:23,960 --> 00:31:26,110 Câu hỏi nhiều hơn? 383 00:31:29,310 --> 00:31:31,940 [Sinh viên] Có một câu hỏi khác. 384 00:31:31,940 --> 00:31:36,710 Nó nói làm là một trình biên dịch. Đúng hay Sai? 385 00:31:36,710 --> 00:31:42,030 Và câu trả lời là sai, và tôi hiểu lý do tại sao nó không giống như Clang. 386 00:31:42,030 --> 00:31:44,770 Nhưng những gì chúng ta gọi làm nếu nó không? 387 00:31:44,770 --> 00:31:49,990 Hãy là cơ bản chỉ - tôi có thể thấy chính xác những gì nó gọi nó. 388 00:31:49,990 --> 00:31:52,410 Nhưng nó chỉ chạy lệnh. 389 00:31:53,650 --> 00:31:55,650 Thực hiện. 390 00:31:58,240 --> 00:32:00,870 Tôi có thể kéo lên này. Yeah. 391 00:32:10,110 --> 00:32:13,180 Oh, yeah. Thực hiện cũng có nào đó. 392 00:32:13,180 --> 00:32:17,170 Điều này nói rằng mục đích của tiện ích make là để xác định tự động 393 00:32:17,170 --> 00:32:19,610 phần của một chương trình lớn cần phải được biên dịch lại 394 00:32:19,610 --> 00:32:22,350 và ban hành các lệnh để biên dịch lại chúng. 395 00:32:22,350 --> 00:32:27,690 Bạn có thể làm cho các tập tin là hoàn toàn rất lớn. 396 00:32:27,690 --> 00:32:33,210 Hãy nhìn vào tem thời gian của các tập tin, và như chúng tôi đã nói trước đây, 397 00:32:33,210 --> 00:32:36,930 bạn có thể biên dịch các tập tin cá nhân, và nó không phải cho đến khi bạn nhận được các mối liên kết 398 00:32:36,930 --> 00:32:39,270 rằng họ đang đặt lại với nhau thành một thực thi. 399 00:32:39,270 --> 00:32:43,810 Vì vậy, nếu bạn có 10 tập tin khác nhau và bạn thực hiện một sự thay đổi đến 1 trong số họ, 400 00:32:43,810 --> 00:32:47,870 sau đó những gì làm cho là sẽ làm là chỉ cần biên dịch lại 1 tập tin 401 00:32:47,870 --> 00:32:50,640 và sau đó liên kết lại tất cả mọi thứ với nhau. 402 00:32:50,640 --> 00:32:53,020 Nhưng đó là ngớ ngẩn hơn thế rất nhiều. 403 00:32:53,020 --> 00:32:55,690 Đó là vào bạn để hoàn toàn xác định rằng đó là những gì nó cần phải làm. 404 00:32:55,690 --> 00:32:59,560 Nó theo mặc định có khả năng nhận ra các công cụ này tem thời gian, 405 00:32:59,560 --> 00:33:03,220 nhưng bạn có thể viết một tập tin làm cho làm bất cứ điều gì. 406 00:33:03,220 --> 00:33:09,150 Bạn có thể viết một tập tin để khi bạn gõ làm cho nó chỉ cd vào thư mục khác. 407 00:33:09,150 --> 00:33:15,560 Tôi đã cảm thấy thất vọng bởi vì tôi tack tất cả mọi thứ bên trong của gia dụng của tôi 408 00:33:15,560 --> 00:33:21,740 và sau đó tôi xem các file PDF từ máy Mac. 409 00:33:21,740 --> 00:33:30,720 >> Vì vậy, tôi hãy vào Finder và tôi có thể đi, kết nối với máy chủ, 410 00:33:30,720 --> 00:33:36,950 và các máy chủ kết nối với gia dụng của tôi, và sau đó tôi mở ra PDF 411 00:33:36,950 --> 00:33:40,190 được biên dịch LaTeX. 412 00:33:40,190 --> 00:33:49,320 Nhưng tôi đã thất vọng bởi vì mỗi lần duy nhất tôi cần thiết để làm mới PDF, 413 00:33:49,320 --> 00:33:53,900 Tôi đã để sao chép nó vào một thư mục cụ thể mà nó có thể truy cập 414 00:33:53,900 --> 00:33:57,710 và nó đã nhận được gây phiền nhiễu. 415 00:33:57,710 --> 00:34:02,650 Vì vậy, thay vào đó tôi đã viết một tập tin thực hiện, bạn phải xác định làm thế nào nó làm cho mọi thứ. 416 00:34:02,650 --> 00:34:06,130 Làm thế nào bạn thực hiện trong này là PDF LaTeX. 417 00:34:06,130 --> 00:34:10,090 Cũng giống như bất kỳ tập tin làm cho khác - tôi đoán bạn không nhìn thấy các tập tin làm cho, 418 00:34:10,090 --> 00:34:13,510 nhưng chúng tôi có trong Ứng dụng một tập tin làm cho toàn cầu mà chỉ nói, 419 00:34:13,510 --> 00:34:16,679 nếu bạn đang biên soạn một tập tin C, sử dụng Clang. 420 00:34:16,679 --> 00:34:20,960 Và vì vậy ở đây trong tập tin làm cho tôi rằng tôi làm cho tôi nói, 421 00:34:20,960 --> 00:34:25,020 tập tin này, bạn sẽ muốn để biên dịch với PDF LaTeX. 422 00:34:25,020 --> 00:34:27,889 Và thật LaTeX PDF đó là làm việc biên dịch. 423 00:34:27,889 --> 00:34:31,880 Phải là không biên dịch. Nó chỉ chạy các lệnh trong trình tự tôi đã chỉ định. 424 00:34:31,880 --> 00:34:36,110 Vì vậy, nó chạy PDF LaTeX, nó sao chép nó vào thư mục tôi muốn nó được sao chép vào, 425 00:34:36,110 --> 00:34:38,270 nó cd vào thư mục và không những thứ khác, 426 00:34:38,270 --> 00:34:42,380 nhưng tất cả nó được nhận ra khi một thay đổi tập tin, 427 00:34:42,380 --> 00:34:45,489 và nếu nó thay đổi, sau đó nó sẽ chạy những lệnh mà nó phải chạy 428 00:34:45,489 --> 00:34:48,760 khi thay đổi tập tin. >> [Sinh viên] Okay. 429 00:34:50,510 --> 00:34:54,420 Tôi không biết nơi mà các tập tin làm cho toàn cầu cho tôi để kiểm tra xem nó ra. 430 00:34:57,210 --> 00:35:04,290 Các câu hỏi khác? Bất cứ điều gì từ quá khứ câu đố? Bất kỳ điều con trỏ? 431 00:35:06,200 --> 00:35:08,730 Có những điều tinh tế với con trỏ như - 432 00:35:08,730 --> 00:35:10,220 Tôi sẽ không để có thể tìm thấy một câu hỏi bài kiểm tra trên đó - 433 00:35:10,220 --> 00:35:16,250 nhưng cũng giống như các loại điều này. 434 00:35:19,680 --> 00:35:24,060 Hãy chắc chắn rằng bạn hiểu rằng khi tôi nói int * x * y - 435 00:35:24,890 --> 00:35:28,130 Điều này là không chính xác bất cứ điều gì ở đây, tôi đoán. 436 00:35:28,130 --> 00:35:32,140 Nhưng giống như * x * y, những người đang có 2 biến trên stack. 437 00:35:32,140 --> 00:35:37,220 Khi tôi nói x = malloc (sizeof (int)), x là một biến trên stack, 438 00:35:37,220 --> 00:35:41,180 malloc là một số khối trên trong đống, và chúng tôi đang có x điểm heap. 439 00:35:41,180 --> 00:35:43,900 >> Vì vậy, một cái gì đó trên các ngăn xếp để heap. 440 00:35:43,900 --> 00:35:48,100 Bất cứ khi nào bạn malloc bất cứ điều gì, bạn chắc chắn lưu trữ nó bên trong của một con trỏ. 441 00:35:48,100 --> 00:35:55,940 Vì vậy, rằng con trỏ là trên stack, khối malloced trên heap. 442 00:35:55,940 --> 00:36:01,240 Rất nhiều người bị lẫn lộn và nói int * x = malloc, x là trên heap. 443 00:36:01,240 --> 00:36:04,100 Số gì x điểm đến là trên heap. 444 00:36:04,100 --> 00:36:08,540 x chính nó là trên stack, trừ khi vì lý do gì đã x là một biến toàn cầu, 445 00:36:08,540 --> 00:36:11,960 trong trường hợp này nó sẽ xảy ra trong một khu vực bộ nhớ. 446 00:36:13,450 --> 00:36:20,820 Vì vậy, việc theo dõi, các sơ đồ hộp và mũi tên khá phổ biến cho các bài kiểm tra. 447 00:36:20,820 --> 00:36:25,740 Hoặc nếu nó không phải trên đố 0, nó sẽ được bài kiểm tra 1. 448 00:36:27,570 --> 00:36:31,940 Bạn nên biết tất cả những điều này, các bước biên soạn 449 00:36:31,940 --> 00:36:35,740 kể từ khi bạn đã trả lời câu hỏi về những người. Vâng. 450 00:36:35,740 --> 00:36:38,940 [Sinh viên] chúng ta có thể đi qua những bước - >> chắc. 451 00:36:48,340 --> 00:36:58,640 Trước khi bước và biên dịch chúng tôi có bộ tiền xử lý, 452 00:36:58,640 --> 00:37:16,750 biên soạn, lắp ráp, và liên kết. 453 00:37:16,750 --> 00:37:21,480 Tiền xử lý. Điều đó làm gì? 454 00:37:29,720 --> 00:37:32,290 Đó là bước đơn giản nhất - tốt, không giống như - 455 00:37:32,290 --> 00:37:35,770 điều đó không có nghĩa là nó nên được rõ ràng, nhưng đó là bước đơn giản nhất. 456 00:37:35,770 --> 00:37:38,410 Các bạn có thể thực hiện nó chính mình. Yeah. 457 00:37:38,410 --> 00:37:43,410 [Sinh viên] những gì bạn có trong của bạn bao gồm như thế này và nó sao chép và sau đó cũng xác định. 458 00:37:43,410 --> 00:37:49,250 Nó tìm kiếm những thứ như # include và # xác định, 459 00:37:49,250 --> 00:37:53,800 và nó chỉ là bản sao và dạng bột nhão những gì những người thực sự có ý nghĩa. 460 00:37:53,800 --> 00:37:59,240 Vì vậy, khi bạn nói # bao gồm cs50.h, tiền xử lý là sao chép và dán cs50.h 461 00:37:59,240 --> 00:38:01,030 vào dòng đó. 462 00:38:01,030 --> 00:38:06,640 Khi bạn nói # xác định x là 4, tiền xử lý đi qua toàn bộ chương trình 463 00:38:06,640 --> 00:38:10,400 và thay thế tất cả các trường hợp của x với 4. 464 00:38:10,400 --> 00:38:17,530 Vì vậy, tiền xử lý có một tập tin C hợp lệ và kết quả đầu ra một tập tin C hợp lệ 465 00:38:17,530 --> 00:38:20,300 nơi mà mọi thứ đã được sao chép và dán. 466 00:38:20,300 --> 00:38:24,230 Vì vậy, bây giờ biên dịch. Điều đó làm gì? 467 00:38:25,940 --> 00:38:28,210 [Sinh viên] đi từ C đến nhị phân. 468 00:38:28,210 --> 00:38:30,970 >> [Bowden] Nó không đi tất cả các cách để nhị phân. 469 00:38:30,970 --> 00:38:34,220 [Sinh viên] mã máy sau đó? >> Đó không phải là mã máy. 470 00:38:34,220 --> 00:38:35,700 [Sinh viên] hội? >> Hội. 471 00:38:35,700 --> 00:38:38,890 Nó đi vào hội trước khi nó đi tất cả các cách để mã C, 472 00:38:38,890 --> 00:38:45,010 và hầu hết các ngôn ngữ làm một cái gì đó như thế này. 473 00:38:47,740 --> 00:38:50,590 Chọn bất kỳ ngôn ngữ cấp cao, và nếu bạn đang đi để biên dịch nó, 474 00:38:50,590 --> 00:38:52,390 nó có khả năng biên dịch trong các bước. 475 00:38:52,390 --> 00:38:58,140 Đầu tiên nó sẽ biên dịch Python C, sau đó nó sẽ biên dịch C để hội, 476 00:38:58,140 --> 00:39:01,600 và sau đó hội sẽ nhận được dịch sang nhị phân. 477 00:39:01,600 --> 00:39:07,800 Vì vậy, biên dịch được sẽ mang lại cho nó từ C đến hội. 478 00:39:07,800 --> 00:39:12,130 Từ biên dịch thường có nghĩa là đưa nó từ một mức độ cao hơn 479 00:39:12,130 --> 00:39:14,340 một ngôn ngữ lập trình cấp thấp hơn. 480 00:39:14,340 --> 00:39:19,190 Vì vậy, đây là bước duy nhất trong việc lập, nơi mà bạn bắt đầu với một ngôn ngữ cấp cao 481 00:39:19,190 --> 00:39:23,270 và kết thúc bằng một ngôn ngữ cấp thấp, và đó là lý do tại sao bước được gọi là biên dịch. 482 00:39:25,280 --> 00:39:33,370 [Sinh viên] Trong quá trình biên soạn, chúng ta hãy nói rằng bạn đã thực hiện # bao gồm cs50.h. 483 00:39:33,370 --> 00:39:42,190 Trình biên dịch biên dịch lại các cs50.h, giống như các chức năng mà trong đó, 484 00:39:42,190 --> 00:39:45,280 và dịch thành mã hội là tốt, 485 00:39:45,280 --> 00:39:50,830 hoặc nó sẽ sao chép và dán một cái gì đó là được trước hội? 486 00:39:50,830 --> 00:39:56,910 cs50.h sẽ khá nhiều không bao giờ kết thúc hội. 487 00:39:59,740 --> 00:40:03,680 Các công cụ như nguyên mẫu chức năng và những thứ chỉ dành cho bạn phải cẩn thận. 488 00:40:03,680 --> 00:40:09,270 Nó đảm bảo rằng các trình biên dịch có thể kiểm tra những thứ như bạn đang gọi chức năng 489 00:40:09,270 --> 00:40:12,910 với các loại trả lại quyền và các đối số và các công cụ phù hợp. 490 00:40:12,910 --> 00:40:18,350 >> Vì vậy, cs50.h sẽ được preprocessed vào tập tin, và sau đó khi nó được biên dịch 491 00:40:18,350 --> 00:40:22,310 Về cơ bản nó vứt bỏ sau khi nó làm cho chắc chắn rằng tất cả mọi thứ được gọi chính xác. 492 00:40:22,310 --> 00:40:29,410 Nhưng các chức năng quy định trong thư viện CS50, riêng biệt từ cs50.h, 493 00:40:29,410 --> 00:40:33,610 những người sẽ không được biên soạn riêng. 494 00:40:33,610 --> 00:40:37,270 Điều đó thực sự sẽ đi xuống trong bước kết nối, vì vậy chúng tôi sẽ nhận được trong một giây. 495 00:40:37,270 --> 00:40:40,100 Nhưng trước tiên, những gì đang lắp ráp? 496 00:40:41,850 --> 00:40:44,500 [Sinh viên] hội nhị phân? >> Yeah. 497 00:40:46,300 --> 00:40:48,190 Lắp ráp. 498 00:40:48,190 --> 00:40:54,710 Chúng tôi không gọi đó là biên dịch bởi vì hội là khá nhiều một bản dịch thuần túy nhị phân. 499 00:40:54,710 --> 00:41:00,230 Có rất ít logic trong đi từ hội để nhị phân. 500 00:41:00,230 --> 00:41:03,180 Nó giống như nhìn lên trong một bảng, oh, chúng tôi có hướng dẫn này; 501 00:41:03,180 --> 00:41:06,290 tương ứng để nhị phân 01.110. 502 00:41:10,200 --> 00:41:15,230 Và như vậy các tập tin mà lắp ráp thường kết quả đầu ra các tập tin o. 503 00:41:15,230 --> 00:41:19,020 Và o các tập tin là những gì chúng tôi đã nói trước, 504 00:41:19,020 --> 00:41:21,570 làm thế nào một tập tin không cần phải có một chức năng chính. 505 00:41:21,570 --> 00:41:27,640 Tập tin bất kỳ có thể được biên dịch vào một tập tin o. Miễn là nó là một tập tin C hợp lệ. 506 00:41:27,640 --> 00:41:30,300 Nó có thể được biên dịch xuống. O. 507 00:41:30,300 --> 00:41:43,030 Bây giờ, liên kết là những gì thực sự mang lại một loạt các o các tập tin và mang lại cho họ một tập tin thực thi. 508 00:41:43,030 --> 00:41:51,110 Và vì vậy những gì liên kết nào bạn có thể nghĩ của thư viện CS50 như một tập tin o. 509 00:41:51,110 --> 00:41:56,980 Nó là một tập tin nhị phân đã được biên dịch. 510 00:41:56,980 --> 00:42:03,530 Và như vậy khi bạn biên dịch tập tin của bạn, hello.c của bạn, mà các cuộc gọi GetString, 511 00:42:03,530 --> 00:42:06,360 hello.c được biên dịch xuống hello.o, 512 00:42:06,360 --> 00:42:08,910 hello.o bây giờ là trong nhị phân. 513 00:42:08,910 --> 00:42:12,830 Nó sử dụng GetString, vì vậy nó cần phải đi qua để cs50.o, 514 00:42:12,830 --> 00:42:16,390 và mối liên kết smooshes chúng lại với nhau và bản sao GetString vào tập tin này 515 00:42:16,390 --> 00:42:20,640 và đi ra với một thực thi có tất cả các chức năng cần thiết. 516 00:42:20,640 --> 00:42:32,620 Vì vậy, cs50.o là không thực sự là một tập tin O, nhưng nó đủ gần là không có sự khác biệt cơ bản. 517 00:42:32,620 --> 00:42:36,880 Vì vậy, liên kết chỉ mang đến một loạt các tập tin với nhau 518 00:42:36,880 --> 00:42:41,390 riêng chứa tất cả các chức năng cần phải sử dụng 519 00:42:41,390 --> 00:42:46,120 và tạo ra các thực thi mà sẽ thực sự chạy. 520 00:42:48,420 --> 00:42:50,780 >> Và đó cũng là những gì chúng tôi đã nói trước 521 00:42:50,780 --> 00:42:55,970 nơi bạn có thể có 1000 c các tập tin, bạn biên dịch tất cả chúng để o các tập tin,. 522 00:42:55,970 --> 00:43:00,040 mà có lẽ sẽ mất một thời gian, sau đó bạn thay đổi 1 file c. 523 00:43:00,040 --> 00:43:05,480 Bạn chỉ cần biên dịch lại 1. C tập tin và sau đó tất cả mọi thứ relink khác, 524 00:43:05,480 --> 00:43:07,690 liên kết tất cả mọi thứ trở lại với nhau. 525 00:43:09,580 --> 00:43:11,430 [Sinh viên] Khi chúng tôi đang liên kết chúng ta viết lcs50? 526 00:43:11,430 --> 00:43:20,510 Yeah, cái lcs50. Mà lá cờ tín hiệu để mối liên kết mà bạn cần phải liên kết trong thư viện đó. 527 00:43:26,680 --> 00:43:28,910 Câu hỏi? 528 00:43:41,310 --> 00:43:46,860 Chúng ta đã đi qua nhị phân khác hơn so với 5 giây trong bài giảng đầu tiên? 529 00:43:50,130 --> 00:43:53,010 Tôi không nghi vậy. 530 00:43:55,530 --> 00:43:58,820 Bạn nên biết tất cả của hệ điều hành lớn mà chúng tôi đã đi qua, 531 00:43:58,820 --> 00:44:02,670 và bạn sẽ có khả năng, nếu chúng ta đã cho bạn một chức năng, 532 00:44:02,670 --> 00:44:09,410 bạn sẽ có thể nói đó là O lớn, khoảng. Hoặc tốt, O lớn là thô. 533 00:44:09,410 --> 00:44:15,300 Vì vậy, nếu bạn thấy lồng nhau cho các vòng Looping trên cùng một số vật, 534 00:44:15,300 --> 00:44:22,260 như int i, i > [sinh viên] n bình phương. >> Nó có xu hướng được n bình phương. 535 00:44:22,260 --> 00:44:25,280 Nếu bạn đã ba lồng nhau, nó có xu hướng được n Cubed. 536 00:44:25,280 --> 00:44:29,330 Vì vậy, loại điều đó, bạn sẽ có thể chỉ ra ngay lập tức. 537 00:44:29,330 --> 00:44:33,890 Bạn cần phải biết sắp xếp chèn và loại bong bóng và hợp nhất phân loại và tất cả những người. 538 00:44:33,890 --> 00:44:41,420 Nó dễ dàng hơn để hiểu lý do tại sao họ là những n bình phương và n log n và tất cả những điều đó 539 00:44:41,420 --> 00:44:47,810 bởi vì tôi nghĩ rằng đã có một bài kiểm tra một năm chúng tôi về cơ bản cho bạn 540 00:44:47,810 --> 00:44:55,050 thực hiện các loại bong bóng và nói, "thời gian hoạt động của chức năng này là gì?" 541 00:44:55,050 --> 00:45:01,020 Vì vậy, nếu bạn nhận ra nó như là loại bong bóng, sau đó bạn có thể ngay lập tức nói n bình phương. 542 00:45:01,020 --> 00:45:05,470 Nhưng nếu bạn chỉ cần nhìn vào nó, bạn thậm chí không cần phải nhận ra loại bong bóng; 543 00:45:05,470 --> 00:45:08,990 bạn chỉ có thể nói điều này là làm điều này và điều này. Này là n bình phương. 544 00:45:12,350 --> 00:45:14,710 [Sinh viên] Có bất kỳ ví dụ khó khăn bạn có thể đến với 545 00:45:14,710 --> 00:45:20,370 như một ý tưởng tương tự để tìm ra? 546 00:45:20,370 --> 00:45:24,450 >> Tôi không nghĩ rằng chúng tôi sẽ cung cấp cho bạn bất kỳ ví dụ khó khăn. 547 00:45:24,450 --> 00:45:30,180 Việc sắp xếp bong bóng là về là khó khăn như chúng tôi sẽ đi, 548 00:45:30,180 --> 00:45:36,280 và thậm chí đó, miễn là bạn hiểu rằng bạn đang iterating trên mảng 549 00:45:36,280 --> 00:45:41,670 cho mỗi phần tử trong mảng, là có được cái gì đó là n bình phương. 550 00:45:45,370 --> 00:45:49,940 Có những câu hỏi chung, ngay tại đây, chúng tôi có - Oh. 551 00:45:55,290 --> 00:45:58,530 Một ngày khác, Doug tuyên bố, "Tôi đã phát minh ra một thuật toán mà có thể sắp xếp một mảng 552 00:45:58,530 --> 00:46:01,780 "Số n trong O (log n) thời gian!" 553 00:46:01,780 --> 00:46:04,900 Vì vậy, làm thế nào để chúng ta biết đó là không thể? 554 00:46:04,900 --> 00:46:08,850 [Không nghe được sinh viên phản ứng] >> Yeah. 555 00:46:08,850 --> 00:46:13,710 Ít nhất, bạn phải chạm vào mỗi phần tử trong mảng, 556 00:46:13,710 --> 00:46:16,210 vì vậy nó không thể sắp xếp một mảng - 557 00:46:16,210 --> 00:46:20,850 Nếu tất cả mọi thứ để phân loại, sau đó bạn sẽ được chạm vào tất cả mọi thứ trong mảng, 558 00:46:20,850 --> 00:46:25,320 do đó, nó không thể làm điều đó trong ít hơn O của n. 559 00:46:27,430 --> 00:46:30,340 [Sinh viên] cho chúng ta thấy rằng ví dụ có khả năng để làm điều đó trong O n 560 00:46:30,340 --> 00:46:33,920 nếu bạn sử dụng rất nhiều bộ nhớ. >> Yeah. 561 00:46:33,920 --> 00:46:37,970 Và Đó - tôi quên những gì that's nó đếm loại? 562 00:46:47,360 --> 00:46:51,330 Hmm. Đó là một thuật toán phân loại số nguyên. 563 00:46:59,850 --> 00:47:05,100 Tôi đang tìm kiếm các tên đặc biệt cho điều này mà tôi không thể nhớ tuần trước. 564 00:47:05,100 --> 00:47:13,000 Yeah. Đây là các loại của các loại mà có thể thực hiện những điều trong O lớn của n. 565 00:47:13,000 --> 00:47:18,430 Nhưng có những hạn chế, như bạn chỉ có thể sử dụng số nguyên đến một số lượng nhất định. 566 00:47:20,870 --> 00:47:24,560 Cộng thêm nếu bạn đang cố gắng để sắp xếp that's một cái gì đó - 567 00:47:24,560 --> 00:47:30,750 Nếu mảng của bạn là 012, -12, 151, 4 triệu đồng, 568 00:47:30,750 --> 00:47:35,120 sau đó là yếu tố duy nhất được sẽ hoàn toàn hủy hoại toàn bộ việc phân loại. 569 00:47:42,060 --> 00:47:44,030 >> Câu hỏi? 570 00:47:49,480 --> 00:47:58,870 [Sinh viên] Nếu bạn có một hàm đệ quy và nó chỉ làm cho các cuộc gọi đệ quy 571 00:47:58,870 --> 00:48:02,230 trong một tuyên bố trở lại, đó là đệ quy đuôi, 572 00:48:02,230 --> 00:48:07,360 và do đó sẽ không sử dụng bộ nhớ nhiều hơn nữa trong thời gian chạy 573 00:48:07,360 --> 00:48:12,550 hoặc ít nhất sẽ sử dụng bộ nhớ so sánh như một giải pháp lặp đi lặp lại? 574 00:48:12,550 --> 00:48:14,530 [Bowden]. 575 00:48:14,530 --> 00:48:19,840 Nó có khả năng sẽ là hơi chậm, nhưng không thực sự. 576 00:48:19,840 --> 00:48:23,290 Đệ quy đuôi là khá tốt. 577 00:48:23,290 --> 00:48:32,640 Nhìn lại các khung stack, chúng ta hãy nói rằng chúng ta có chính 578 00:48:32,640 --> 00:48:42,920 và chúng tôi có thanh int (int x) hoặc một cái gì đó. 579 00:48:42,920 --> 00:48:52,310 Đây không phải là một hàm đệ quy hoàn hảo, nhưng trở lại bar (x - 1). 580 00:48:52,310 --> 00:48:57,620 Vì vậy, rõ ràng, điều này là sai lầm. Bạn cần phải trường hợp cơ sở và các công cụ. 581 00:48:57,620 --> 00:49:00,360 Tuy nhiên, ý tưởng ở đây là đây là đệ quy đuôi, 582 00:49:00,360 --> 00:49:06,020 có nghĩa là khi thanh cuộc gọi chính nó sẽ nhận được stack frame. 583 00:49:09,550 --> 00:49:12,440 Stack frame này sẽ là một khối ít bộ nhớ 584 00:49:12,440 --> 00:49:17,490 tương ứng với đối số x của nó. 585 00:49:17,490 --> 00:49:25,840 Và do đó, chúng ta hãy nói rằng chính xảy ra để gọi bar (100); 586 00:49:25,840 --> 00:49:30,050 Vì vậy, x sẽ bắt đầu ra như là 100. 587 00:49:30,050 --> 00:49:35,660 Nếu trình biên dịch nhận ra rằng đây là một chức năng đệ quy đuôi, 588 00:49:35,660 --> 00:49:38,540 sau đó khi thanh làm cho cuộc gọi đệ quy của nó để thanh, 589 00:49:38,540 --> 00:49:45,490 thay vì làm một khung stack mới, đó là nơi mà ngăn xếp bắt đầu phát triển phần lớn, 590 00:49:45,490 --> 00:49:48,220 cuối cùng nó sẽ chạy vào heap và sau đó bạn sẽ có được segfaults 591 00:49:48,220 --> 00:49:51,590 bởi vì bộ nhớ bắt đầu va chạm. 592 00:49:51,590 --> 00:49:54,830 >> Vì vậy, thay vì làm cho khung stack riêng của mình, nó có thể nhận ra, 593 00:49:54,830 --> 00:49:59,080 hey, tôi không bao giờ thực sự cần phải quay trở lại stack frame này, 594 00:49:59,080 --> 00:50:08,040 do đó, thay vào đó tôi sẽ chỉ thay thế đối số này với 99 và sau đó bắt đầu thanh trên tất cả. 595 00:50:08,040 --> 00:50:11,810 Và sau đó nó sẽ làm điều đó một lần nữa và nó sẽ đạt đến thanh trở lại (x - 1), 596 00:50:11,810 --> 00:50:17,320 và thay vì làm một stack frame mới, nó chỉ sẽ thay thế tham số hiện tại của nó với 98 597 00:50:17,320 --> 00:50:20,740 và sau đó nhảy đến sự khởi đầu của thanh. 598 00:50:23,860 --> 00:50:30,430 Những hoạt động, thay thế giá trị đó 1 trên stack và nhảy trở lại để bắt đầu, 599 00:50:30,430 --> 00:50:32,430 là khá hiệu quả. 600 00:50:32,430 --> 00:50:41,500 Vì vậy, không chỉ là sử dụng bộ nhớ giống như là một chức năng riêng biệt được lặp đi lặp lại 601 00:50:41,500 --> 00:50:45,390 bởi vì bạn chỉ sử dụng 1 stack frame, nhưng bạn không bị các nhược điểm 602 00:50:45,390 --> 00:50:47,240 có để gọi chức năng. 603 00:50:47,240 --> 00:50:50,240 Chức năng gọi điện thoại có thể hơi tốn kém bởi vì nó đã làm tất cả những thiết lập này 604 00:50:50,240 --> 00:50:52,470 và teardown và tất cả các công cụ này. 605 00:50:52,470 --> 00:50:58,160 Vì vậy, điều này đệ quy đuôi là tốt. 606 00:50:58,160 --> 00:51:01,170 [Sinh viên] Tại sao nó không tạo ra bước tiến mới? 607 00:51:01,170 --> 00:51:02,980 Bởi vì nó nhận ra rằng nó không cần phải. 608 00:51:02,980 --> 00:51:07,800 Các cuộc gọi đến một quán bar chỉ là trở về cuộc gọi đệ quy. 609 00:51:07,800 --> 00:51:12,220 Vì vậy, nó không cần phải làm bất cứ điều gì với các giá trị trả về. 610 00:51:12,220 --> 00:51:15,120 Nó sẽ ngay lập tức trả lại. 611 00:51:15,120 --> 00:51:20,530 Vì vậy, nó sẽ thay thế lập luận riêng của mình và bắt đầu lại từ đầu. 612 00:51:20,530 --> 00:51:25,780 Và cũng có thể, nếu bạn không có phiên bản đệ quy đuôi, 613 00:51:25,780 --> 00:51:31,460 sau đó bạn sẽ có được tất cả các quán bar, nơi khi thanh này trả về 614 00:51:31,460 --> 00:51:36,010 nó phải trả về giá trị của nó với trang này, sau đó là thanh ngay lập tức trở 615 00:51:36,010 --> 00:51:39,620 và nó trả về giá trị là một trong những điều này, sau đó nó chỉ sẽ ngay lập tức quay trở lại 616 00:51:39,620 --> 00:51:41,350 và trả lại giá trị của nó với trường này. 617 00:51:41,350 --> 00:51:45,350 Vì vậy, bạn đang tiết kiệm này popping tất cả những việc của chồng 618 00:51:45,350 --> 00:51:48,730 kể từ khi giá trị trả lại sẽ được thông qua tất cả các cách trở lại lên anyway. 619 00:51:48,730 --> 00:51:55,400 Vậy tại sao không chỉ cần thay thế lập luận của chúng tôi với các đối số được cập nhật và bắt đầu lại từ đầu? 620 00:51:57,460 --> 00:52:01,150 Nếu chức năng không phải là đệ quy đuôi, nếu bạn làm một cái gì đó như 621 00:52:01,150 --> 00:52:07,530 [Sinh viên] bar (x + 1). >> Yeah. 622 00:52:07,530 --> 00:52:11,770 >> Vì vậy, nếu bạn đặt nó trong điều kiện, sau đó bạn đang làm một cái gì đó với giá trị trả về. 623 00:52:11,770 --> 00:52:16,260 Hoặc ngay cả khi bạn chỉ cần làm trở lại 2 bar (x - 1). 624 00:52:16,260 --> 00:52:23,560 Vì vậy, bây giờ bar (x - 1) cần phải quay trở lại để cho nó để tính toán 2 lần giá trị đó, 625 00:52:23,560 --> 00:52:26,140 vì vậy bây giờ nó không cần stack frame riêng biệt của riêng mình, 626 00:52:26,140 --> 00:52:31,180 và bây giờ, không có vấn đề khó khăn như thế nào bạn cố gắng, bạn sẽ cần phải - 627 00:52:31,180 --> 00:52:34,410 Đây không phải là đệ quy đuôi. 628 00:52:34,410 --> 00:52:37,590 [Sinh viên] Tôi sẽ cố gắng để mang lại một đệ quy để nhằm mục đích cho một đệ quy đuôi - 629 00:52:37,590 --> 00:52:41,450 [Bowden] Trong một thế giới lý tưởng, nhưng trong CS50 bạn không có. 630 00:52:43,780 --> 00:52:49,280 Để có được đệ quy đuôi, nói chung, bạn thiết lập một đối số bổ sung 631 00:52:49,280 --> 00:52:53,550 nơi thanh sẽ mất int x vào y 632 00:52:53,550 --> 00:52:56,990 và y tương ứng với điều cuối cùng bạn muốn trả lại. 633 00:52:56,990 --> 00:53:03,650 Vì vậy, sau đó bạn sẽ được trả lại bar (x - 1), 2 * y. 634 00:53:03,650 --> 00:53:09,810 Vì vậy, đó chỉ là một cấp cao như thế nào bạn biến đổi những điều cần phải được đệ quy đuôi. 635 00:53:09,810 --> 00:53:13,790 Nhưng cuộc tranh luận thêm 636 00:53:13,790 --> 00:53:17,410 Và rồi cuối cùng khi bạn đạt đến trường hợp cơ sở của bạn, bạn chỉ cần trả lại y 637 00:53:17,410 --> 00:53:22,740 bởi vì bạn đã được tích lũy toàn bộ thời gian giá trị trả về mà bạn muốn. 638 00:53:22,740 --> 00:53:27,280 Bạn chắc hẳn đã được làm việc đó lặp đi lặp lại nhưng bằng cách sử dụng các cuộc gọi đệ quy. 639 00:53:32,510 --> 00:53:34,900 Câu hỏi? 640 00:53:34,900 --> 00:53:39,890 [Sinh viên] Có lẽ về con trỏ số học, giống như khi sử dụng dây. >> Chắc chắn rồi. 641 00:53:39,890 --> 00:53:43,610 Con trỏ số học. 642 00:53:43,610 --> 00:53:48,440 Khi sử dụng dây rất dễ dàng bởi vì dây là sao char, 643 00:53:48,440 --> 00:53:51,860 ký tự là mãi mãi và luôn luôn một byte duy nhất, 644 00:53:51,860 --> 00:53:57,540 và do đó, con trỏ số học tương đương với số học thường xuyên khi bạn đang làm việc với chuỗi. 645 00:53:57,540 --> 00:54:08,790 Hãy chỉ nói char * s = "hello". 646 00:54:08,790 --> 00:54:11,430 Vì vậy, chúng tôi có một khối trong bộ nhớ. 647 00:54:19,490 --> 00:54:22,380 Nó cần 6 byte bởi vì bạn luôn cần terminator vô giá trị. 648 00:54:22,380 --> 00:54:28,620 Và char * s để trỏ đến đầu của mảng này. 649 00:54:28,620 --> 00:54:32,830 Vì vậy, s chỉ ở đó. 650 00:54:32,830 --> 00:54:36,710 Bây giờ, điều này về cơ bản là mảng bất kỳ hoạt động như thế nào, 651 00:54:36,710 --> 00:54:40,780 bất kể cho dù đó là sự trở lại của malloc hoặc cho dù đó là trên stack. 652 00:54:40,780 --> 00:54:47,110 Bất kỳ mảng về cơ bản là một con trỏ đến sự bắt đầu của mảng, 653 00:54:47,110 --> 00:54:53,640 và sau đó bất kỳ hoạt động mảng, bất kỳ lập chỉ mục, chỉ cần đi vào mảng đó nhất định bù đắp. 654 00:54:53,640 --> 00:55:05,360 >> Vì vậy, khi tôi nói một cái gì đó như s [3]; điều này là có s và đếm 3 ký tự. 655 00:55:05,360 --> 00:55:12,490 Vì vậy, s [3], chúng ta có 0, 1, 2, 3, nên s [3] sẽ tham khảo l này. 656 00:55:12,490 --> 00:55:20,460 [Sinh viên] Và chúng ta có thể đạt được cùng một giá trị bằng cách làm s + 3 và sau đó sao ngoặc? 657 00:55:20,460 --> 00:55:22,570 Vâng. 658 00:55:22,570 --> 00:55:26,010 Điều này tương đương với * (+ 3); 659 00:55:26,010 --> 00:55:31,240 và đó là mãi mãi và luôn luôn tương đương không có vấn đề gì bạn làm. 660 00:55:31,240 --> 00:55:34,070 Bạn không bao giờ cần sử dụng cú pháp khung. 661 00:55:34,070 --> 00:55:37,770 Bạn luôn có thể sử dụng * cú pháp (s + 3). 662 00:55:37,770 --> 00:55:40,180 Mọi người có xu hướng thích cú pháp khung, mặc dù. 663 00:55:40,180 --> 00:55:43,860 [Sinh viên] Vì vậy, tất cả các mảng thực sự chỉ là con trỏ. 664 00:55:43,860 --> 00:55:53,630 Có sự phân biệt nhẹ khi tôi nói int x [4]; [sinh viên] Điều đó tạo ra bộ nhớ? 665 00:55:53,630 --> 00:56:03,320 Bowden] Đó là để tạo ra 4 ints trên stack, do đó, 16 byte tổng thể. 666 00:56:03,320 --> 00:56:05,700 Nó sẽ tạo ra 16 bytes trên stack. 667 00:56:05,700 --> 00:56:09,190 x không được lưu trữ bất cứ nơi nào. 668 00:56:09,190 --> 00:56:13,420 Nó chỉ là một biểu tượng đề cập đến sự khởi đầu của điều này. 669 00:56:13,420 --> 00:56:17,680 Bởi vì bạn tuyên bố các mảng bên trong chức năng này, 670 00:56:17,680 --> 00:56:22,340 trình biên dịch sẽ làm là chỉ cần thay thế tất cả các trường hợp của biến x 671 00:56:22,340 --> 00:56:26,400 nơi nó xảy ra để lựa chọn để đưa những 16 byte. 672 00:56:26,400 --> 00:56:30,040 Nó không thể làm điều đó với char * s vì s là một con trỏ thực tế. 673 00:56:30,040 --> 00:56:32,380 Nó là miễn phí để sau đó trỏ đến những thứ khác. 674 00:56:32,380 --> 00:56:36,140 x là một hằng số. Bạn không thể có nó trỏ đến một mảng khác nhau. >> [Sinh viên] Okay. 675 00:56:36,140 --> 00:56:43,420 Tuy nhiên, ý tưởng này, lập chỉ mục, là như nhau bất kể cho dù đó là một mảng truyền thống 676 00:56:43,420 --> 00:56:48,230 hoặc nếu nó là một con trỏ đến một cái gì đó hoặc nếu đó là một con trỏ đến một mảng malloced. 677 00:56:48,230 --> 00:56:59,770 Và trên thực tế, nó là như vậy tương đương rằng đó cũng là điều tương tự. 678 00:56:59,770 --> 00:57:05,440 Nó thực sự chỉ dịch những gì bên trong các dấu ngoặc và những gì còn lại của khung, 679 00:57:05,440 --> 00:57:07,970 thêm chúng với nhau, và dereferences. 680 00:57:07,970 --> 00:57:14,710 Vì vậy, đây chỉ là giá trị như * (s + 3) hoặc s [3]. 681 00:57:16,210 --> 00:57:22,090 [Sinh viên] bạn có thể có con trỏ trỏ đến mảng 2-chiều? 682 00:57:22,090 --> 00:57:27,380 >> Đó là khó khăn hơn. Theo truyền thống, không. 683 00:57:27,380 --> 00:57:34,720 Một mảng 2-chiều chỉ là một mảng 1 chiều với một số cú pháp thuận tiện 684 00:57:34,720 --> 00:57:54,110 bởi vì khi tôi nói int x [3] [3], điều này thực sự chỉ là 1 mảng với 9 giá trị. 685 00:57:55,500 --> 00:58:03,000 Và như vậy khi tôi chỉ số, trình biên dịch biết những gì tôi có ý nghĩa. 686 00:58:03,000 --> 00:58:13,090 Nếu tôi nói x [1] [2], nó biết tôi muốn đi đến hàng thứ hai, do đó, nó sẽ bỏ qua người đầu tiên 3, 687 00:58:13,090 --> 00:58:17,460 và sau đó nó muốn điều thứ hai trong đó, do đó, nó sẽ nhận được một trong những điều này. 688 00:58:17,460 --> 00:58:20,480 Nhưng nó vẫn chỉ là một mảng một chiều. 689 00:58:20,480 --> 00:58:23,660 Và vì vậy nếu tôi muốn gán một con trỏ đến mảng đó, 690 00:58:23,660 --> 00:58:29,770 Tôi sẽ nói int * p = x; 691 00:58:29,770 --> 00:58:33,220 Các loại x chỉ là - 692 00:58:33,220 --> 00:58:38,280 Đó là kiểu nói thô của x vì nó chỉ là một biểu tượng và nó không phải là một biến thực tế, 693 00:58:38,280 --> 00:58:40,140 nhưng nó chỉ là một int *. 694 00:58:40,140 --> 00:58:44,840 x chỉ là một con trỏ đến sự bắt đầu của điều này. >> [Sinh viên] Okay. 695 00:58:44,840 --> 00:58:52,560 Và vì vậy tôi sẽ không thể truy cập [1] [2]. 696 00:58:52,560 --> 00:58:58,370 Tôi nghĩ rằng đó là cú pháp đặc biệt để khai báo một con trỏ, 697 00:58:58,370 --> 00:59:12,480 một cái gì đó vô lý như int (* p [- một cái gì đó hoàn toàn vô lý, tôi thậm chí không biết. 698 00:59:12,480 --> 00:59:17,090 Nhưng có một cú pháp để khai báo con trỏ như thế nào với các dấu ngoặc đơn và những thứ. 699 00:59:17,090 --> 00:59:22,960 Nó có thể không cho phép bạn làm điều đó. 700 00:59:22,960 --> 00:59:26,640 Tôi có thể nhìn lại một cái gì đó mà có thể cho tôi biết sự thật. 701 00:59:26,640 --> 00:59:34,160 Tôi sẽ xem xét cho nó sau này, nếu có một cú pháp cho điểm. Nhưng bạn sẽ không bao giờ nhìn thấy nó. 702 00:59:34,160 --> 00:59:39,670 Và ngay cả cú pháp như vậy là cổ xưa rằng nếu bạn sử dụng nó, mọi người sẽ bị bối rối. 703 00:59:39,670 --> 00:59:43,540 Mảng nhiều chiều là khá hiếm như nó được. 704 00:59:43,540 --> 00:59:44,630 Bạn có khá nhiều - 705 00:59:44,630 --> 00:59:48,490 Vâng, nếu bạn đang làm những việc ma trận nó sẽ không là hiếm, 706 00:59:48,490 --> 00:59:56,730 nhưng trong C, bạn hiếm khi sẽ được sử dụng các mảng đa chiều. 707 00:59:57,630 --> 01:00:00,470 Yeah. >> [Sinh viên] Hãy nói rằng bạn có một mảng thực sự dài. 708 01:00:00,470 --> 01:00:03,900 >> Vì vậy, trong bộ nhớ ảo, nó sẽ xuất hiện là tất cả các liên tiếp, 709 01:00:03,900 --> 01:00:05,640 giống như các yếu tố ngay bên cạnh nhau, 710 01:00:05,640 --> 01:00:08,770 nhưng trong bộ nhớ vật lý, nó sẽ có thể cho rằng để được chia? >>. 711 01:00:08,770 --> 01:00:16,860 Làm thế nào các công trình bộ nhớ ảo là nó chỉ tách - 712 01:00:19,220 --> 01:00:24,860 Các đơn vị phân bổ là một trang, mà có xu hướng là 4 kilobyte, 713 01:00:24,860 --> 01:00:29,680 và do đó, khi một quá trình nói, hey, tôi muốn sử dụng bộ nhớ này, 714 01:00:29,680 --> 01:00:35,970 hệ điều hành được phân bổ cho 4 kilobyte cho rằng khối ít bộ nhớ. 715 01:00:35,970 --> 01:00:39,100 Thậm chí nếu bạn chỉ sử dụng một ít byte duy nhất trong toàn bộ khối của bộ nhớ, 716 01:00:39,100 --> 01:00:42,850 hệ điều hành sẽ để cho nó đủ trong 4 kilobyte. 717 01:00:42,850 --> 01:00:49,410 Vì vậy, điều này có nghĩa là tôi có thể có - chúng ta hãy nói rằng đây là chồng của tôi. 718 01:00:49,410 --> 01:00:53,180 Ngăn xếp này có thể được tách ra. Ngăn xếp của tôi có thể là MB và MB. 719 01:00:53,180 --> 01:00:55,020 Ngăn xếp của tôi có thể là rất lớn. 720 01:00:55,020 --> 01:01:00,220 Nhưng ngăn xếp chính nó có thể được chia thành các trang cá nhân, 721 01:01:00,220 --> 01:01:09,010 nếu chúng ta nhìn ở đây chúng ta hãy nói rằng đây là bộ nhớ RAM của chúng tôi, 722 01:01:09,010 --> 01:01:16,600 nếu tôi có 2 GB RAM, đây là địa chỉ thực tế 0 như các byte 0 của bộ nhớ RAM của tôi, 723 01:01:16,600 --> 01:01:22,210 và đây là 2 GB tất cả các con đường xuống đây. 724 01:01:22,210 --> 01:01:27,230 Vì vậy, trang này có thể tương ứng với khối này ở đây. 725 01:01:27,230 --> 01:01:29,400 Trang này có thể tương ứng với khối này ở đây. 726 01:01:29,400 --> 01:01:31,560 Điều này có thể tương ứng này ở đây. 727 01:01:31,560 --> 01:01:35,540 Vì vậy, hệ điều hành là miễn phí để gán bộ nhớ vật lý 728 01:01:35,540 --> 01:01:39,320 bất kỳ trang cá nhân tùy tiện. 729 01:01:39,320 --> 01:01:46,180 Và điều đó có nghĩa là nếu biên giới này xảy ra với sự dang chân ra một mảng, 730 01:01:46,180 --> 01:01:50,070 một mảng xảy ra để được bên trái và bên phải của thứ tự của trang này, 731 01:01:50,070 --> 01:01:54,460 sau đó mà mảng sẽ được phân chia trong bộ nhớ vật lý. 732 01:01:54,460 --> 01:01:59,280 Và sau đó khi bạn thoát khỏi chương trình, khi quá trình này kết thúc, 733 01:01:59,280 --> 01:02:05,690 các ánh xạ này được xoá hoàn toàn và sau đó nó miễn phí để sử dụng các khối nhỏ cho những thứ khác. 734 01:02:14,730 --> 01:02:17,410 Câu hỏi nhiều hơn? 735 01:02:17,410 --> 01:02:19,960 [Sinh viên] con trỏ số học. >> Oh yeah. 736 01:02:19,960 --> 01:02:28,410 Dây dễ dàng hơn, nhưng nhìn vào một cái gì đó giống như ints, 737 01:02:28,410 --> 01:02:35,000 để trở lại int x [4]; 738 01:02:35,000 --> 01:02:41,810 Cho dù đây là một mảng hoặc cho dù đó là một con trỏ đến một mảng malloced của 4 số nguyên, 739 01:02:41,810 --> 01:02:47,060 nó sẽ được đối xử theo cùng một cách. 740 01:02:50,590 --> 01:02:53,340 [Sinh viên] Vì vậy, mảng là trên heap? 741 01:03:01,400 --> 01:03:05,270 Bowden] Mảng không phải là trên heap này. >> [Sinh viên] Oh. 742 01:03:05,270 --> 01:03:08,320 >> [Bowden] của mảng này có xu hướng được trên stack 743 01:03:08,320 --> 01:03:12,220 trừ khi bạn tuyên bố nó - bỏ qua các biến toàn cầu. Không sử dụng các biến toàn cầu. 744 01:03:12,220 --> 01:03:16,280 Bên trong của một chức năng tôi nói int x [4]; 745 01:03:16,280 --> 01:03:22,520 Nó sẽ tạo ra một khối 4 số nguyên trên stack cho mảng này. 746 01:03:22,520 --> 01:03:26,960 Nhưng điều này malloc (4 * sizeof (int)); sẽ đi trên heap. 747 01:03:26,960 --> 01:03:31,870 Tuy nhiên, sau thời điểm này, tôi có thể sử dụng x và p khá nhiều cùng một cách, 748 01:03:31,870 --> 01:03:36,140 khác với các trường hợp ngoại lệ tôi đã nói trước khi về, bạn có thể gán lại p. 749 01:03:36,140 --> 01:03:40,960 Về mặt kỹ thuật, kích thước của họ là hơi khác nhau, nhưng đó là hoàn toàn không liên quan. 750 01:03:40,960 --> 01:03:43,310 Bạn không bao giờ thực sự sử dụng kích thước của chúng. 751 01:03:48,020 --> 01:03:56,810 P tôi có thể nói p [3] = 2; x [3] = 2; 752 01:03:56,810 --> 01:03:59,680 Bạn có thể sử dụng chúng trong chính xác cùng một cách. 753 01:03:59,680 --> 01:04:01,570 Vì vậy, con trỏ số học bây giờ - Có. 754 01:04:01,570 --> 01:04:07,390 [Sinh viên] Bạn không cần phải làm p * nếu bạn có các dấu ngoặc? 755 01:04:07,390 --> 01:04:11,720 Ngoặc là một dereference ngầm. >> Okay. 756 01:04:11,720 --> 01:04:20,200 Trên thực tế, cũng là những gì bạn đang nói với các bạn có thể nhận được các mảng đa chiều 757 01:04:20,200 --> 01:05:02,650 với con trỏ, những gì bạn có thể làm là một cái gì đó như thế, chúng ta hãy nói, int ** pp = malloc (sizeof (int *) * 5); 758 01:05:02,650 --> 01:05:06,900 Tôi chỉ sẽ viết tất cả ra đầu tiên. 759 01:05:37,880 --> 01:05:41,020 Tôi không muốn điều đó. 760 01:05:41,020 --> 01:05:42,550 Okay. 761 01:05:42,550 --> 01:05:48,910 Những gì tôi đã làm ở đây là - Đó nên là pp [i]. 762 01:05:48,910 --> 01:05:53,680 Vì vậy, Trang là một con trỏ đến một con trỏ. 763 01:05:53,680 --> 01:06:02,420 Bạn đang mallocing Trang để trỏ đến một mảng trong 5 sao int. 764 01:06:02,420 --> 01:06:10,950 Vì vậy, trong bộ nhớ bạn có trên các trang ngăn xếp 765 01:06:10,950 --> 01:06:20,150 Nó sẽ để trỏ đến một mảng của 5 khối đó là tất cả bản thân con trỏ. 766 01:06:20,150 --> 01:06:28,210 Và sau đó khi tôi malloc xuống đây, tôi malloc rằng mỗi người trong số các con trỏ riêng biệt 767 01:06:28,210 --> 01:06:32,080 phải trỏ đến một khối riêng biệt của 4 byte trên heap. 768 01:06:32,080 --> 01:06:35,870 Vì vậy, điều này dẫn đến 4 byte. 769 01:06:37,940 --> 01:06:40,660 Và điều này một trong những điểm đến 4 byte khác nhau. 770 01:06:40,660 --> 01:06:43,200 >> Và tất cả chúng trỏ đến 4 byte của riêng của họ. 771 01:06:43,200 --> 01:06:49,080 Điều này mang lại cho tôi một cách để làm những việc đa chiều. 772 01:06:49,080 --> 01:06:58,030 Tôi có thể nói pp [3] [4], nhưng bây giờ điều này không phải là điều tương tự như các mảng đa chiều 773 01:06:58,030 --> 01:07:05,390 bởi vì các mảng đa chiều dịch [3] [4] vào một bù đắp vào mảng x. 774 01:07:05,390 --> 01:07:14,790 Này dereferences p, truy cập các chỉ số thứ ba, sau đó dereferences rằng 775 01:07:14,790 --> 01:07:20,790 và truy cập - 4 sẽ là không hợp lệ - chỉ số thứ hai. 776 01:07:24,770 --> 01:07:31,430 Trong khi đó, khi chúng tôi đã có int x [3] [4] trước khi một mảng đa chiều 777 01:07:31,430 --> 01:07:35,740 và khi bạn tăng gấp đôi khung nó thực sự chỉ là một dereference duy nhất, 778 01:07:35,740 --> 01:07:40,490 bạn đang theo dõi một con trỏ đơn và sau đó một bù đắp, 779 01:07:40,490 --> 01:07:42,850 đây thực sự là tài liệu tham khảo 2D. 780 01:07:42,850 --> 01:07:45,840 Bạn làm theo 2 con trỏ riêng biệt. 781 01:07:45,840 --> 01:07:50,420 Vì vậy, đây cũng là kỹ thuật cho phép bạn có các mảng đa chiều 782 01:07:50,420 --> 01:07:53,550 trong đó mỗi mảng cá nhân là kích cỡ khác nhau. 783 01:07:53,550 --> 01:07:58,000 Vì vậy, tôi nghĩ rằng mảng lởm chởm đa chiều là những gì nó được gọi là 784 01:07:58,000 --> 01:08:01,870 kể từ khi thực sự là điều đầu tiên có thể trỏ đến cái gì đó có 10 yếu tố, 785 01:08:01,870 --> 01:08:05,540 Điều thứ hai có thể trỏ đến cái gì đó có 100 phần tử. 786 01:08:05,540 --> 01:08:10,790 [Sinh viên] có bất kỳ giới hạn về số lượng của các con trỏ bạn có thể có 787 01:08:10,790 --> 01:08:14,290 chỉ cho con trỏ khác? >> Số 788 01:08:14,290 --> 01:08:17,010 Bạn có thể có int ***** p. 789 01:08:18,050 --> 01:08:23,760 Con trỏ số học - >> [sinh viên] Oh. >> Yeah. 790 01:08:23,760 --> 01:08:35,649 [Sinh viên] Nếu tôi có int *** p và sau đó tôi làm một dereferencing và tôi nói p * bằng giá trị này, 791 01:08:35,649 --> 01:08:39,560 là nó chỉ sẽ làm 1 mức độ dereferencing? >>. 792 01:08:39,560 --> 01:08:43,340 Vì vậy, nếu tôi muốn truy cập những điều mà con trỏ cuối cùng là chỉ vào - 793 01:08:43,340 --> 01:08:46,210 Sau đó, bạn làm p ***. >> Okay. 794 01:08:46,210 --> 01:08:54,080 Vì vậy, đây là điểm p để 1 block, điểm cho khối khác, các điểm cho khối khác. 795 01:08:54,080 --> 01:09:02,010 Sau đó, nếu bạn nào * p = cái gì khác, sau đó bạn đang thay đổi này 796 01:09:02,010 --> 01:09:13,640 bây giờ trỏ đến một khối khác nhau. >> Okay. 797 01:09:13,640 --> 01:09:17,649 >> [Bowden] Và nếu những malloced, sau đó bạn đã bị rò rỉ bộ nhớ 798 01:09:17,649 --> 01:09:20,430 trừ khi bạn xảy ra để có tài liệu tham khảo khác nhau của các 799 01:09:20,430 --> 01:09:25,270 vì bạn không thể có được trở lại với những những người mà bạn chỉ cần ném đi. 800 01:09:25,270 --> 01:09:29,550 Con trỏ số học. 801 01:09:29,550 --> 01:09:36,310 int x [4]; là sẽ cấp phát một mảng của 4 số nguyên 802 01:09:36,310 --> 01:09:40,670 trong đó x sẽ để trỏ đến đầu của mảng. 803 01:09:40,670 --> 01:09:50,420 Vì vậy, khi tôi nói một cái gì đó giống như x [1], tôi muốn nó có nghĩa là đi đến số nguyên thứ hai trong mảng, 804 01:09:50,420 --> 01:09:53,319 đó sẽ là một trong những điều này. 805 01:09:53,319 --> 01:10:04,190 Nhưng thực sự, đó là 4 byte vào mảng kể từ khi số nguyên này chiếm 4 byte. 806 01:10:04,190 --> 01:10:08,470 Vì vậy, một offset của 1 thực sự có nghĩa là một bù đắp của 1 807 01:10:08,470 --> 01:10:12,030 lần kích thước của bất cứ loại của mảng. 808 01:10:12,030 --> 01:10:17,170 Đây là một mảng các số nguyên, để nó biết làm 1 lần kích thước của int khi nó muốn để bù đắp. 809 01:10:17,170 --> 01:10:25,260 Cú pháp khác. Hãy nhớ rằng đây là tương đương với * (x + 1); 810 01:10:25,260 --> 01:10:35,250 Khi tôi nói con trỏ + 1, những gì mà trả về là địa chỉ mà con trỏ được lưu trữ 811 01:10:35,250 --> 01:10:40,360 cộng thêm 1 lần kích thước của các loại của con trỏ. 812 01:10:40,360 --> 01:10:59,510 Vì vậy, nếu x = ox100, sau đó x + 1 = ox104. 813 01:10:59,510 --> 01:11:19,750 Và bạn có thể lợi dụng điều này và nói điều gì đó như char * c = (char *) x; 814 01:11:19,750 --> 01:11:23,050 và bây giờ c là có được địa chỉ giống như x. 815 01:11:23,050 --> 01:11:26,040 c sẽ để được bằng ox100, 816 01:11:26,040 --> 01:11:31,490 nhưng c + 1 là có được bằng ox101 817 01:11:31,490 --> 01:11:38,030 kể từ khi con trỏ số học phụ thuộc vào kiểu của con trỏ mà bạn đang thêm. 818 01:11:38,030 --> 01:11:45,390 Vì vậy, c + 1, nó nhìn vào c, đó là một con trỏ char, vì vậy nó sẽ thêm 1 lần kích thước của char, 819 01:11:45,390 --> 01:11:48,110 mà luôn luôn có được 1, do đó, bạn sẽ có được 101, 820 01:11:48,110 --> 01:11:54,890 trong khi đó nếu tôi làm x, cũng vẫn còn 100, x + 1 sẽ là 104. 821 01:11:56,660 --> 01:12:06,340 [Sinh viên] Bạn có thể sử dụng c + + để tạm ứng con trỏ của bạn bằng 1? 822 01:12:06,340 --> 01:12:09,810 Có, bạn có thể. 823 01:12:09,810 --> 01:12:16,180 Bạn không thể làm điều đó với x vì x chỉ là một biểu tượng, nó là một hằng số, bạn không thể thay đổi x. 824 01:12:16,180 --> 01:12:22,610 >> Nhưng c xảy ra chỉ là một con trỏ, vì vậy c + + là hoàn toàn hợp lệ và nó sẽ tăng 1. 825 01:12:22,610 --> 01:12:32,440 Nếu c chỉ là một int *, sau đó c + + sẽ được 104. 826 01:12:32,440 --> 01:12:41,250 + + Con trỏ số học cũng giống như c + 1 sẽ phải thực hiện con trỏ số học. 827 01:12:43,000 --> 01:12:48,870 Điều này thực sự là rất nhiều những thứ như merge sort - 828 01:12:49,670 --> 01:12:55,710 Thay vì tạo ra các bản sao của sự vật, thay vào đó bạn có thể vượt qua - 829 01:12:55,710 --> 01:13:02,400 Cũng giống như nếu tôi muốn để vượt qua một nửa của mảng - hãy cho xóa một số điều này. 830 01:13:04,770 --> 01:13:10,520 Hãy nói rằng tôi muốn vượt qua bên này của mảng vào một chức năng. 831 01:13:10,520 --> 01:13:12,700 Những gì tôi sẽ vượt qua chức năng đó? 832 01:13:12,700 --> 01:13:17,050 Nếu tôi vượt qua x, tôi đi qua địa chỉ này. 833 01:13:17,050 --> 01:13:23,780 Nhưng tôi muốn vượt qua địa chỉ cụ thể này. Vì vậy, những gì tôi cần phải vượt qua? 834 01:13:23,780 --> 01:13:26,590 [Sinh viên] Pointer + 2? 835 01:13:26,590 --> 01:13:29,350 Bowden] Vì vậy x + 2. Vâng. 836 01:13:29,350 --> 01:13:31,620 Đó sẽ là địa chỉ này. 837 01:13:31,620 --> 01:13:42,810 Bạn cũng sẽ rất thường xuyên xem nó như là x [2] và sau đó địa chỉ đó. 838 01:13:42,810 --> 01:13:47,850 Vì vậy, bạn cần phải lấy địa chỉ của nó bởi vì khung là một dereference ngầm. 839 01:13:47,850 --> 01:13:53,250 x [2] đề cập đến giá trị trong hộp này, và sau đó bạn muốn địa chỉ của hộp đó, 840 01:13:53,250 --> 01:13:56,850 vì vậy bạn nói & x [2]. 841 01:13:56,850 --> 01:14:02,880 Vì vậy, đó là một cái gì đó như thế nào trong hợp nhất loại mà bạn muốn vượt qua một nửa danh sách để một cái gì đó 842 01:14:02,880 --> 01:14:08,790 bạn thực sự chỉ cần vượt qua & x [2], và bây giờ như xa như các cuộc gọi đệ quy là có liên quan, 843 01:14:08,790 --> 01:14:12,510 mảng mới của tôi bắt đầu có. 844 01:14:12,510 --> 01:14:15,130 Đến phút cuối của câu hỏi. 845 01:14:15,130 --> 01:14:20,050 [Sinh viên] Nếu chúng ta không đặt một dấu "và" hoặc một - đó là những gì được gọi là? >> Sao? 846 01:14:20,050 --> 01:14:23,200 [Sinh viên] Star. >> Mặt kỹ thuật, điều hành dereference, nhưng - >> [sinh viên] tham chiếu đến. 847 01:14:23,200 --> 01:14:29,310 >> Nếu chúng ta không đưa một ngôi sao hay một ký hiệu, những gì sẽ xảy ra nếu tôi chỉ nói y = x và x là một con trỏ? 848 01:14:29,310 --> 01:14:34,620 Loại của y là gì? >> [Sinh viên] tôi sẽ chỉ nói con trỏ nó 2. 849 01:14:34,620 --> 01:14:38,270 Vì vậy, nếu bạn chỉ cần nói y = x, bây giờ x và y điểm để điều tương tự. >> [Sinh viên] Point để điều tương tự. 850 01:14:38,270 --> 01:14:45,180 Và nếu x là một con trỏ int? >> Nó sẽ phàn nàn vì bạn không thể gán con trỏ. 851 01:14:45,180 --> 01:14:46,540 [Sinh viên] Okay. 852 01:14:46,540 --> 01:14:51,860 Hãy nhớ rằng con trỏ, mặc dù chúng ta vẽ chúng như là mũi tên, 853 01:14:51,860 --> 01:15:02,010 thực sự tất cả các cửa hàng họ - int * x - thực sự tất cả các x được lưu trữ là một cái gì đó giống như ox100, 854 01:15:02,010 --> 01:15:06,490 mà chúng xảy ra với đại diện là chỉ khối được lưu trữ ở 100. 855 01:15:06,490 --> 01:15:19,660 Vì vậy, khi tôi nói int * y = x; tôi chỉ cần sao chép ox100 vào y, 856 01:15:19,660 --> 01:15:24,630 mà chúng ta chỉ cần đi để đại diện cho y, cũng chỉ để ox100. 857 01:15:24,630 --> 01:15:39,810 Và nếu tôi nói int i = (int) x, sau đó tôi sẽ để lưu trữ bất cứ điều gì giá trị của ox100 858 01:15:39,810 --> 01:15:45,100 bên trong của nó, nhưng bây giờ nó sẽ được hiểu như là một số nguyên thay vì một con trỏ. 859 01:15:45,100 --> 01:15:49,310 Nhưng bạn cần các diễn viên hoặc người nào khác nó sẽ khiếu nại. 860 01:15:49,310 --> 01:15:53,300 [Sinh viên] Vì vậy, bạn có nghĩa là để cast - 861 01:15:53,300 --> 01:16:00,290 Là nó sẽ được đúc int int x hoặc đúc của y? 862 01:16:00,290 --> 01:16:03,700 [Bowden] gì? 863 01:16:03,700 --> 01:16:07,690 [Sinh viên] Okay. Sau khi các dấu ngoặc đơn là có sẽ là một x hoặc ay có? 864 01:16:07,690 --> 01:16:11,500 >> [Bowden] Hoặc. x và y là tương đương. >> [Sinh viên] Okay. 865 01:16:11,500 --> 01:16:14,390 Bởi vì họ là cả hai con trỏ. >> Yeah. 866 01:16:14,390 --> 01:16:21,050 [Sinh viên] Vì vậy, nó sẽ lưu trữ các hệ thập lục phân 100 ở dạng số nguyên? >> [Bowden] Yeah. 867 01:16:21,050 --> 01:16:23,620 Nhưng không phải là giá trị của bất cứ điều gì nó trỏ tới. 868 01:16:23,620 --> 01:16:29,940 [Bowden] Yeah. >> [Sinh viên] Vì vậy, chỉ cần địa chỉ ở dạng số nguyên. Okay. 869 01:16:29,940 --> 01:16:34,720 [Bowden] Nếu bạn muốn đối với một số lý do kỳ lạ, 870 01:16:34,720 --> 01:16:38,900 bạn hoàn toàn có thể đối phó với con trỏ và không bao giờ đối phó với số nguyên 871 01:16:38,900 --> 01:16:49,240 và chỉ cần như int * x = 0. 872 01:16:49,240 --> 01:16:53,000 Sau đó, bạn sẽ nhận được thực sự bối rối khi con trỏ số học bắt đầu xảy ra. 873 01:16:53,000 --> 01:16:56,570 Vì vậy, những con số mà họ lưu trữ là vô nghĩa. 874 01:16:56,570 --> 01:16:58,940 Đó chỉ là cách bạn kết thúc giải thích chúng. 875 01:16:58,940 --> 01:17:02,920 Vì vậy, tôi là miễn phí để sao chép ox100 từ một int * đến một int, 876 01:17:02,920 --> 01:17:07,790 và tôi là miễn phí để gán - phổ cập như có thể sẽ bị mắng không đúc - 877 01:17:07,790 --> 01:17:18,160 Tôi là miễn phí để chỉ định một cái gì đó giống như (int *) ox1234 vào int * tùy ý. 878 01:17:18,160 --> 01:17:25,480 Vì vậy, ox123 chỉ là một địa chỉ hợp lệ bộ nhớ như là & y. 879 01:17:25,480 --> 01:17:32,060 & Y xảy ra để trở về một cái gì đó là khá nhiều ox123. 880 01:17:32,060 --> 01:17:35,430 [Sinh viên] mà có thể là một cách thực sự mát mẻ để đi từ hệ thập lục phân dạng thập phân, 881 01:17:35,430 --> 01:17:39,230 giống như nếu bạn có một con trỏ và bạn cast nó như là một int? 882 01:17:39,230 --> 01:17:44,860 [Bowden] Bạn thực sự chỉ có thể in bằng cách sử dụng giống như printf. 883 01:17:44,860 --> 01:17:50,300 Hãy nói rằng tôi có int y = 100. 884 01:17:50,300 --> 01:18:02,700 Vì vậy, printf (% d \ n - như bạn đã nên biết - in rằng, cũng như một số nguyên, x%. 885 01:18:02,700 --> 01:18:05,190 Chúng tôi sẽ chỉ in nó như là hệ thập lục phân. 886 01:18:05,190 --> 01:18:10,760 Vì vậy, một con trỏ không được lưu trữ như hệ thập lục phân, 887 01:18:10,760 --> 01:18:12,960 và một số nguyên không được lưu trữ là số thập phân. 888 01:18:12,960 --> 01:18:14,700 Tất cả mọi thứ được lưu trữ như nhị phân. 889 01:18:14,700 --> 01:18:17,950 Nó chỉ là chúng ta có xu hướng hiển thị con trỏ như là hệ thập lục phân 890 01:18:17,950 --> 01:18:23,260 bởi vì chúng tôi nghĩ rằng những thứ trong các khối 4-byte, 891 01:18:23,260 --> 01:18:25,390 và địa chỉ bộ nhớ có xu hướng là quen thuộc. 892 01:18:25,390 --> 01:18:28,890 Chúng tôi đang như thế nào, nếu nó bắt đầu với bf, sau đó nó sẽ xảy ra trên stack. 893 01:18:28,890 --> 01:18:35,560 Vì vậy, nó chỉ là giải thích của chúng ta về con trỏ như là hệ thập lục phân. 894 01:18:35,560 --> 01:18:39,200 Okay. Bất kỳ câu hỏi cuối cùng? 895 01:18:39,200 --> 01:18:41,700 >> Tôi sẽ ở đây cho một chút sau khi nếu bạn có bất cứ điều gì khác. 896 01:18:41,700 --> 01:18:46,070 Và đó là kết thúc đó. 897 01:18:46,070 --> 01:18:48,360 >> [Sinh viên] Yay! [Vỗ tay] 898 01:18:51,440 --> 01:18:53,000 >> [CS50.TV]