[Powered by Google Translate] [Частина 4 - більш комфортною]
[Rob Боуден - Гарвардський університет]
[Це CS50. - CS50.TV]
У нас є тест завтра, у випадку, якщо ви, хлопці, не знаю, що.
Це в основному все, що ви могли бачити в класі або повинні були бачити в своєму класі.
Це включає в себе покажчики, навіть якщо вони зовсім недавно тема.
Ви повинні принаймні, зрозуміти високого рівня з них.
Все, що було перейшли в клас ви повинні розуміти, для вікторини.
Так що якщо у вас є питання по ним, ви можете задати їх зараз.
Але це буде дуже студента під керівництвом сесії, де ви, хлопці, задавати питання,
так що сподіваюся, людям є питання.
У кого-небудь є питання?
Так. >> [Студент] Чи можете ви перейти на покажчики знову?
Я піду за покажчиками.
Всі ваші змінні обов'язково жити в пам'яті,
але зазвичай ви не хвилюйтеся про це, і ви просто говорите х + 2, у + 3
і компілятор буде з'ясувати, де живуть речі для вас.
Коли ви маєте справу з покажчиками, тепер ви явно за допомогою цих адрес пам'яті.
Таким чином, однією змінною буде тільки коли жити за однією адресою в будь-який момент часу.
Якщо ми хочемо оголосити покажчик, те, що тип буде виглядати?
>> Я хочу оголосити покажчик р. Що ж типу виглядають?
[Студент] Int * р. >> Да. Так Int * р.
А як зробити, щоб вона вказувала на х? >> [Студент] Ampersand.
[Боуден] Так амперсанд буквально називається адресу оператора.
Тому, коли я кажу, і х він стає адресу пам'яті змінної х.
Так що тепер у мене є покажчик р, і в будь-якому місці в моєму коді я можу використовувати * р
або я міг би використовувати х, і це буде одне і те ж.
(* Р). Що це робиш? Що означає, що зірка на увазі?
[Студент] Це означає значення в цій точці. >> Да.
Так, якщо ми дивимося на нього, він може бути дуже корисно, щоб витягнути діаграм
де це маленька коробочка пам'яті для х, в якому є значення 4,
Потім у нас є маленька коробочка пам'яті для р,
і так з точки х, так що ми малюємо стрілку від р х.
Тому коли ми говоримо * р ми говоримо піти у вікно, р.
Зірка слідуйте за стрілкою, а потім робити все, що ви хочете з цією коробці прямо там.
Тому я можу сказати * р = 7, і що піде на ящик, який є х і зміни, які до 7.
Або я міг би сказати Int г = * р * 2; Це помилка, тому що це зірка, зірка.
Одна зірка разименованія р, інша зірка множенням на 2.
Зверніть увагу, я міг би з таким же успіхом замінили * р з х.
Ви можете використовувати їх таким же чином.
А потім на мене може бути з точки на абсолютно нову річ.
Я можу тільки сказати, р = &z;
Так що тепер P більше не вказує на х; він вказує на р.
І в будь-який час я * р це так само, як робив р.
Таким чином, корисна річ про це як тільки ми починаємо отримувати по функціях.
>> Це свого роду даремні оголосити покажчик, який вказує на те,
а потім ви просто разименованія його
коли ви могли б використовувати оригінальний змінну з самого початку.
Але коли ви отримуєте в функції - так скажемо, у нас є деякі функції, внутр Фу,
, Яка приймає покажчик і просто робить * р = 6;
Як ми бачили раніше з підкачки, ви не можете зробити ефективний обмін і окремі функції
від просто проходили цілі тому що всі в C завжди проходять за значенням.
Навіть тоді, коли ви передаєте покажчик ви передаєте по значенню.
Просто так вийшло, що ці значення адрес пам'яті.
Тому коли я кажу Foo (р); я передаю покажчик у функції Foo
, А потім Foo робить * р = 6;
Таким чином, усередині цієї функції, * р і раніше еквівалентно х,
але я не можу використовувати х усередині цієї функції, тому що це не областю в цій функції.
Так * р = 6 є єдиним способом я можу отримати доступ з локальної змінної іншу функцію.
Або, добре, покажчики є єдиним способом я можу отримати доступ до локальної змінної з іншої функції.
[Студент] Припустимо, ви хотіли повертати покажчик. Як саме ви це зробили?
[Боуден] Повертає покажчик, як в щось на зразок Int у = 3; повернення & Y? >> [Студент] Так.
[Боуден] Добре. Ви ніколи не повинні це робити. Це погано.
Я думаю, що я бачив у ці лекції слайди ви почали бачити всю цю схему пам'яті
де тут у вас є пам'ять адреса 0
і тут у вас є адреса пам'яті, 4 гігабайтами або від 2 до 32.
Таким чином, то у вас є деякі речі і деякі речі, а потім у вас є свій стек
і у вас є ваша купа, яку ви тільки почали вивчення, зростає.
[Студент] не є купою над стеком?
>> Так. Купа знаходиться на вершині, чи не так? >> [Студент] Ну, він поставив 0 на вершині.
[Студент] О, він поставив 0 на вершині. >> [Студент] О, все в порядку.
Відмова від відповідальності: Anywhere з CS50 ви побачите його таким чином. >> [Студент] Добре.
Це тільки, що, коли ви вперше побачивши стеки,
подобається, коли ви думаєте про стек ви думаєте укладання речей один на одного.
Таким чином, ми, як правило, щоб перегорнути цю навколо так стек росте вгору, як це зазвичай стек
замість того, щоб стік висить вниз. >> [Студент] Не купи технічно рости занадто, правда?
Це залежить від того, що ви розумієте під рости.
Стека і купи завжди зростають у протилежному напрямку.
Стек завжди ростуть в тому сенсі, що воно росте
до більш високих адресах пам'яті, і купа росте вниз
в тому, що він росте в бік менших адрес пам'яті.
Таким чином, верхній дорівнює 0, а нижній є висока адрес пам'яті.
Вони обидва росте, тільки в протилежних напрямках.
[Студент] Я просто мав на увазі, що, оскільки ви сказали, поклав стек на дно
бо здається більш інтуїтивним, оскільки для стека для запуску у верхній частині купи,
купа знаходиться на вершині самого теж, так що that's - >> Да.
Ви також думати про купу, як ростуть і більше, але в стеці більше.
Таким чином, стек є той, який ми як би хочуть показати ростуть.
Але куди не глянь в іншому випадку покаже адреса 0 у верхньому
і найвищий адресу пам'яті в нижній, так що це звичайний вид пам'яті.
>> У вас є питання?
[Студент] Чи можете ви розповісти нам більше про купу?
Так. Я повернуся до цього в секунду.
По-перше, повертаючись до повернення і чому у погана річ,
в стеку у вас є купа кадрів стека, які представляють всі функції
які були названі.
Таким чином, ігноруючи попередні речі, у верхній частині стека завжди буде головною функцією
так як це перша функція, яка викликається.
А потім, коли ви дзвоните іншу функцію, стек буде рости вниз.
Так що, якщо я називаю деякі функції, Foo, і він отримує власний фрейм стеку,
він може викликати деякі функції, бар, він отримує власний фрейм стеку.
І бар може бути рекурсивною, і це може викликати саму себе,
і так, що другий виклик барі збирається отримати свій фрейм стеку.
І тому те, що відбувається в цих кадрів стека є всі локальні змінні
і всі аргументи функції, що -
Будь-які речі, які мають локальну область дії цієї функції перейдіть у цих кадрів стека.
Таким чином, це означає, що, коли я сказав щось на кшталт бару є функцією,
Я просто хочу, щоб оголосити ціле, а потім повертає покажчик на це число.
Так де ж у живете?
[Студент] у живе в барі. >> [Боуден] Так.
Десь в цьому маленькому квадраті пам'яті квадратних Літтлер, який має у в ньому.
Коли я повернуся, і у, я повертаю покажчик на цей невеликий блок пам'яті.
Але потім, коли функція повертається, його стек отримує стека.
І саме тому вона називається стеком.
Це як структури даних стека, якщо ви знаєте, що це таке.
Або навіть як стек лотків завжди, наприклад,
Основними збирається піти на дно, то перша функція ви дзвоните збирається піти на вершині, що,
і ви не можете повернутися на головну, поки не повернетеся зі всіх функцій, які були покликані
, Які були розміщені на ньому.
>> [Студент] Так що якщо ви робили повернутися і у, що вартість може бути змінена без попереднього повідомлення.
Так, it's - >> [студент] Це може бути переписана. >> Да.
Це повністю - Якщо ви спробуєте -
Це також було б Int бар *, тому що це повертає покажчик,
так що його повернення типу Int *.
Якщо ви спробуєте використовувати повернене значення цієї функції, це невизначене поведінку
тому що покажчик вказує на погану пам'ять. >> [Студент] Добре.
Так що, якщо, наприклад, ви заявили Int * у = Танос (SizeOf (INT))?
Так-то краще. Так.
[Студент] Ми говорили про те, коли ми перетягнути речі в наші кошики
вони насправді не стираються, ми просто втрачають свої покажчики.
Тому в даному випадку ми насправді видалити значення або це ще там, у пам'яті?
Здебільшого, це буде ще буде там.
Але, припустимо, ми, трапляється, називають деякі інші функції, Баз.
База збирається отримати свій фрейм стеку тут.
Це буде перезаписувати всі ці речі,
, А потім, якщо ви пізніше спробувати використовувати покажчик, який ви отримали раніше,
це не буде те ж значення.
Це буде змінилися тільки тому, що ви викликали функцію Баз.
[Студент] Але якщо б ми не, ми б досі отримати 3?
[Боуден] По всій імовірності, ви б.
Але ви не можете покладатися на це. C просто говорить невизначений поведінку.
>> [Студент] О, це так. Добре.
Отже, коли ви хочете повернути покажчик, це де Танос приходить у використанні.
Я пишу насправді просто повернути Танос (3 * SizeOf (INT)).
Ми пройдемося по Танос ще в секунду, але ідея Танос це все локальні змінні
завжди йдуть в стек.
Нічого, що malloced йде по купі, і він буде вічно і завжди бути в купі
поки ви явно звільнити його.
Таким чином, це означає, що коли ви Танос щось, вона збирається вижити після повернення з функції.
[Студент] Чи буде вона вижити після того, як програма зупиняється? >> Ні.
Гаразд, так що це буде там, поки програма повністю не зробив роботу. >> Да.
Ми можемо піти на деталі того, що відбувається, коли програма зупиняється.
Вам може знадобитися, щоб нагадати мені, але це окрема річ цілком.
[Студент] Так Танос створює покажчик? >> Да.
Malloc - >> [студент] Я думаю, що Танос позначає блок пам'яті, який можна використовувати в якості покажчика.
[Боуден] Я хочу, щоб схема знову. >> [Студент] Таким чином, ця функція працює, правда?
[Студент] Так, Танос позначає блок пам'яті, який можна використовувати,
а потім повертає адресу першого блоку цієї пам'яті.
>> [Боуден] Так. Отже, коли ви Танос, ви захоплення деяких блок пам'яті
що в даний час в купі.
Якщо купа занадто мало, то купа всього буде рости, і воно росте в цьому напрямку.
Так скажімо, купа занадто мала.
Тоді мова йде про рости трохи, і повертає покажчик на цей блок тільки росла.
Коли Ви безкоштовно речі, ви робите більше місця в купі,
так, то пізніше подзвонити в Танос може використовувати цю пам'ять, що раніше ви вже звільнені.
Головне про Танос і безкоштовно, що вона дає вам повний контроль
протягом терміну служби цих блоків пам'яті.
Глобальні змінні завжди жива.
Локальні змінні живі в межах своєї компетенції.
Як тільки ви йдете повз фігурною дужкою, локальні змінні мертві.
Malloced пам'ять жива, коли ви хочете, щоб він живий
, А потім вивільняється, коли ви сказати, що це повинен бути звільнений.
Ті, насправді є тільки 3 типів пам'яті, насправді.
Там в автоматичне керування пам'яттю, яка є стек.
Все відбувається автоматично.
Коли ви говорите Int х, пам'яті виділяється для внутр х.
При х виходить з області видимості, пам'ять буде утилізований для х.
Тоді є динамічне управління пам'яттю, що і Танос є,
який є, коли у вас є контроль.
Ви динамічно вирішити, коли пам'ять повинна і не повинна бути виділена.
А тут ще статичні, який просто означає, що він живе вічно,
що і глобальні змінні.
Вони просто завжди в пам'яті.
>> Питання?
[Студент] Чи можете ви визначити блок тільки за допомогою фігурних дужок
але не того, щоб мати, якщо заяву або заяву під час або щось в цьому роді?
Ви можете визначити блок, як у функції, але це не має фігурні дужки теж.
[Студент] Таким чином, ви не можете просто як випадкові пара фігурних дужок в коді
, Які мають локальні змінні? >> Так, можна.
Усередині Int барі ми могли б мати {INT у = 3;}.
Це повинно бути тут.
Але це повністю визначає сферу Int у.
Після того, що другий фігурною дужкою, у не може бути використана більше.
Ви майже ніколи не роблять цього, хоча.
Повертаючись до того, що відбувається, коли програма закінчується,
там ніби оману / половина брехня, що ми даємо для того, щоб просто зробити речі простіше.
Ми говоримо вам, що, коли ви виділити пам'ять
Ви виділенні деяких шматок оперативної пам'яті для цієї змінної.
Але ви дійсно не торкаючись безпосередньо RAM все у ваших програмах.
Якщо ви думаєте про це, як я намалював -
А насправді, якщо ви проходите в GDB ви побачите те ж саме.
Незалежно від того, скільки разів ви запустите програму або якою програмою ви працюєте,
Стек завжди збирається почати -
Ви завжди побачите змінні навколо адресу щось oxbffff.
Це, як правило, десь в цьому регіоні.
Але як 2 програми можливо мати покажчики на ту ж пам'ять?
[Студент] Там деякі довільні позначення, де oxbfff повинна бути на RAM
які дійсно можуть знаходитися в різних місцях, в залежності від того, коли функція була викликана.
Так. Цей термін є віртуальної пам'яті.
Ідея полягає в тому, що кожен процес, кожна програма, яка працює на вашому комп'ютері
має свою власну - припустимо, 32 біт - повністю незалежна адресного простору.
Це адресний простір.
Він має свій власний повністю незалежними 4 гігабайти у використанні.
>> Так що якщо ви запустите 2 програми одночасно, ця програма бачить 4 гігабайти до себе,
ця програма бачить 4 гігабайти до себе,
і неможливо для цієї програми разименовать покажчик
і в підсумку пам'яті з цієї програми.
І те, що віртуальна пам'ять є відображенням з адресного простору процесу
фактичних речей на пам'ять.
Так що до вашій операційній системі знати, що,
агов, коли цей покажчик хлопець разименовивает oxbfff, що насправді означає
що він хоче байт RAM 1000,
а якщо це oxbfff програми разименовивает, що він дійсно хоче байт RAM 10000.
Вони можуть бути як завгодно далеко один від одного.
Це вірно навіть речі в одному адресному просторі процесу.
Так як він бачить всі 4 гігабайти до себе, але, скажімо -
[Студент] Чи кожен процес -
Скажімо, у вас є комп'ютер з 4 гігабайтами оперативної пам'яті.
Чи має кожен процес побачити цілих 4 гігабайти? >> Да.
Але 4 гігабайти він бачить це брехня.
Це просто він думає, що все це має пам'яті, тому що він не знає, і будь-який інший процес існує.
Він буде використовувати тільки стільки пам'яті, скільки насправді потрібно.
Операційна система не дасть RAM в цей процес
якщо він не використовує пам'ять у всій цій області.
Це не збираюся дати йому пам'ять для цього регіону.
Але ідея в тому, що - я намагаюся думати - я не можу думати про аналогія.
Аналогії важко.
Одне з питань, віртуальної пам'яті, або одна з речей, це рішення
є те, що процеси повинні бути в повному невіданні один від одного.
І таким чином, ви можете написати будь-яку програму, яка просто разименовивает будь покажчик,
хотів просто написати програму, яка говорить * (ox1234),
і це разименованія адресу пам'яті 1234.
>> Але це до операційної системи, щоб потім перевести те, що 1234 кошти.
Так, якщо 1234 виявиться дійсну адресу пам'яті для цього процесу,
як він в стек або щось, то це буде повертати значення даного адреси пам'яті
Що стосується процесу знає.
Але якщо 1234 не є дійсною адресою, як це відбувається на землю
У деяких маленький шматочок пам'яті тут, що виходить за межі стека і купи
і ви дійсно не використовували це, то що, коли ви отримуєте щось на зразок сегментації
тому що ти торкаєшся пам'яті, які ви не повинні стосуватися.
Це також вірно -
32-бітова система, 32 біт означає, що у вас є 32 біта для визначення адреси пам'яті.
Ось чому покажчиків 8 байт, оскільки 32 біт 8 байт - або 4 байт.
Покажчики 4 байт.
Тому, коли ви бачите покажчик, як oxbfffff, тобто -
У будь даної програми ви можете просто побудувати будь-який довільний покажчик,
в будь-якому місці від Ох0 ОХ 8 f's - FFFFFFFF.
[Студент] Хіба ви не кажете, що вони 4 байти? >> Да.
[Студент] Тоді кожен байт буде - >> [Боуден] Шістнадцяткові.
Шістнадцяткові - 5, 6, 7, 8. Так покажчиків ви будете завжди бачити в шістнадцятковому вигляді.
Це просто, як ми класифікуємо покажчиків.
Кожні 2 цифри шістнадцятковій 1 байт.
Так що це буде 8 шістнадцятирічних цифр на 4 байти.
Таким чином, кожен покажчик на 32-бітної системі буде 4 байти,
Це означає, що у вашому процесі можна побудувати будь-який довільний 4 байти
і зробити покажчик з нього,
Це означає, що, наскільки він знає, він може звернутися ціла 2 до 32 байт пам'яті.
Навіть якщо це насправді не мають доступу до цієї,
навіть якщо ваш комп'ютер має тільки 512 мегабайт, він думає, що він має багато пам'яті.
І операційна система досить розумна, що вона буде тільки виділити те, що вам дійсно потрібно.
Це не просто йти, ой, новий процес: 4 концертів.
>> Так. >> [Студент] Що бик значить? Чому ви пишете?
Це просто символ шістнадцятковій.
Коли ви бачите номер починається з бика, послідовні речі шістнадцяткове.
[Студент] Ви були пояснити, що відбувається, коли програма закінчується. >> Да.
Що відбувається, коли програма закінчується являє собою операційну систему
просто стирає відображень, що вона має для цих адрес, ось і все.
В якості операційної системи тепер можна просто дати, що пам'ять у іншій програмі використовувати.
[Студент] Добре.
Отже, коли ви виділити щось у купі або в стеці або глобальні змінні або що-небудь,
всі вони просто зникають, як тільки програма закінчується
, Оскільки операційна система тепер може дати, що пам'ять для будь-якого іншого процесу.
[Студент] Навіть якщо Є, ймовірно, ще значення написані на? >> Да.
Значення, ймовірно, все ще там.
Це просто, що це буде важко отримати на них.
Це набагато важче отримати на них, ніж це, щоб дістатися до віддалених файлів
тому що віддалений файл виду сидить там протягом довгого часу і жорсткого диска набагато більше.
Таким чином, він збирається переписати різних частинах пам'яті
перш ніж це відбудеться, щоб замінити шматок пам'яті, що файл, використовуваний щоб бути в.
Але основний пам'яті, RAM, ви циклу через багато швидше,
так що це буде дуже швидко будуть перезаписані.
Питання на цю або щось ще?
[Студент] У мене є питання про іншої теми. >> Добре.
Хто-небудь є питання з цього приводу?
>> Добре. Різні теми. >> [Студент] Добре.
Я йшов через деякі практичні тести,
і в одній з них він говорив про SizeOf
і значення, яке вона повертає або різних типів змінних. >> Да.
І він сказав, що обидва Int і довго, як повернення 4, так що вони обидва 4 байти.
Чи є різниця між Int і довго, або це одне і те ж?
Так, є різниця.
C стандарт -
Я, ймовірно, буде безлад.
C стандарт просто подобається те, що C є офіційна документація C.
Це те, що він говорить.
Таким чином, C стандартна просто говорить, що символ буде вічно і завжди буде 1 байт.
Все, після цього - короткий завжди просто визначити як більше або дорівнює символ.
Це може бути строго більше, але не позитивно.
Int просто визначається як більше або дорівнює короткий.
І довго просто визначається як більшу або рівну Int.
І довго довго, більше або дорівнює довго.
Так що єдине, C стандарт визначає відносний порядок у всьому.
Фактичний обсяг пам'яті, що речі займають, як правило, до реалізації,
але він дуже добре визначена в цій точці. >> [Студент] Добре.
Таким чином, шорти майже завжди буде 2 байти.
Ints майже завжди буде 4 байт.
Довгі довгі, майже завжди буде 8 байт.
І мріє, це залежить від того, чи використовується 32-бітні або 64-бітові системи.
Так довго буде відповідати типу системи.
Якщо ви використовуєте 32-розрядну систему, як Appliance, це буде 4 байт.
Якщо ви використовуєте 64-розрядну, як багато останніх комп'ютерах, це буде 8 байт.
>> Ints майже завжди 4 байти в цій точці.
Довгі довгі, майже завжди 8 байт.
У минулому цілі використані тільки бути 2 байти.
Але зверніть увагу, що це повністю задовольняє всі ці стосунки більше і дорівнює.
До тих пір, прекрасно дозволено бути такого ж розміру, як ціле,
і це також дозволено мати той же розмір, як довго довго.
І так вже трапляється, що в 99,999% систем, буде рівна
або Int або довгий довго. Це залежить тільки від 32-бітної або 64-бітної. >> [Студент] Добре.
У поплавці, яким десяткової крапки, позначеної в плані біт?
Ніби як бінарний? >> Да.
Вам не потрібно знати, що для CS50.
Ви навіть не дізнаєтеся, що в 61.
Ви не дізнаєтеся, що дійсно в будь-який курс.
Це просто уявлення.
Я забув точне наділи небагато.
Ідея з плаваючою точкою є те, що ви виділити певну кількість біт для представлення -
В принципі, все в науковій нотації.
Таким чином, ви виділити певну кількість біт для представлення самого числа, як і 1.2345.
Я ніколи не можуть представляти числа із більш ніж 5 цифр.
Після цього ви також виділити певну кількість бітів, так що він прагне бути схожим на
Ви можете йти тільки до певного числа, як і найбільший показника ви можете мати,
і ви можете йти тільки до певного показника,
як це найменший показник ви можете мати.
>> Я не пам'ятаю точно біти шляху призначаються на всі ці цінності,
але певна кількість бітів присвячений 1.2345,
інший певну кількість бітів призначені для експоненти,
і це тільки можна уявити показником певного розміру.
[Студент] і подвійний? Хіба що, як і подовжені поплавок? >> Да.
Це те ж саме, як поплавок тільки тепер ви використовуєте 8 байт замість 4 байт.
Тепер ви зможете використовувати 9 цифр або 10 цифр,
і це буде в змозі піти до 300 замість 100. >> [Студент] Добре.
І поплавки також 4 байти. >> Да.
Ну, знову ж таки, це, ймовірно, залежить в цілому на загальну реалізацію,
але поплавці 4 байти, двомісні є 8.
Парний називаються подвійними, тому що вони в два рази поплавців.
[Студент] Добре. І є подвійне подвоює? >> Є не так.
Я думаю - >> [студент] Як довго тужить? >> Да. Не думаю. Так.
[Студент] На тесті у минулому році там було питання про основну функції
того, щоб бути частиною вашої програми.
Відповідь була, що вона не повинна бути частиною вашої програми.
В якій ситуації? Це те, що я бачив.
[Боуден] Здається - >> [студент] Яка ситуація?
Чи є у вас проблеми? >> [Студент] Так, я можу виразно потягніть його вгору.
Це не повинні бути технічно, але в основному це буде.
[Студент] Я бачив одного на інший рік.
Це було схоже Вірно чи ні: дійсно - >> О, з файлом.?
. [Студент] Будь С файл повинен мати - [як каже відразу - нерозбірливо]
Добре. Так от окремо.
>> . C файл, просто повинен містити функцій.
Ви можете скомпілювати файл в машинний код, двійковий, що завгодно,
без його виконуваним ще немає.
Дійсний виконуваний файл повинен мати основну функцію.
Ви можете написати 100 функцій в 1 файл, але не основна
, А потім скомпілювати, що аж до двійковий,
Потім ви пишете інший файл, який має тільки головною, але вона викликає купу цих функцій
У цей двійковий файл тут.
І тому, коли ви робите виконуваний файл, ось що робить компонувальник
воно поєднує в собі ці 2 двійкових файлів у виконуваний файл.
Так. У файлі не повинно бути основною функцією на всіх.
І на великих базах коду ви побачите тисячі. Файли з і 1 головний файл.
Ще питання?
[Студент] Існував ще одне питання.
Він сказав, зробити це компілятор. Правда чи Брехня?
І відповідь була помилковою, і я зрозумів, чому це не так, як Clang.
Але те, що ми називаємо зробити, якщо це не так?
Зробити це в основному просто - я бачу саме те, що він це називає.
Але це тільки виконує команди.
Зробити.
Я можу потягнути це. Так.
О, так. Переконайтеся також, що робить.
Це говорить про мету марку утиліта для автоматичного визначення
які частини великої програми повинні бути перекомпілювати
і видає команди потрібні для.
Ви можете зробити файли, які є абсолютно величезне.
Зробити дивиться на штампи часу файлів і, як ми вже говорили,
Ви можете зібрати окремі файли вниз, і це не поки не дійдете до компонувальник
що вони зібрали в виконуваний файл.
Так що якщо у вас є 10 різних файлів, і ви внести зміни в 1 з них,
те, що робить збирається зробити, це просто перекомпиляция, що 1 файл
, А потім повторно зв'язати всі разом.
Але набагато тупіше, ніж це.
Це до вас, щоб повністю визначити, що це те, що він повинен робити.
Це за замовчуванням має здатність розпізнавати цей матеріал штамп часу,
але ви можете написати зробити файл нічого робити.
Ви можете написати зробити файл, так що, коли ви вводите зробити це тільки компакт-диски в інший каталог.
Я розчаровані, тому що я треку усередині всі мої Appliance
а потім переглянути PDF з Mac.
>> Так що я йду в Finder, і я можу дійсно йдете, підключитися до сервера,
і сервер підключитися до моє Appliance, а потім я відкриваю PDF
, Який отримує складений LaTeX.
Але мене спіткало розчарування, тому що кожного разу, коли мені потрібно, щоб оновити PDF,
Мені довелося скопіювати його в певний каталог, що він може отримати доступ до
і це ставало дратує.
Так що замість цього я написав зробити файл, який ви повинні визначити, як він робить речі.
Як ви робите в цей PDF LaTeX.
Так само, як і будь-який інший файл марки - або я думаю, ви ще не бачили марку файлів,
але у нас є в прилад файл глобальних марки, які просто говорить:
якщо ви компілюєте файл C, використовуйте Clang.
І ось тут, в моїй зробити файл, що я роблю я кажу,
Цей файл ви збираєтеся хочете зібрати з PDF LaTeX.
І таким чином, це PDF LaTeX, що робить компіляцію.
Зробити це не компіляція. Це просто виконання наступних команд в послідовності я вказав.
Таким чином, вона працює PDF LaTeX, він копіює його в каталог, я хочу, щоб бути скопійована,
це компакт-дисків в каталозі і робить інші речі,
але все вона робить, це визнають при зміні файлу,
і якщо він змінюється, то вона буде працювати командами, які він повинен виконати
При зміні файлу. >> [Студент] Добре.
Я не знаю, де глобальні файли зробити для мене, щоб перевірити його.
Інші питання? Все, починаючи від минулих тестів? Будь покажчик речі?
Є тонкі речі з покажчиками, як -
Я не збираюся бути в змозі знайти питання вікторини на ньому -
але, як і такого роду речі.
Переконайтеся, що ви розумієте, що, коли я говорю Int * х * у -
Це не зовсім тут нічого, я думаю.
Але, як і * х * у, ті 2 змінні, які знаходяться на стеку.
Коли я кажу, х = Танос (SizeOf (INT)), х і раніше змінної в стек,
Танос деякий блок більш в купу, і ми має точки х до купи.
>> Так щось в стек вказує на купу.
Всякий раз, коли ви Танос небудь, ви неминуче зберігати його всередині миші.
Так що покажчик на стек, malloced блоку в купі.
Багато людей плутають і говорять Int * х = Танос; х в купу.
Кількість х Що вказує на це в купу.
х сама перебуває в стеку, якщо з якихось причин ви х глобальної змінної,
У цьому випадку він опиняється в іншій області пам'яті.
Таким чином відстежувати ці коробки і стрілочні діаграми є досить загальними для вікторини.
Або, якщо це не тест на 0, це буде на тест 1.
Ви повинні знати все це, кроки в складанні
так як ви повинні були відповісти на запитання на них. Так.
[Студент] Чи можемо ми піти на ці кроки - >> Звичайно.
Перед кроків і складання нас є попередня обробка,
компіляції, збирання та компонування.
Попередня обробка. Що ж це зробити?
Це найпростіший крок у - добре, не подобається -
це не означає, повинно бути очевидним, але це найпростіший крок.
Ви, хлопці могли реалізувати себе. Так.
[Студент] Візьміть те, що у вас є у вашій включає в себе, як це і копіює, а потім і визначає.
Він шукає речі, як # # включають в себе і визначити,
і він просто копіює і вставляє те, що ті насправді означає.
Тому, коли ви говорите # включити cs50.h, препроцесор копіювання і вставки cs50.h
в цій лінії.
Коли ви говорите: # визначити х рівним 4, препроцесор проходить через всю програму
і замінює всі екземпляри х з 4.
Таким чином, препроцесор приймає правильний файл C і видає правильний файл C
, Де речі були скопійовані.
Так що тепер компіляції. Що ж це зробити?
[Студент] Це йде від C в двійковий формат.
>> [Боуден] Це не пройти весь шлях в двійковий формат.
[Студент] в машинний код то? >> Це не машинний код.
[Студент] Асамблеї? >> Асамблеї.
Це йде в Асамблеї перш ніж він йде всю дорогу в код C,
і більшість мов зробити щось на зразок цього.
Виберіть будь мова високого рівня, і якщо ви збираєтеся компілювати його,
це, ймовірно, зібрати в кроках.
Спочатку він збирається скласти Python в C, то це буде для компіляції C Асамблеї,
, А потім Асамблея збирається отримати переклад в двійкову.
Таким чином, складання збирається вивести його з C Асамблеї.
Слово компіляції зазвичай означає приведення його від більш високого рівня
в нижній мова програмування високого рівня.
Так що це тільки крок в компіляції, де ви починаєте з мови високого рівня
і в кінцевому підсумку в мову низького рівня, і тому крок називається компіляцією.
[Студент] Під час компіляції, давайте скажемо, що ви зробили # включити cs50.h.
Чи буде перекомпілювати компілятор cs50.h, як і функції, які там,
, І перевести це в асемблерний код, а також,
або це скопіювати і вставити те, що було попередньо збори?
cs50.h буде майже ніколи не виявляються в Асамблеї.
Речі, як прототипи функцій і речей для вас бути обережними.
Це гарантує, що компілятор може перевірити такі речі, як ви викликаєте функції
з правом типи повернення і правильні аргументи та інше.
>> Так cs50.h буде попередню обробку в файл, а потім, коли це компіляція
це в основному викидаються після того, як переконується, що все, що називають правильно.
Але функції, визначені в CS50 бібліотеки, які є окремими від cs50.h,
тих, хто не буде складена окремо.
Що буде насправді спуститися в стадії компонування, тому ми повернемося до цього в секунду.
Але, по-перше, те, що збірка?
[Студент] асамблеї в двійкову? >> Да.
Збірка.
Ми не називаємо його складання, оскільки Асамблея є в значній мірі чиста перекладу двійкового файлу.
Існує дуже мало логіки в переході від Асамблеї в двійковий формат.
Це все одно, дивлячись у таблицю, ой, у нас є ця інструкція;
, Що відповідає двійковим 01110.
І тому файли, які зборки в цілому виходи. Про файлах.
А. Висновку файлів, що ми говорили раніше,
як файл не потрібно мати основну функцію.
Будь-який файл може бути складений до. Файл виводу тих пір, поки це правильний файл C.
Він може бути складений до. °.
Тепер, пов'язуючи це те, що насправді приносить купу. Про файлах і приводить їх до виконуваного файлу.
І те, що компонування робить, ви можете думати про CS50 бібліотеку. Файл виводу.
Це вже скомпільованих двійкових файлів.
І так при компіляції файлу, ваш hello.c, яка закликає GetString,
hello.c компілюється до hello.o,
hello.o в даний час в двійковому вигляді.
Він використовує GetString, тому вона повинна перейти до cs50.o,
і компонувальник smooshes їх разом і копіює GetString в цей файл
і виходить з виконуваного файлу, який має всі функції яких вона потребує.
Так cs50.o насправді не про файл, але це досить близько, що немає ніякої принципової різниці.
Таким чином, зв'язок тільки приносить купу файлів разом
що окремо містять всі функції мені потрібно використовувати
і створює виконуваний файл, який буде реально працювати.
>> І таким чином, це також те, що ми говорили до
де ви можете мати 1000. с файлами, ви зібрати їх усі. про файли,
який, ймовірно, займе деякий час, то ви зміните 1. с файлом.
Вам тільки потрібно перекомпілювати, що 1. С файлу, а потім перелінковки все інше,
зв'язати всі разом.
[Студент] Коли ми пишемо зв'язку lcs50?
Так, так lcs50. Цей прапор сигнали в компонувальник, що ви повинні зв'язків в цій бібліотеці.
Питання?
Хіба ми перейшли двійковій інші, ніж 5 секунд в першій лекції?
Не думаю.
Ви повинні знати все більшу Os, що ми перейшли,
і ви повинні бути в змозі, якби ми дали вам функції,
Ви повинні бути в змозі сказати, що це велика O, грубо. Або ж, Big O є приблизними.
Так що якщо ви бачите, вкладені цикли цикли в порівнянні з аналогічною кількістю речей,
Int, як я, я <п; Int J, J <п - >> [студент] п квадрат. >> Він має тенденцію бути вказаний в квадраті.
Якщо ви потрійний вкладений, він, як правило, п кубі.
Так що такого роду речі ви повинні бути в змозі вказати відразу.
Ви повинні знати, роду вставки і бульбашкового сортування та сортування злиттям, і всі з них.
Це легше зрозуміти, чому вони є п квадратів і п § п і все, що
тому що я думаю, що була на тест один рік, де ми в основному дав вам
здійснення бульбашкового сортування і сказав: "Що таке час роботи цієї функції?"
Так що якщо ви визнаєте це, як бульбашкового сортування, то ви можете відразу сказати, п квадрат.
Але якщо ви просто подивіться на неї, вам навіть не потрібно усвідомити, що це бульбашкового сортування;
Ви можете просто сказати, що це робити це і це. Це п квадрат.
[Студент] Чи існують які-небудь жорсткі приклади, які ви можете придумати,
як аналогічна ідея з'ясувати?
>> Я не думаю, що ми хотіли б дати Вам будь-які жорсткі приклади.
Справа в бульбашкового сортування приблизно так само жорстко, як ми ходили,
і те, як довго, як ви розумієте, що ви ітерації по масиву
Для кожного елемента масиву, який буде щось, що п в квадраті.
Є загальні питання, наприклад, прямо тут, у нас - Oh.
Буквально днями, Дуг заявив: "Я винайшов алгоритм, який може сортувати масив
"П чисел в O (журнал N) раз!"
Отже, як ми знаємо, що це неможливо?
[Нерозбірливо відповідь студента] >> Да.
По крайней мере, ви повинні торкнутися кожного елемента в масиві,
так що це неможливо відсортувати масив -
Якщо все в порядку несортоване, то ви будете стосуватися всі, що в масиві,
так що це неможливо зробити це менш ніж за O н.
[Студент] Ви показали нам, що приклад в змозі зробити це в O п
якщо ви використовуєте багато пам'яті. >> Да.
І that's - Я забув, що that's - Хіба підрахунку роду?
Хм. Це ціле алгоритм сортування.
Я шукав спеціальну назву для цього, що я не міг згадати минулого тижня.
Так. Ці типи видів, які можуть виконати речі у великій O н.
Але є обмеження, як ви можете використовувати тільки цілі числа до певного числа.
Плюс, якщо ви намагаєтеся розібратися щось that's -
Якщо ваш масив 012, -12, 151, 4 млн.
те, що один елемент буде повністю зруйнує весь сортування.
>> Питання?
[Студент] Якщо у вас є рекурсивна функція, і він просто робить рекурсивні виклики
в повернення заяви, що це хвіст рекурсивної,
і так би це не використовувати більше пам'яті під час виконання
або, принаймні, використовувати зіставні пам'яті, як ітераційні рішення?
[Боуден] Так.
Це, ймовірно, буде трохи повільніше, але не зовсім.
Хвіст рекурсивних досить добре.
Дивлячись знову на кадри стека, скажімо, у нас є основний
і у нас є Int бар (INT х) або щось ще.
Це не ідеальний рекурсивної функції, але повернення бар (х - 1).
Таким чином, очевидно, що це помилково. Ви повинні базі випадки та інше.
Але ідея тут в тому, що це хвіст рекурсивної,
що означає, коли головний бар дзвінки він збирається отримати свій стек.
У цьому кадрі стека там буде невеликий блок пам'яті
, Що відповідає її аргументу х.
І так скажемо, основний, трапляється, називають Бар (100);
Таким х збирається почати, як 100.
Якщо компілятор визнає, що це хвіст рекурсивної функції,
Потім, коли бару робить його рекурсивний виклик бар,
замість того, щоб новий кадр стека, який є, де стек починає рости в основному,
в кінцевому підсумку він буде працювати в купу і тоді ви отримаєте помилку сегментації
тому що пам'ять починає зіткнення.
>> Таким чином, замість того, щоб його власний кадр стека, він може реалізувати,
Ей, я ніколи не потрібно повертатися до цього кадру стека,
так замість цього я просто замінити цей аргумент з 99, а потім почати барі на всьому протязі.
І тоді вона буде робити це знову і вона досягне повернення бар (х - 1),
і замість того, щоб новий кадр стека, це буде просто замінити свій поточний аргумент з 98
, А потім перейти до самого початку бар.
Ці операції, замінивши, що 1 значення в стеку і стрибає назад до початку,
досить ефективним.
Так що не тільки ця ж використання пам'яті як окрема функція, яка ітераційного
тому що ви використовуєте тільки 1 кадр стека, але ви не страждаєте мінуси
того, щоб викликати функції.
Виклик функції може бути трохи дорожче, тому що він повинен робити все це установка
і демонтажу та всі ці речі.
Так що цей хвостовій рекурсії добре.
[Студент] Чому не створити нові кроки?
Тому що він розуміє, що це не потрібно.
Виклик бар щойно повернувся рекурсивний виклик.
Так що не потрібно нічого робити з повертаним значенням.
Це просто буде негайно повернути його.
Так що це просто збирається замінити свої аргументи і почати все спочатку.
А також, якщо ви не маєте хвіст рекурсивної версії,
, То ви отримаєте всі ці бари, де, коли цей бар повертається
він повинен повернути його значення в цьому, то, що бар відразу ж повертається
і повертає його значення в цьому, то він просто буде негайно повернутися
і повернути його значення на цьому.
Таким чином, ви економите цього з'являються всі ці речі з стека
З значення, що повертається тільки збирається бути переданий весь шлях назад у будь-якому випадку.
Так чому б не замінити нашу суперечку з оновленим аргумент і почати все спочатку?
Якщо функція не є хвостовою рекурсією, якщо ви робите щось подібне -
[Студент], якщо бар (х + 1). >> Да.
>> Так що, якщо ви помістіть його в стан, то ви робите щось з повертаним значенням.
Або навіть якщо ви просто повернення 2 * бар (х - 1).
Так що тепер бар (х - 1) необхідно повернути для того, щоб обчислити, що в 2 рази значення,
так що тепер він дійсно потребує у своєму власному окремому кадрі стека,
і тепер, як не старайся, ви збираєтеся потрібно -
Це не хвіст рекурсивної.
[Студент] Чи буду я намагатися довести рекурсії прагнути до хвостової рекурсії -
[Боуден] В ідеальному світі, але в CS50 вам не доведеться.
Для того щоб отримати хвостовій рекурсії, загалом, ви створили додатковий аргумент
де бар відбудеться Int х в у
і у відповідає кінцева річ, яку ви хочете повернути.
Так ось це ви будете повертатися бар (х - 1), 2 * у.
Так що це тільки на високому рівні, як ви перетворення речей, щоб бути хвостом рекурсивні.
Але додатковий аргумент -
А потім, в кінці кінців, коли ви досягнете своєї бази випадку, ви просто повернути у
тому що у вас накопичується весь час повертається значення, що ви хочете.
Ви начебто робили це багаторазово, але з використанням рекурсивних викликів.
Питання?
[Студент] Може бути, про арифметику покажчиків, наприклад, при використанні рядків. >> Звичайно.
Покажчик арифметика.
При використанні рядків, що це легко, тому що рядки символів зірки,
символи вічні і завжди один байт,
і так арифметики покажчиків еквівалентно регулярні арифметичних коли ви маєте справу з рядками.
Давайте просто скажемо, символ * S = "привіт".
Отже, ми маємо блок в пам'яті.
Вона потребує 6 байт, тому що ви завжди повинні нулем.
І символ * S буде вказувати на початок цього масиву.
Таким чином, з точок.
Тепер, це в основному, як будь-який масив працює,
незалежно від того, чи було це повернення Танос або це в стеці.
Будь масив в основному покажчик на початок масиву,
і тоді будь-який масив операції, будь індексації, тільки збирається в цей масив певного зміщення.
>> Тому, коли я кажу щось подібне до [3], це буде їй і підрахунок 3 символи дюйма
Таким чином, з [3], ми маємо 0, 1, 2, 3, таким чином, з [3] буде посилатися на цю л.
[Студент] І ми могли б досягти такого ж значення, роблячи з + 3, а потім дужки зірки?
Так.
Це еквівалентно * (S + 3);
і це назавжди і завжди еквівалентні незалежно від того, що ви робите.
Ви ніколи не повинні використовувати кронштейн синтаксису.
Ви завжди можете використовувати * (S + 3) синтаксис.
Люди, як правило, подобаються кронштейн синтаксису, однак.
[Студент] Таким чином, всі масиви в дійсності є просто покажчиками.
Існує невелике розходження, коли я говорю Int х [4] >> [студент] Чи означає це, створіть пам'яті?
[Боуден], що збирається створити 4 цілих чисел в стеку, тому 16 байт в цілому.
Він збирається створити 16 байт в стеці.
х ніде не зберігається.
Це просто символ з посиланням на старті річ.
Тому що ви оголосили масив всередині цієї функції,
що компілятор буде зробити, це просто замінити всі входження змінної х
с, де це сталося вибрати, щоб покласти ці 16 байт.
Він не може зробити це за допомогою символів * тому, що їй це фактично покажчик.
Це безкоштовно, щоб потім вказати на інші речі.
х є постійним. Ви не можете мати його точки до іншої масив. >> [Студент] Добре.
Але ця ідея, ця індексація, таке ж, незалежно від того, чи є це традиційним масивом
або, якщо це покажчик на щось або, якщо це покажчик на malloced масиву.
І справді, це так еквівалентної, що це також одне і те ж.
Це насправді просто означає, що всередині дужок і те, що залишилося за дужки,
складає їх, і разименовивает.
Так що це тільки ж силу, як * (S + 3) або з [3].
[Студент] Може у вас є покажчики, що вказують на 2-мірних масивів?
>> Це важче. Традиційно, немає.
2-мірний масив знаходиться всього в 1-мірний масив з деяким зручний синтаксис
тому що, коли я говорю Int х [3] [3], це дійсно тільки 1 масив з 9 значень.
І тому, коли я індексом, компілятор знає, що я маю на увазі.
Якщо я скажу, х [1] [2], він знає, я хочу піти на другому рядку, так що він збирається пропустити перші 3,
, А потім вона хоче Друге в тому, що так воно збирається отримати це.
Але це ще тільки одновимірний масив.
І тому, якщо я хотів привласнити покажчик на цей масив,
Я б сказав Int * р = х;
Тип х просто -
Це грубо кажучи типу х, так як це всього лише символ, і це не фактичної змінної,
Але це всього лише Int *.
х це просто покажчик на початок цього. >> [Студент] Добре.
І тому я не буду мати можливість доступу [1] [2].
Я думаю, що є спеціальний синтаксис для оголошення покажчика,
щось смішне, як Int (* р [-. щось абсолютно смішно, я навіть не знаю.
Але є синтаксис для оголошення покажчиків, як з дужками і речі.
Він не може навіть дозволити вам зробити це.
Я можу озирнутися на те, що б сказати мені правду.
Я буду шукати його пізніше, якщо є синтаксис точки. Але ви ніколи не побачите.
І навіть синтаксис дуже архаїчна, що якщо ви використовуєте його, люди будуть збиті з пантелику.
Багатовимірні масиви є досить рідкими, як це.
Ви в значній мірі -
Ну, а якщо ви робите матрицю речей він не збирається бути рідкісними,
але в C ви рідко будете використовувати багатовимірні масиви.
Так. >> [Студент] Скажімо, у вас є дуже довгий масив.
>> Таким чином, у віртуальній пам'яті, вона, здавалося б, все підряд,
як елементи поруч один з одним,
але й у фізичній пам'яті, це було б можливо, що бути розділені? >> Да.
Як віртуальна пам'ять працює це тільки відокремлює -
Блок розподілу являє собою сторінку, яка має тенденцію бути 4 кілобайти,
і тому, коли процес говорить, агов, я хочу використати цю пам'ять,
Операційна система збирається виділити її 4 кілобайти, що мало блок пам'яті.
Навіть якщо ви використовуєте тільки один маленький байт в цілий блок пам'яті,
Операційна система збираюся дати йому повний 4 кілобайти.
Так що це означає, я міг би - скажімо, це мій стек.
Цей стек можуть бути розділені. Мій стек може бути мегабайти і мегабайти.
Мій стек може бути величезним.
Але сам стек повинен бути розбитий на окремі сторінки,
, Який, якщо ми подивимося на тут скажімо, це наша пам'ять,
якщо у мене є 2 гігабайти оперативної пам'яті, це дійсно адресою 0 як нульовий байт моїй пам'яті,
і це становить 2 гігабайти на всьому шляху сюди.
Так цій сторінці може відповідати цьому блоку тут.
Ця сторінка може відповідати цьому блоку тут.
Це одна може відповідати цим сюди.
Таким чином, операційна система вільна призначити фізичної пам'яті
в окремих сторінок довільно.
А це означає, що якщо це станеться, межа осідлати масиву,
Масив трапляється, залишив це і право цей порядок сторінок,
Потім цей масив буде розділений у фізичній пам'яті.
А потім, коли ви виходите з програми, коли процес закінчиться,
ці відображення отримати стерті, а потім вона вільно використовувати ці маленькі блоки для інших речей.
Ще питання?
[Студент] арифметики покажчиків. >> Ах так.
Струни були легші, але, дивлячись на те, як цілими,
Отже, повернемося до Int х [4];
Чи є це масив або це покажчик на malloced масив з 4 чисел,
це буде розглядатися таким же чином.
[Студент] Так масивів в купі?
[Боуден] Масиви не в купі. >> [Студент] Ох.
>> [Боуден] Цей тип масиву, як правило, в стеці
якщо Ви заявив на - ігнорування глобальних змінних. Не використовуйте глобальні змінні.
Усередині функції Я кажу Int х [4];
Він збирається створити 4-ціле число блоків в стеку для цього масиву.
Але це Танос (4 * SizeOf (INT)); буде йти в купу.
Але після цього моменту я можу використовувати х і р у значній мірі тими ж способами,
крім винятків, я вже говорив про вас можна перепризначити р.
Технічно, їх розміри трохи відрізняються, але це абсолютно не має значення.
Ви ніколи не використовувати їх розмірів.
Р я можу сказати, р [3] = 2, або х [3] = 2;
Ви можете використовувати їх точно так само способами.
Так що арифметика покажчиків тепер - так.
[Студент] Ви не повинні робити р * якщо у вас є дужки?
Дужках неявних посилань. >> Добре.
Насправді, і те, що ви говорите з ви можете отримати багатовимірні масиви
з покажчиками, що ви можете зробити щось подібне, скажімо, Int ** рр = Танос (SizeOf (INT *) * 5);
Я просто написати все це в першу чергу.
Я не хотів цього.
Добре.
Що я зробив тут - Це має бути рр [I].
Так п.п. це покажчик на покажчик.
Ви mallocing п.п. вказує на масив з 5 зірочок Int.
Таким чином, в пам'яті у вас в стеку С.
Це буде вказувати на масив з 5 блоків, які все самі покажчики.
А потім, коли я Танос сюди, я Танос, що кожен з цих окремих покажчиків
повинен вказувати на окремий блок з 4 байт в купі.
Таким чином, це вказує на 4 байти.
А це вказує на іншу 4 байт.
>> І всі вони вказують на своїх 4 байт.
Це дає мені спосіб зробити багатовимірним речі.
Я міг би сказати п.п. [3] [4], але тепер це не те ж саме, багатовимірні масиви
тому що багатовимірні масиви в її перекладі [3] [4] в одну зміщення у масиві х.
Це разименовивает р, доступ до третього індексу, те, що разименовивает
і доступи - 4 будуть вважатися недійсними - другий індекс.
У той час, коли ми були Int х [3] [4] до як багатовимірний масив
і при подвійному кронштейні це дійсно тільки один разименованія,
Ви після одного покажчика, а потім зсув,
це дійсно 2D посилання.
Ви прямуєте 2 окремі покажчики.
Таким чином, це також технічно дозволяє мати багатовимірні масиви
де кожен масиву різних розмірів.
Тому я думаю, зубчасті багатовимірних масивів є те, що вона називається
так як насправді перше, що може вказувати на те, що має 10 елементів,
Друге, що може вказувати на те, що має 100 елементів.
[Студент] Чи є обмеження на кількість покажчиків ви можете мати
вказують на інші покажчики? >> Ні.
Ви можете мати Int ***** р.
Повернутися до арифметики з покажчиками - >> [студент] Ох. >> Да.
[Студент] Якщо у мене є Int *** р а потім я разименованія, і я кажу р * дорівнює цьому значенню,
це тільки збирається зробити 1 рівень разименованія? >> Да.
Так що, якщо я хочу отримати доступ те, що останній покажчик направлений на -
Тоді ви *** р. >> Добре.
Так що це р вказує на 1 блок, який вказує на інший блок, який вказує на інший блок.
Тоді, якщо ви робите * р = щось інше, то ви міняєте цю
Тепер, щоб вказати на інший блок. >> Добре.
>> [Боуден] І якщо вони були malloced, то ви тепер витік пам'яті
якщо вам пощастило мати різні посилання з цих
Оскільки ви не можете повернутися в ті, що ви просто викинули.
Покажчик арифметика.
Int х [4]; збирається виділити масив з 4 чисел
де х буде вказувати на початок масиву.
Тому, коли я кажу щось подібне X [1], я хочу, щоб це означало йти на другий ціле число в масиві,
, Який був би цьому.
Але насправді, це 4 байти в масиві, так як це ціле число займає 4 байти.
Таким чином, зсув 1 на насправді означає зміщення 1
раз розмір незалежно від типу масиву.
Це масив цілих чисел, тому він знає, що потрібно робити 1 раз розмір Int, коли він хоче, щоб компенсувати.
Інший синтаксис. Пам'ятайте, що це еквівалентно * (х + 1);
Коли я кажу покажчик + 1, то, що повертає це адреса, що покажчик зберігання
плюс 1 раз розмір тип покажчика.
Таким чином, якщо х = ox100, то х + 1 = ox104.
І ви можете зловживати цим і сказати щось на зразок символ * C = (символ *) х;
і тепер з буде той же адреса, х.
З буде дорівнювати ox100,
але з + 1 буде дорівнює ox101
З арифметикою покажчика залежить від типу покажчик, який ви додаєте в.
Таким чином, з + 1, він дивиться на C, це символьний покажчик, так що він збирається додати 1 разу розмір символів,
який завжди буде на 1, так що ви отримаєте 101,
а якщо я зроблю х, яка також ще 100, х + 1 буде 104.
[Студент] Чи можна використовувати C + +, в цілях просування покажчика на 1?
Так, можна.
Ви не можете зробити цього, тому що з х х це просто символ, це постійна, ви не можете змінити х.
>> Але з відбувається, щоб бути просто покажчик, так що C + + є цілком допустимим, і вона буде збільшуватися на 1.
Якщо з просто Int *, то C + + буде 104.
+ + Робить арифметику покажчиків так само, як з + 1 зробив би арифметики покажчиків.
Насправді, як багато таких речей, як сортування злиттям -
Замість того щоб створювати копії речей, ви можете замість цього пройти -
Як якщо б я хотів передати цю половину масиву - давайте стерти частину цього.
Скажімо, я хотів би передати цю сторону масиву у функцію.
Що б я передати цю функцію?
Якщо я проходжу х, я передаю цю адресу.
Але я хочу, щоб пройти цей конкретний адресу. Так що я повинен пройти?
[Студент] покажчик + 2?
[Боуден] Таким чином, х + 2. Так.
Це буде ця адреса.
Ви також дуже часто бачу це як х [2], а потім адресу цього.
Таким чином, ви повинні взяти на адресу, тому що кронштейн неявних посилань.
х [2] посилається на значення, яке знаходиться в цьому полі, а потім ви хочете адресу цього вікна,
так що ви говорите і х [2].
Так от, як щось сортування злиттям, де ви хочете передати половину списку, щоб щось
Ви дійсно просто передати і х [2], і в даний час, наскільки рекурсивний виклик, то,
мій новий масив починається там.
Останні питання хвилину.
[Студент] Якщо ми не будемо ставити амперсанд або - що, що називається? >> Star?
[Студент] Star. >> Технічно, оператор разименованія, але - >> [студент] Dereference.
>> Якщо ми не ставимо зірки або амперсанд, що станеться, якщо я просто скажу, у = х і х є покажчиком?
Який тип у? >> [Студент] Я просто кажу, що це покажчик 2.
Так що якщо ви тільки що сказали у = х, тепер х і у указують на одне і те ж. >> [Студент] вказують на те ж саме.
І якщо х Int покажчика? >> Було б скаржитися, тому що ви не можете призначити покажчиків.
[Студент] Добре.
Пам'ятайте, що покажчики, хоча ми і залучити їх, як стріли,
насправді все, що вони магазину - Int * х - дійсно все х зберігання щось подібне ox100,
які ми, трапляється, що представляють як вказівку на блоці зберігається 100.
Тому коли я кажу Int * у = х, я просто копіювання ox100 в у,
які ми тільки збираємося представити як у, також вказуючи на ox100.
І якщо я говорю Int я = (INT) х, тоді я маю намір зберігати будь-які значення ox100 є
всередині нього, але тепер це буде інтерпретуватися як ціле, а не покажчик.
Але для цього потрібно литих або ж він буде скаржитися.
[Студент] Таким чином, ви маєте на увазі, щоб кинути -
Це збирається бути лиття Int х або лиття Int у?
[Боуден] Що?
[Студент] Добре. Після цих дужках там буде х або ау там?
>> [Боуден] Або. х та у є еквівалентними. >> [Студент] Добре.
Тому що вони обидва покажчика. >> Да.
[Студент] Тому було б зберігати шістнадцяткове ціле число 100 у формі? >> [Боуден] Так.
Але не значення того, що це вказує.
[Боуден] Так. >> [Студент] Таким чином, тільки адресу в целочисленном вигляді. Добре.
[Боуден] Якщо ви хотіли б за деякою дивної причини,
Ви могли б мати справу виключно з покажчиками і ніколи не мати справу з цілими числами
і просто бути як Int * х = 0.
Тоді ви збираєтеся отримати дійсно плутають раз арифметики покажчиків починає відбуватися.
Так що цифри, які вони зберігають не мають сенсу.
Це просто, як ви в кінцевому підсумку їх інтерпретації.
Так що я вільно копіювати ox100 від Int * в ціле число,
і я вільно призначати - ти, ймовірно, збираюся кричати на що не лиття -
Я вільний призначити щось подібне (Int *) ox1234 в цій довільній * Int.
Так ox123 так само вірний адресу пам'яті, як це і у.
І у трапляється, повернути те, що є в значній мірі ox123.
[Студент] Це було б дійсно здорово шлях від шістнадцятковій в десяткову форму,
подобається, якщо у вас є покажчик, і ви кинули його у вигляді цілого числа?
[Боуден] Ви дійсно можете просто друкувати, використовуючи як Printf.
Скажімо, у мене є Int у = 100.
Таким чином, Е (% г \ п - як ви вже знаєте - друк, що як ціле, х%.
Ми просто роздрукувати його як шістнадцяткове.
Таким чином, покажчик не зберігається в шістнадцятковому,
і ціле не зберігається у вигляді десяткового.
Все зберігається в двійковому вигляді.
Це тільки, що ми, як правило, щоб показати, покажчики, як шістнадцяткове
тому що ми думаємо про речі, в цих 4-байтових блоків,
і адреси пам'яті, як правило, знайомі.
Ми як, якщо він починається з BF, то воно відбудеться, буде в стеці.
Так що це просто наша інтерпретація покажчики, як шістнадцяткове.
Добре. Будь останніх запитань?
>> Я буду тут трохи після, якщо у вас є щось ще.
І це кінець.
>> [Студент] Ура! [Оплески]
>> [CS50.TV]