[Powered by Google Translate] [Показалки]
[Роб Bowden] [Харвардския университет]
[Това е CS50 [CS50.TV]
>> Да поговорим за указатели.
До момента, ние винаги сме само към нещата в паметта изрично от името.
Казахме INT N = 42 и тогава, когато искаме да използваме променливата N,
ние просто го наричат ​​с името му даваме от писането на нещо като N * 2.
Но тази променлива трябва да живеят някъде в паметта.
Когато искате да използвате стойност, която в момента се съхраняват във вътрешността н
или актуализиране на стойността, която N държи,
вашата програма трябва да знаете къде в паметта, за да търсят N.
Когато в паметта с променлива живота се нарича неговия адрес.
Това е като къща адрес.
Мога да намеря къщата на някого толкова дълго, колкото знам, домашния си адрес,
и компютърна програма, може да се намери променлива толкова дълго, колкото го знае нейната адресна памет.
Какво указатели осигуряват е начин пряко се занимават с тези адреси от паметта.
>> Много от властта в C не е в състояние да манипулират памет като тази.
Но с голяма сила идва и голяма отговорност.
Указатели може да се използва опасно достатъчно, че много езици за програмиране
скрий указатели изцяло.
Така че, защо C ни даде насоки?
Както знаете, аргументи за функция C
винаги са копирани в параметрите на функцията.
Така че, наричайки нещо като суап на някои променливи х и у
не могат да разменят стойности на х и у в викащата функция,
въпреки че може да е полезно.
Както ще видим по-късно, пренаписване разменяне на указатели към местата, които трябва да бъдат сменени
позволява да засегне променливите си абонати.
>> Нека минем през сравнително прост пример за това какво може да направи указатели.
Нека кажем, че имаме INT N = 4 и вътр * pointer_to_n = & N.
Уау! Малко нов синтаксис за покриване.
Първо, нека да тълкуват това и N.
Не забравяйте, че всичко в паметта има някакъв адрес.
Амперсанд се нарича "адрес на" оператор.
Така че, се отнася до адреса в паметта, където се съхранява N & N.
Сега, ние сме съхраняване на този адрес в нова променлива, pointer_to_n.
Какъв е типът на тази нова променлива?
Звездичката е част от типа на променливата,
и ние ще прочетете типа, INT *.
Int * означава, че pointer_to_n е променлива, съдържаща адрес на цяло число.
Ние знаем, че & N е INT *, тъй като N е цяло число, и ние сме като адреса на N.
Int * е пример за типа указател.
Веднага след като започнете да виждате звездички във вида,
знаете, че си имате работа с указатели.
Точно както можем да декларираме променлива INT х и Чар г.,
можем да кажем, вътр * Z и Чар * Ш.
Int * и Чар * са само нови видове за нас да използваме.
Мястото на * пред името на променливата може да отиде навсякъде.
Така че, както Int * pointer_to_n - с * до INT, тъй като имаме тук -
и вътр * pointer_to_n с * до pointer_to_n са валидни.
Но тук, аз ще поставим * до Int.
Няма значение кое предпочитате, просто да бъде последователна.
>> Да се ​​изготви схема за това.
Първия има променлива N, който ще привлече като малка кутийка с памет.
За този пример, нека да кажем, че това поле се намира на адрес 100.
Вътре в това поле, ние сме съхраняване на стойност 4.
Сега имаме нова променлива, pointer_to_n.
Разполага със собствен прозорец в паметта,
което ще кажем, че е на адрес 200.
Вътре в това поле, ние сме съхраняване на адреса на N,
които ние преди това каза, че е 100.
Често в диаграми, ще видите, това е показано като буквално стрелка
оставяйки pointer_to_n кутия сочи към полето, което се съхранява н.
Сега, това, което можем реално с pointer_to_n?
Е, ако кажем нещо подобно * pointer_to_n = 8, това е различно за звездичка
че е напълно отделен от използването на звездичка за обявяване на променлива
от тип указател.
Ето, звездичката се нарича сочен.
В нашата диаграма, какво * pointer_to_n = 8 средства,
кутия, съдържаща pointer_to_n, следвайте стрелката,
и след това присвоите на полето в края на стрелката на стойност 8.
Това означава, че след този ред, ако се опитваме да използваме N ще имат стойност 8.
Думата "показалеца" се използва в много различни контексти.
Ето, ние ще се опитаме да бъде последователна.
А показалеца тип е нещо като INT *.
В това видео, само ще се използва показалка означава стойност с показалеца тип,
като pointer_to_n която има * тип Int.
Навсякъде можем да кажем N, можем да сега вместо каже * pointer_to_n,
и всичко ще работи също толкова добре.
>> Нека разгледаме един прост пример.
Нека кажем, че имаме INT N = 14, вътр * показалеца = &n; N + +, и (* показалеца) + +.
Първият ред създава нова кутия в паметта етикетирани н.
Този път, ние няма да етикетират кутия с изрично адрес, но тя все още има една.
Вътрешността на кутията, ние сме съхраняване на номер 14.
Следващият ред създава втори кутията с надпис показалеца.
И в рамките на това поле, ние сме съхраняване на показалеца на кутията с надпис N.
Така че, нека да привлече стрелката от показалеца, за да н.
Сега, N + + нарастване на стойността в кутията с надпис N,
така че ние 14-15.
И накрая, (* показалеца) + + отива в кутията с надпис показалеца,
dereferences стойност в полето, което означава, следвайте стрелката на къде сочи,
и нарастване на стойността, съхранена там, така че отиваме 15-16.
И това е всичко.
N съхранява номер 16 след като е бил увеличен два пъти -
веднъж директно с помощта на променливата N име, а други чрез pointer_to_n.
>> Бърз тест. Какво мислиш, че означава, че ако аз се опитам да кажа нещо подобно && N?
Ами, нека да пренапише това като & (н), който прави същото.
(Н) връща адреса на променливата N в паметта.
Но след това след това външната амперсанд се опитва да се върне на адрес на адрес.
Това е като да се опитвам да направя и две.
То няма смисъл да се получи на адрес само на известен брой
тъй като той не се съхраняват в паметта.
Използване на две амперсанди в ред никога не е на прав път.
Но сега, какво означава това, ако се опитам да се каже, вътр ** double_pointer = показалеца?
Сега, аз съм създаване на нова кутията с надпис double_pointer
и вътре в тази кутия съм съхраняване на адреса на показалеца,
, което означава, че начертайте стрелка от кутията double_pointer на показалеца кутия.
Обърнете внимание на вида на double_pointer, INT **.
N е цяло число, показалецът съхранява адреса на N, и затова има * тип Int.
Сега, double_pointer съхранява адреса на показалеца, така че има тип Int **.
>> Така че, това, което смятаме, че това означава -
** Double_pointer = 23?
Забележете, че сега съм dereferencing два пъти.
Просто следвайте полето и стрелката схема вече сме създадени.
Първо, ние се връщаме към кутията с надпис double_pointer.
Първо * означава, следвайте стрелката веднъж.
Сега, ние сме в кутията с надпис показалеца.
Втората звезда казва, че отново върху стрелката,
и сега сме в кутията с надпис N, и стойността на тази клетка 23.
Забележете, че сочен и адреса на "оператори са обратно пропорционални един на друг.
Това ми позволява да правя нещо подобно * & * & N = 42.
Докато това стане, вие никога не трябва да направя нещо подобно в практиката.
Какво всъщност правиш тук?
Първо амперсанд грабва адрес на променливата N.
След това имаме и сочен оператор, което означава, че на този адрес в паметта,
така че ние сме най-н.
Сега, ние вземете адреса на N отново и веднага сочен
така че ние сме най-н и магазин 42.
Така че, всяка двойка * & отменя.
>> Има специална показалеца, наречена нулев указател.
Това е указател, че ние никога не бива сочен.
Такава показалеца е важно, защото ни дава възможност да се направи разграничение между
показалеца, които трябва и не трябва да се dereferenced.
Ако се опитате да сочен с нулев указател,
обикновено вашата програма ще се срине с сегментация вина
които може да сте виждали преди.
Така че, нека кажем, че имаме кода Int * х = NULL; * х = 4.
В този пример, може да изглежда очевидно, че правим нещо лошо,
но не забравяйте, че за нищожна наистина може да бъде стойността, върната от извикване на функция
като изчистване, ако изчистване не е в състояние да се разпредели памет, поискани от потребителя.
Поради тази причина, ако вместо стойността на х от извикването на изчистване,
както и в Int * х = изчистване (sizeof (INT)), тогава ние трябва винаги изрично проверите
за да видите дали нищожна е върнат.
Ако (х == NULL) / / uhoh! връщане; друго, което може да продължи и да каже * х = 4.
>> Така че, отново, защо трябва да се някога използват указатели?
Нека разгледаме един пример на една програма, където ние трябва да използваме указатели -
проста функция суап.
Да кажем, че имам две цели числа, вътр х = 4 и Int Y = 15;
и искам да напиша функция, наречена суап, които мога да използвам като така: суап (X, Y).
След тази линия, стойностите вътре на променливата х трябва да бъде 15,
и стойност вътре променлива г. трябва да бъде 4.
Стойностите вътрешността на х и у са разменени.
Без указатели, бихме могли да се опитаме нещо като невалидни суап (Int а, вътр б);
Int TMP = б, б = а; а = ПТУ.
Но, да забележите, че проблем с това?
Не забравяйте, че стойността, съхранена в променливата а е просто копие на стойността на х,
и стойност в б е копиран от години.
Всички промени, направени в А и Б няма да бъдат отразени в х и у.
Така че, докато стойностите на а и б са правилно разменят,
х и у не са се променили изобщо.
Сега, нека да промените функцията суап, така че аргументите си
са указатели към променливите трябва да се сменят, като така:
невалидни суап (INT * а, вътр * б); вътр TMP = * б * б = * А; * а = ПТУ.
Не забравяйте, че суапове аргументи са указатели,
и затова ние трябва да премине адреса на х и у в поканата да се разменят, като така:
суап (& X, и г).
Това сега правилно суапове стойности на х и у.
>> Нека се направи кутия и стрелката диаграма, за да се види защо това работи.
Ние започваме с нашите две кутии в паметта, х и у.
Вътре в полето за х е номер 4, и вътрешността на кутия за години имаме 15.
Сега, в рамките на поканата за суап функция, ние имаме още две кутии
за аргументите А и Б;
точкова полето за х, и б пункта до полето за години.
Се създава нова кутия за променливата малки,
и вътре в него ние съхраняваме резултат от dereferencing б,
, което означава "стрела от кутията с надпис б."
Така че, ние съхраняваме 15 вътрешността на ПТУ.
След това, ние следваме стрелката в б и магазин у нас в резултат на dereferencing
, който е на стойност 4.
И накрая, ние следваме стрелката в това, което е в момента в рамките на малки и магазин, който е 15.
Забележете, че квадратчетата х и у правилно са разменени стойности.
>> След като научите повече за изчистване и динамично управление на паметта,
ще видим, че имаме друг избор, освен да използват указатели.
Разглеждане на през полето и стрелката схема за всяка програма
може да ви помогне да разберете това, което програмата е наистина прави.
>> Моето име е Роб Боудън, и това е CS50.
[CS50.TV]
>> Това е различно за звездичка - bleah, мразя тази дума.
Навсякъде можем да кажем N, можем да се каже, pointer_to_n - не 'т - * pointer_to_n.